19e046f02SJonas Devlieghere //===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===//
29e046f02SJonas Devlieghere //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69e046f02SJonas Devlieghere //
79e046f02SJonas Devlieghere //===----------------------------------------------------------------------===//
89e046f02SJonas Devlieghere 
99e046f02SJonas Devlieghere #include "CommandObjectReproducer.h"
109e046f02SJonas Devlieghere 
1197fc8eb4SJonas Devlieghere #include "lldb/Host/OptionParser.h"
128fc8d3feSJonas Devlieghere #include "lldb/Utility/GDBRemote.h"
13f4f12012SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
149e046f02SJonas Devlieghere 
15df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h"
169e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h"
179e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h"
189e046f02SJonas Devlieghere 
19c8dfe907SJonas Devlieghere #include <csignal>
20c8dfe907SJonas Devlieghere 
219e046f02SJonas Devlieghere using namespace lldb;
2297fc8eb4SJonas Devlieghere using namespace llvm;
239e046f02SJonas Devlieghere using namespace lldb_private;
2497fc8eb4SJonas Devlieghere using namespace lldb_private::repro;
2597fc8eb4SJonas Devlieghere 
2697fc8eb4SJonas Devlieghere enum ReproducerProvider {
2797fc8eb4SJonas Devlieghere   eReproducerProviderCommands,
2897fc8eb4SJonas Devlieghere   eReproducerProviderFiles,
2997fc8eb4SJonas Devlieghere   eReproducerProviderGDB,
3097fc8eb4SJonas Devlieghere   eReproducerProviderVersion,
31f4f12012SJonas Devlieghere   eReproducerProviderWorkingDirectory,
3297fc8eb4SJonas Devlieghere   eReproducerProviderNone
3397fc8eb4SJonas Devlieghere };
3497fc8eb4SJonas Devlieghere 
3597fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
3697fc8eb4SJonas Devlieghere     {
3797fc8eb4SJonas Devlieghere         eReproducerProviderCommands,
3897fc8eb4SJonas Devlieghere         "commands",
3997fc8eb4SJonas Devlieghere         "Command Interpreter Commands",
4097fc8eb4SJonas Devlieghere     },
4197fc8eb4SJonas Devlieghere     {
4297fc8eb4SJonas Devlieghere         eReproducerProviderFiles,
4397fc8eb4SJonas Devlieghere         "files",
4497fc8eb4SJonas Devlieghere         "Files",
4597fc8eb4SJonas Devlieghere     },
4697fc8eb4SJonas Devlieghere     {
4797fc8eb4SJonas Devlieghere         eReproducerProviderGDB,
4897fc8eb4SJonas Devlieghere         "gdb",
4997fc8eb4SJonas Devlieghere         "GDB Remote Packets",
5097fc8eb4SJonas Devlieghere     },
5197fc8eb4SJonas Devlieghere     {
5297fc8eb4SJonas Devlieghere         eReproducerProviderVersion,
5397fc8eb4SJonas Devlieghere         "version",
5497fc8eb4SJonas Devlieghere         "Version",
5597fc8eb4SJonas Devlieghere     },
5697fc8eb4SJonas Devlieghere     {
57f4f12012SJonas Devlieghere         eReproducerProviderWorkingDirectory,
58f4f12012SJonas Devlieghere         "cwd",
59f4f12012SJonas Devlieghere         "Working Directory",
60f4f12012SJonas Devlieghere     },
61f4f12012SJonas Devlieghere     {
6297fc8eb4SJonas Devlieghere         eReproducerProviderNone,
6397fc8eb4SJonas Devlieghere         "none",
6497fc8eb4SJonas Devlieghere         "None",
6597fc8eb4SJonas Devlieghere     },
6697fc8eb4SJonas Devlieghere };
6797fc8eb4SJonas Devlieghere 
6897fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() {
6997fc8eb4SJonas Devlieghere   return OptionEnumValues(g_reproducer_provider_type);
7097fc8eb4SJonas Devlieghere }
7197fc8eb4SJonas Devlieghere 
7236eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump
7397fc8eb4SJonas Devlieghere #include "CommandOptions.inc"
749e046f02SJonas Devlieghere 
75c8dfe907SJonas Devlieghere enum ReproducerCrashSignal {
76c8dfe907SJonas Devlieghere   eReproducerCrashSigill,
77c8dfe907SJonas Devlieghere   eReproducerCrashSigsegv,
78c8dfe907SJonas Devlieghere };
79c8dfe907SJonas Devlieghere 
80c8dfe907SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_signaltype[] = {
81c8dfe907SJonas Devlieghere     {
82c8dfe907SJonas Devlieghere         eReproducerCrashSigill,
83c8dfe907SJonas Devlieghere         "SIGILL",
84c8dfe907SJonas Devlieghere         "Illegal instruction",
85c8dfe907SJonas Devlieghere     },
86c8dfe907SJonas Devlieghere     {
87c8dfe907SJonas Devlieghere         eReproducerCrashSigsegv,
88c8dfe907SJonas Devlieghere         "SIGSEGV",
89c8dfe907SJonas Devlieghere         "Segmentation fault",
90c8dfe907SJonas Devlieghere     },
91c8dfe907SJonas Devlieghere };
92c8dfe907SJonas Devlieghere 
93c8dfe907SJonas Devlieghere static constexpr OptionEnumValues ReproducerSignalType() {
94c8dfe907SJonas Devlieghere   return OptionEnumValues(g_reproducer_signaltype);
95c8dfe907SJonas Devlieghere }
96c8dfe907SJonas Devlieghere 
97c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash
98c8dfe907SJonas Devlieghere #include "CommandOptions.inc"
99c8dfe907SJonas Devlieghere 
1009e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed {
1019e046f02SJonas Devlieghere public:
1029e046f02SJonas Devlieghere   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
103973d66eeSJonas Devlieghere       : CommandObjectParsed(
104973d66eeSJonas Devlieghere             interpreter, "reproducer generate",
105973d66eeSJonas Devlieghere             "Generate reproducer on disk. When the debugger is in capture "
106973d66eeSJonas Devlieghere             "mode, this command will output the reproducer to a directory on "
1070cf86da1SJonas Devlieghere             "disk and quit. In replay mode this command in a no-op.",
108973d66eeSJonas Devlieghere             nullptr) {}
1099e046f02SJonas Devlieghere 
1109e046f02SJonas Devlieghere   ~CommandObjectReproducerGenerate() override = default;
1119e046f02SJonas Devlieghere 
1129e046f02SJonas Devlieghere protected:
1139e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
1149e046f02SJonas Devlieghere     if (!command.empty()) {
1159e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
1169e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
1179e046f02SJonas Devlieghere       return false;
1189e046f02SJonas Devlieghere     }
1199e046f02SJonas Devlieghere 
12097fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
1219e046f02SJonas Devlieghere     if (auto generator = r.GetGenerator()) {
1229e046f02SJonas Devlieghere       generator->Keep();
123865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
124bb090bb1SJonas Devlieghere       // Make this operation a NO-OP in replay mode.
1252dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1262dca6538SJonas Devlieghere       return result.Succeeded();
1279e046f02SJonas Devlieghere     } else {
1289e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer generator");
1292dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusFailed);
1309e046f02SJonas Devlieghere       return false;
1319e046f02SJonas Devlieghere     }
1329e046f02SJonas Devlieghere 
1339e046f02SJonas Devlieghere     result.GetOutputStream()
1349e046f02SJonas Devlieghere         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
1351c5250abSJonas Devlieghere     result.GetOutputStream()
1361c5250abSJonas Devlieghere         << "Please have a look at the directory to assess if you're willing to "
1371c5250abSJonas Devlieghere            "share the contained information.\n";
1389e046f02SJonas Devlieghere 
1390cf86da1SJonas Devlieghere     m_interpreter.BroadcastEvent(
1400cf86da1SJonas Devlieghere         CommandInterpreter::eBroadcastBitQuitCommandReceived);
1410cf86da1SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
1429e046f02SJonas Devlieghere     return result.Succeeded();
1439e046f02SJonas Devlieghere   }
1449e046f02SJonas Devlieghere };
1459e046f02SJonas Devlieghere 
146c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed {
147c8dfe907SJonas Devlieghere public:
148c8dfe907SJonas Devlieghere   CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
149c8dfe907SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer xcrash",
150c8dfe907SJonas Devlieghere                             "Intentionally force  the debugger to crash in "
151c8dfe907SJonas Devlieghere                             "order to trigger and test reproducer generation.",
152c8dfe907SJonas Devlieghere                             nullptr) {}
153c8dfe907SJonas Devlieghere 
154c8dfe907SJonas Devlieghere   ~CommandObjectReproducerXCrash() override = default;
155c8dfe907SJonas Devlieghere 
156c8dfe907SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
157c8dfe907SJonas Devlieghere 
158c8dfe907SJonas Devlieghere   class CommandOptions : public Options {
159c8dfe907SJonas Devlieghere   public:
160c8dfe907SJonas Devlieghere     CommandOptions() : Options() {}
161c8dfe907SJonas Devlieghere 
162c8dfe907SJonas Devlieghere     ~CommandOptions() override = default;
163c8dfe907SJonas Devlieghere 
164c8dfe907SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
165c8dfe907SJonas Devlieghere                           ExecutionContext *execution_context) override {
166c8dfe907SJonas Devlieghere       Status error;
167c8dfe907SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
168c8dfe907SJonas Devlieghere 
169c8dfe907SJonas Devlieghere       switch (short_option) {
170c8dfe907SJonas Devlieghere       case 's':
171c8dfe907SJonas Devlieghere         signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
172c8dfe907SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
173c8dfe907SJonas Devlieghere         if (!error.Success())
174c8dfe907SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
175c8dfe907SJonas Devlieghere                                          option_arg.str().c_str());
176c8dfe907SJonas Devlieghere         break;
177c8dfe907SJonas Devlieghere       default:
178c8dfe907SJonas Devlieghere         llvm_unreachable("Unimplemented option");
179c8dfe907SJonas Devlieghere       }
180c8dfe907SJonas Devlieghere 
181c8dfe907SJonas Devlieghere       return error;
182c8dfe907SJonas Devlieghere     }
183c8dfe907SJonas Devlieghere 
184c8dfe907SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
185c8dfe907SJonas Devlieghere       signal = eReproducerCrashSigsegv;
186c8dfe907SJonas Devlieghere     }
187c8dfe907SJonas Devlieghere 
188c8dfe907SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
189c8dfe907SJonas Devlieghere       return makeArrayRef(g_reproducer_xcrash_options);
190c8dfe907SJonas Devlieghere     }
191c8dfe907SJonas Devlieghere 
192c8dfe907SJonas Devlieghere     ReproducerCrashSignal signal = eReproducerCrashSigsegv;
193c8dfe907SJonas Devlieghere   };
194c8dfe907SJonas Devlieghere 
195c8dfe907SJonas Devlieghere protected:
196c8dfe907SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
197c8dfe907SJonas Devlieghere     if (!command.empty()) {
198c8dfe907SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
199c8dfe907SJonas Devlieghere                                    m_cmd_name.c_str());
200c8dfe907SJonas Devlieghere       return false;
201c8dfe907SJonas Devlieghere     }
202c8dfe907SJonas Devlieghere 
203c8dfe907SJonas Devlieghere     auto &r = Reproducer::Instance();
204bb090bb1SJonas Devlieghere 
205bb090bb1SJonas Devlieghere     if (!r.IsCapturing() && !r.IsReplaying()) {
206c8dfe907SJonas Devlieghere       result.SetError(
207c8dfe907SJonas Devlieghere           "forcing a crash is only supported when capturing a reproducer.");
208c8dfe907SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
209c8dfe907SJonas Devlieghere       return false;
210c8dfe907SJonas Devlieghere     }
211c8dfe907SJonas Devlieghere 
212c8dfe907SJonas Devlieghere     switch (m_options.signal) {
213c8dfe907SJonas Devlieghere     case eReproducerCrashSigill:
214c8dfe907SJonas Devlieghere       std::raise(SIGILL);
215c8dfe907SJonas Devlieghere       break;
216c8dfe907SJonas Devlieghere     case eReproducerCrashSigsegv:
217c8dfe907SJonas Devlieghere       std::raise(SIGSEGV);
218c8dfe907SJonas Devlieghere       break;
219c8dfe907SJonas Devlieghere     }
220c8dfe907SJonas Devlieghere 
221c8dfe907SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
222c8dfe907SJonas Devlieghere     return result.Succeeded();
223c8dfe907SJonas Devlieghere   }
224c8dfe907SJonas Devlieghere 
225c8dfe907SJonas Devlieghere private:
226c8dfe907SJonas Devlieghere   CommandOptions m_options;
227c8dfe907SJonas Devlieghere };
228c8dfe907SJonas Devlieghere 
22915eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed {
2309e046f02SJonas Devlieghere public:
23115eacd74SJonas Devlieghere   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
232973d66eeSJonas Devlieghere       : CommandObjectParsed(
233973d66eeSJonas Devlieghere             interpreter, "reproducer status",
234c8dfe907SJonas Devlieghere             "Show the current reproducer status. In capture mode the "
235c8dfe907SJonas Devlieghere             "debugger "
236973d66eeSJonas Devlieghere             "is collecting all the information it needs to create a "
237973d66eeSJonas Devlieghere             "reproducer.  In replay mode the reproducer is replaying a "
238973d66eeSJonas Devlieghere             "reproducer. When the reproducers are off, no data is collected "
239973d66eeSJonas Devlieghere             "and no reproducer can be generated.",
240973d66eeSJonas Devlieghere             nullptr) {}
2419e046f02SJonas Devlieghere 
24215eacd74SJonas Devlieghere   ~CommandObjectReproducerStatus() override = default;
2439e046f02SJonas Devlieghere 
2449e046f02SJonas Devlieghere protected:
2459e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
24615eacd74SJonas Devlieghere     if (!command.empty()) {
24715eacd74SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
2489e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
2499e046f02SJonas Devlieghere       return false;
2509e046f02SJonas Devlieghere     }
2519e046f02SJonas Devlieghere 
25297fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
253865cd093SJonas Devlieghere     if (r.IsCapturing()) {
25415eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in capture mode.\n";
255865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
25615eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in replay mode.\n";
25715eacd74SJonas Devlieghere     } else {
25815eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is off.\n";
2599e046f02SJonas Devlieghere     }
2609e046f02SJonas Devlieghere 
261*982a77b6SJonas Devlieghere     if (r.IsCapturing() || r.IsReplaying()) {
262*982a77b6SJonas Devlieghere       result.GetOutputStream()
263*982a77b6SJonas Devlieghere           << "Path: " << r.GetReproducerPath().GetPath() << '\n';
264*982a77b6SJonas Devlieghere     }
265*982a77b6SJonas Devlieghere 
266*982a77b6SJonas Devlieghere     // Auto generate is hidden unless enabled because this is mostly for
267*982a77b6SJonas Devlieghere     // development and testing.
268*982a77b6SJonas Devlieghere     if (Generator *g = r.GetGenerator()) {
269*982a77b6SJonas Devlieghere       if (g->IsAutoGenerate())
270*982a77b6SJonas Devlieghere         result.GetOutputStream() << "Auto generate: on\n";
271*982a77b6SJonas Devlieghere     }
272*982a77b6SJonas Devlieghere 
27315eacd74SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishResult);
2749e046f02SJonas Devlieghere     return result.Succeeded();
2759e046f02SJonas Devlieghere   }
2769e046f02SJonas Devlieghere };
2779e046f02SJonas Devlieghere 
27897fc8eb4SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) {
27997fc8eb4SJonas Devlieghere   result.GetErrorStream().Printf("error: %s\n",
28097fc8eb4SJonas Devlieghere                                  toString(std::move(err)).c_str());
28197fc8eb4SJonas Devlieghere   result.SetStatus(eReturnStatusFailed);
28297fc8eb4SJonas Devlieghere }
28397fc8eb4SJonas Devlieghere 
28497fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed {
28597fc8eb4SJonas Devlieghere public:
28697fc8eb4SJonas Devlieghere   CommandObjectReproducerDump(CommandInterpreter &interpreter)
28797fc8eb4SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer dump",
28864b7d955SJonas Devlieghere                             "Dump the information contained in a reproducer. "
28964b7d955SJonas Devlieghere                             "If no reproducer is specified during replay, it "
29064b7d955SJonas Devlieghere                             "dumps the content of the current reproducer.",
29197fc8eb4SJonas Devlieghere                             nullptr) {}
29297fc8eb4SJonas Devlieghere 
29397fc8eb4SJonas Devlieghere   ~CommandObjectReproducerDump() override = default;
29497fc8eb4SJonas Devlieghere 
29597fc8eb4SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
29697fc8eb4SJonas Devlieghere 
29797fc8eb4SJonas Devlieghere   class CommandOptions : public Options {
29897fc8eb4SJonas Devlieghere   public:
29997fc8eb4SJonas Devlieghere     CommandOptions() : Options(), file() {}
30097fc8eb4SJonas Devlieghere 
30197fc8eb4SJonas Devlieghere     ~CommandOptions() override = default;
30297fc8eb4SJonas Devlieghere 
30397fc8eb4SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
30497fc8eb4SJonas Devlieghere                           ExecutionContext *execution_context) override {
30597fc8eb4SJonas Devlieghere       Status error;
30697fc8eb4SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
30797fc8eb4SJonas Devlieghere 
30897fc8eb4SJonas Devlieghere       switch (short_option) {
30997fc8eb4SJonas Devlieghere       case 'f':
31097fc8eb4SJonas Devlieghere         file.SetFile(option_arg, FileSpec::Style::native);
31197fc8eb4SJonas Devlieghere         FileSystem::Instance().Resolve(file);
31297fc8eb4SJonas Devlieghere         break;
31397fc8eb4SJonas Devlieghere       case 'p':
31497fc8eb4SJonas Devlieghere         provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
31597fc8eb4SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
31697fc8eb4SJonas Devlieghere         if (!error.Success())
31797fc8eb4SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
31897fc8eb4SJonas Devlieghere                                          option_arg.str().c_str());
31997fc8eb4SJonas Devlieghere         break;
32097fc8eb4SJonas Devlieghere       default:
32197fc8eb4SJonas Devlieghere         llvm_unreachable("Unimplemented option");
32297fc8eb4SJonas Devlieghere       }
32397fc8eb4SJonas Devlieghere 
32497fc8eb4SJonas Devlieghere       return error;
32597fc8eb4SJonas Devlieghere     }
32697fc8eb4SJonas Devlieghere 
32797fc8eb4SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
32897fc8eb4SJonas Devlieghere       file.Clear();
32997fc8eb4SJonas Devlieghere       provider = eReproducerProviderNone;
33097fc8eb4SJonas Devlieghere     }
33197fc8eb4SJonas Devlieghere 
33297fc8eb4SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
33336eea5c3SJonas Devlieghere       return makeArrayRef(g_reproducer_dump_options);
33497fc8eb4SJonas Devlieghere     }
33597fc8eb4SJonas Devlieghere 
33697fc8eb4SJonas Devlieghere     FileSpec file;
33797fc8eb4SJonas Devlieghere     ReproducerProvider provider = eReproducerProviderNone;
33897fc8eb4SJonas Devlieghere   };
33997fc8eb4SJonas Devlieghere 
34097fc8eb4SJonas Devlieghere protected:
34197fc8eb4SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
34297fc8eb4SJonas Devlieghere     if (!command.empty()) {
34397fc8eb4SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
34497fc8eb4SJonas Devlieghere                                    m_cmd_name.c_str());
34597fc8eb4SJonas Devlieghere       return false;
34697fc8eb4SJonas Devlieghere     }
34797fc8eb4SJonas Devlieghere 
34897fc8eb4SJonas Devlieghere     // If no reproducer path is specified, use the loader currently used for
34997fc8eb4SJonas Devlieghere     // replay. Otherwise create a new loader just for dumping.
35097fc8eb4SJonas Devlieghere     llvm::Optional<Loader> loader_storage;
35197fc8eb4SJonas Devlieghere     Loader *loader = nullptr;
35297fc8eb4SJonas Devlieghere     if (!m_options.file) {
35397fc8eb4SJonas Devlieghere       loader = Reproducer::Instance().GetLoader();
35497fc8eb4SJonas Devlieghere       if (loader == nullptr) {
35597fc8eb4SJonas Devlieghere         result.SetError(
35697fc8eb4SJonas Devlieghere             "Not specifying a reproducer is only support during replay.");
35797fc8eb4SJonas Devlieghere         result.SetStatus(eReturnStatusSuccessFinishNoResult);
35897fc8eb4SJonas Devlieghere         return false;
35997fc8eb4SJonas Devlieghere       }
36097fc8eb4SJonas Devlieghere     } else {
36197fc8eb4SJonas Devlieghere       loader_storage.emplace(m_options.file);
36297fc8eb4SJonas Devlieghere       loader = &(*loader_storage);
36397fc8eb4SJonas Devlieghere       if (Error err = loader->LoadIndex()) {
36497fc8eb4SJonas Devlieghere         SetError(result, std::move(err));
36597fc8eb4SJonas Devlieghere         return false;
36697fc8eb4SJonas Devlieghere       }
36797fc8eb4SJonas Devlieghere     }
36897fc8eb4SJonas Devlieghere 
36997fc8eb4SJonas Devlieghere     // If we get here we should have a valid loader.
37097fc8eb4SJonas Devlieghere     assert(loader);
37197fc8eb4SJonas Devlieghere 
37297fc8eb4SJonas Devlieghere     switch (m_options.provider) {
37397fc8eb4SJonas Devlieghere     case eReproducerProviderFiles: {
37497fc8eb4SJonas Devlieghere       FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
37597fc8eb4SJonas Devlieghere 
37697fc8eb4SJonas Devlieghere       // Read the VFS mapping.
37797fc8eb4SJonas Devlieghere       ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
37897fc8eb4SJonas Devlieghere           vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
37997fc8eb4SJonas Devlieghere       if (!buffer) {
38097fc8eb4SJonas Devlieghere         SetError(result, errorCodeToError(buffer.getError()));
38197fc8eb4SJonas Devlieghere         return false;
38297fc8eb4SJonas Devlieghere       }
38397fc8eb4SJonas Devlieghere 
38497fc8eb4SJonas Devlieghere       // Initialize a VFS from the given mapping.
38597fc8eb4SJonas Devlieghere       IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
38697fc8eb4SJonas Devlieghere           std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
38797fc8eb4SJonas Devlieghere 
38897fc8eb4SJonas Devlieghere       // Dump the VFS to a buffer.
38997fc8eb4SJonas Devlieghere       std::string str;
39097fc8eb4SJonas Devlieghere       raw_string_ostream os(str);
39197fc8eb4SJonas Devlieghere       static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os);
39297fc8eb4SJonas Devlieghere       os.flush();
39397fc8eb4SJonas Devlieghere 
39497fc8eb4SJonas Devlieghere       // Return the string.
39597fc8eb4SJonas Devlieghere       result.AppendMessage(str);
39697fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
39797fc8eb4SJonas Devlieghere       return true;
39897fc8eb4SJonas Devlieghere     }
39997fc8eb4SJonas Devlieghere     case eReproducerProviderVersion: {
400b2575da9SJonas Devlieghere       Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
401b2575da9SJonas Devlieghere       if (!version) {
402b2575da9SJonas Devlieghere         SetError(result, version.takeError());
40397fc8eb4SJonas Devlieghere         return false;
40497fc8eb4SJonas Devlieghere       }
405b2575da9SJonas Devlieghere       result.AppendMessage(*version);
40697fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
40797fc8eb4SJonas Devlieghere       return true;
40897fc8eb4SJonas Devlieghere     }
409f4f12012SJonas Devlieghere     case eReproducerProviderWorkingDirectory: {
410f4f12012SJonas Devlieghere       Expected<std::string> cwd =
411f4f12012SJonas Devlieghere           loader->LoadBuffer<WorkingDirectoryProvider>();
412f4f12012SJonas Devlieghere       if (!cwd) {
413f4f12012SJonas Devlieghere         SetError(result, cwd.takeError());
414f4f12012SJonas Devlieghere         return false;
415f4f12012SJonas Devlieghere       }
416f4f12012SJonas Devlieghere       result.AppendMessage(*cwd);
417f4f12012SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
418f4f12012SJonas Devlieghere       return true;
419f4f12012SJonas Devlieghere     }
42097fc8eb4SJonas Devlieghere     case eReproducerProviderCommands: {
4211d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
4221d41d1bcSEric Christopher           repro::MultiLoader<repro::CommandProvider>::Create(loader);
4231d41d1bcSEric Christopher       if (!multi_loader) {
42497fc8eb4SJonas Devlieghere         SetError(result,
42597fc8eb4SJonas Devlieghere                  make_error<StringError>(llvm::inconvertibleErrorCode(),
42697fc8eb4SJonas Devlieghere                                          "Unable to create command loader."));
42797fc8eb4SJonas Devlieghere         return false;
42897fc8eb4SJonas Devlieghere       }
42997fc8eb4SJonas Devlieghere 
43097fc8eb4SJonas Devlieghere       // Iterate over the command files and dump them.
4311d41d1bcSEric Christopher       llvm::Optional<std::string> command_file;
4321d41d1bcSEric Christopher       while ((command_file = multi_loader->GetNextFile())) {
43397fc8eb4SJonas Devlieghere         if (!command_file)
43497fc8eb4SJonas Devlieghere           break;
43597fc8eb4SJonas Devlieghere 
43697fc8eb4SJonas Devlieghere         auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
43797fc8eb4SJonas Devlieghere         if (auto err = command_buffer.getError()) {
43897fc8eb4SJonas Devlieghere           SetError(result, errorCodeToError(err));
43997fc8eb4SJonas Devlieghere           return false;
44097fc8eb4SJonas Devlieghere         }
44197fc8eb4SJonas Devlieghere         result.AppendMessage((*command_buffer)->getBuffer());
44297fc8eb4SJonas Devlieghere       }
44397fc8eb4SJonas Devlieghere 
44497fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
44597fc8eb4SJonas Devlieghere       return true;
44697fc8eb4SJonas Devlieghere     }
44797fc8eb4SJonas Devlieghere     case eReproducerProviderGDB: {
4481d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
4491d41d1bcSEric Christopher           multi_loader =
4501d41d1bcSEric Christopher               repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
4511d41d1bcSEric Christopher       llvm::Optional<std::string> gdb_file;
4521d41d1bcSEric Christopher       while ((gdb_file = multi_loader->GetNextFile())) {
4531d41d1bcSEric Christopher         auto error_or_file = MemoryBuffer::getFile(*gdb_file);
4548fc8d3feSJonas Devlieghere         if (auto err = error_or_file.getError()) {
4558fc8d3feSJonas Devlieghere           SetError(result, errorCodeToError(err));
4568fc8d3feSJonas Devlieghere           return false;
4578fc8d3feSJonas Devlieghere         }
4588fc8d3feSJonas Devlieghere 
4598fc8d3feSJonas Devlieghere         std::vector<GDBRemotePacket> packets;
4608fc8d3feSJonas Devlieghere         yaml::Input yin((*error_or_file)->getBuffer());
4618fc8d3feSJonas Devlieghere         yin >> packets;
4628fc8d3feSJonas Devlieghere 
4638fc8d3feSJonas Devlieghere         if (auto err = yin.error()) {
4648fc8d3feSJonas Devlieghere           SetError(result, errorCodeToError(err));
4658fc8d3feSJonas Devlieghere           return false;
4668fc8d3feSJonas Devlieghere         }
4678fc8d3feSJonas Devlieghere 
4688fc8d3feSJonas Devlieghere         for (GDBRemotePacket &packet : packets) {
4698fc8d3feSJonas Devlieghere           packet.Dump(result.GetOutputStream());
4708fc8d3feSJonas Devlieghere         }
4711d41d1bcSEric Christopher       }
4728fc8d3feSJonas Devlieghere 
47397fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
47497fc8eb4SJonas Devlieghere       return true;
47597fc8eb4SJonas Devlieghere     }
47697fc8eb4SJonas Devlieghere     case eReproducerProviderNone:
47797fc8eb4SJonas Devlieghere       result.SetError("No valid provider specified.");
47897fc8eb4SJonas Devlieghere       return false;
47997fc8eb4SJonas Devlieghere     }
48097fc8eb4SJonas Devlieghere 
48197fc8eb4SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
48297fc8eb4SJonas Devlieghere     return result.Succeeded();
48397fc8eb4SJonas Devlieghere   }
48497fc8eb4SJonas Devlieghere 
48597fc8eb4SJonas Devlieghere private:
48697fc8eb4SJonas Devlieghere   CommandOptions m_options;
48797fc8eb4SJonas Devlieghere };
48897fc8eb4SJonas Devlieghere 
4899e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer(
4909e046f02SJonas Devlieghere     CommandInterpreter &interpreter)
491973d66eeSJonas Devlieghere     : CommandObjectMultiword(
492973d66eeSJonas Devlieghere           interpreter, "reproducer",
493c8dfe907SJonas Devlieghere           "Commands for manipulating reproducers. Reproducers make it "
494c8dfe907SJonas Devlieghere           "possible "
49564b7d955SJonas Devlieghere           "to capture full debug sessions with all its dependencies. The "
49664b7d955SJonas Devlieghere           "resulting reproducer is used to replay the debug session while "
49764b7d955SJonas Devlieghere           "debugging the debugger.\n"
49864b7d955SJonas Devlieghere           "Because reproducers need the whole the debug session from "
49964b7d955SJonas Devlieghere           "beginning to end, you need to launch the debugger in capture or "
50064b7d955SJonas Devlieghere           "replay mode, commonly though the command line driver.\n"
50164b7d955SJonas Devlieghere           "Reproducers are unrelated record-replay debugging, as you cannot "
50264b7d955SJonas Devlieghere           "interact with the debugger during replay.\n",
503130ec068SJonas Devlieghere           "reproducer <subcommand> [<subcommand-options>]") {
5049e046f02SJonas Devlieghere   LoadSubCommand(
5059e046f02SJonas Devlieghere       "generate",
5069e046f02SJonas Devlieghere       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
50715eacd74SJonas Devlieghere   LoadSubCommand("status", CommandObjectSP(
50815eacd74SJonas Devlieghere                                new CommandObjectReproducerStatus(interpreter)));
50997fc8eb4SJonas Devlieghere   LoadSubCommand("dump",
51097fc8eb4SJonas Devlieghere                  CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
511c8dfe907SJonas Devlieghere   LoadSubCommand("xcrash", CommandObjectSP(
512c8dfe907SJonas Devlieghere                                new CommandObjectReproducerXCrash(interpreter)));
5139e046f02SJonas Devlieghere }
5149e046f02SJonas Devlieghere 
5159e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default;
516