180814287SRaphael Isemann //===-- CommandObjectReproducer.cpp ---------------------------------------===//
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 
112451cbf0SJonas Devlieghere #include "lldb/Host/HostInfo.h"
1297fc8eb4SJonas Devlieghere #include "lldb/Host/OptionParser.h"
13df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h"
149e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h"
159e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h"
162451cbf0SJonas Devlieghere #include "lldb/Utility/GDBRemote.h"
172451cbf0SJonas Devlieghere #include "lldb/Utility/ProcessInfo.h"
182451cbf0SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
199e046f02SJonas Devlieghere 
20c8dfe907SJonas Devlieghere #include <csignal>
21c8dfe907SJonas Devlieghere 
229e046f02SJonas Devlieghere using namespace lldb;
2397fc8eb4SJonas Devlieghere using namespace llvm;
249e046f02SJonas Devlieghere using namespace lldb_private;
2597fc8eb4SJonas Devlieghere using namespace lldb_private::repro;
2697fc8eb4SJonas Devlieghere 
2797fc8eb4SJonas Devlieghere enum ReproducerProvider {
2897fc8eb4SJonas Devlieghere   eReproducerProviderCommands,
2997fc8eb4SJonas Devlieghere   eReproducerProviderFiles,
30a842950bSJonas Devlieghere   eReproducerProviderSymbolFiles,
3197fc8eb4SJonas Devlieghere   eReproducerProviderGDB,
322451cbf0SJonas Devlieghere   eReproducerProviderProcessInfo,
3397fc8eb4SJonas Devlieghere   eReproducerProviderVersion,
34f4f12012SJonas Devlieghere   eReproducerProviderWorkingDirectory,
3573af341bSJonas Devlieghere   eReproducerProviderHomeDirectory,
3697fc8eb4SJonas Devlieghere   eReproducerProviderNone
3797fc8eb4SJonas Devlieghere };
3897fc8eb4SJonas Devlieghere 
3997fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
4097fc8eb4SJonas Devlieghere     {
4197fc8eb4SJonas Devlieghere         eReproducerProviderCommands,
4297fc8eb4SJonas Devlieghere         "commands",
4397fc8eb4SJonas Devlieghere         "Command Interpreter Commands",
4497fc8eb4SJonas Devlieghere     },
4597fc8eb4SJonas Devlieghere     {
4697fc8eb4SJonas Devlieghere         eReproducerProviderFiles,
4797fc8eb4SJonas Devlieghere         "files",
4897fc8eb4SJonas Devlieghere         "Files",
4997fc8eb4SJonas Devlieghere     },
5097fc8eb4SJonas Devlieghere     {
51a842950bSJonas Devlieghere         eReproducerProviderSymbolFiles,
52a842950bSJonas Devlieghere         "symbol-files",
53a842950bSJonas Devlieghere         "Symbol Files",
54a842950bSJonas Devlieghere     },
55a842950bSJonas Devlieghere     {
5697fc8eb4SJonas Devlieghere         eReproducerProviderGDB,
5797fc8eb4SJonas Devlieghere         "gdb",
5897fc8eb4SJonas Devlieghere         "GDB Remote Packets",
5997fc8eb4SJonas Devlieghere     },
6097fc8eb4SJonas Devlieghere     {
612451cbf0SJonas Devlieghere         eReproducerProviderProcessInfo,
622451cbf0SJonas Devlieghere         "processes",
632451cbf0SJonas Devlieghere         "Process Info",
642451cbf0SJonas Devlieghere     },
652451cbf0SJonas Devlieghere     {
6697fc8eb4SJonas Devlieghere         eReproducerProviderVersion,
6797fc8eb4SJonas Devlieghere         "version",
6897fc8eb4SJonas Devlieghere         "Version",
6997fc8eb4SJonas Devlieghere     },
7097fc8eb4SJonas Devlieghere     {
71f4f12012SJonas Devlieghere         eReproducerProviderWorkingDirectory,
72f4f12012SJonas Devlieghere         "cwd",
73f4f12012SJonas Devlieghere         "Working Directory",
74f4f12012SJonas Devlieghere     },
75f4f12012SJonas Devlieghere     {
7673af341bSJonas Devlieghere         eReproducerProviderHomeDirectory,
7773af341bSJonas Devlieghere         "home",
7873af341bSJonas Devlieghere         "Home Directory",
7973af341bSJonas Devlieghere     },
8073af341bSJonas Devlieghere     {
8197fc8eb4SJonas Devlieghere         eReproducerProviderNone,
8297fc8eb4SJonas Devlieghere         "none",
8397fc8eb4SJonas Devlieghere         "None",
8497fc8eb4SJonas Devlieghere     },
8597fc8eb4SJonas Devlieghere };
8697fc8eb4SJonas Devlieghere 
8797fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() {
8897fc8eb4SJonas Devlieghere   return OptionEnumValues(g_reproducer_provider_type);
8997fc8eb4SJonas Devlieghere }
9097fc8eb4SJonas Devlieghere 
9136eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump
9297fc8eb4SJonas Devlieghere #include "CommandOptions.inc"
939e046f02SJonas Devlieghere 
94c8dfe907SJonas Devlieghere enum ReproducerCrashSignal {
95c8dfe907SJonas Devlieghere   eReproducerCrashSigill,
96c8dfe907SJonas Devlieghere   eReproducerCrashSigsegv,
97c8dfe907SJonas Devlieghere };
98c8dfe907SJonas Devlieghere 
99c8dfe907SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_signaltype[] = {
100c8dfe907SJonas Devlieghere     {
101c8dfe907SJonas Devlieghere         eReproducerCrashSigill,
102c8dfe907SJonas Devlieghere         "SIGILL",
103c8dfe907SJonas Devlieghere         "Illegal instruction",
104c8dfe907SJonas Devlieghere     },
105c8dfe907SJonas Devlieghere     {
106c8dfe907SJonas Devlieghere         eReproducerCrashSigsegv,
107c8dfe907SJonas Devlieghere         "SIGSEGV",
108c8dfe907SJonas Devlieghere         "Segmentation fault",
109c8dfe907SJonas Devlieghere     },
110c8dfe907SJonas Devlieghere };
111c8dfe907SJonas Devlieghere 
112c8dfe907SJonas Devlieghere static constexpr OptionEnumValues ReproducerSignalType() {
113c8dfe907SJonas Devlieghere   return OptionEnumValues(g_reproducer_signaltype);
114c8dfe907SJonas Devlieghere }
115c8dfe907SJonas Devlieghere 
116c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash
117c8dfe907SJonas Devlieghere #include "CommandOptions.inc"
118c8dfe907SJonas Devlieghere 
119*37469061SJonas Devlieghere #define LLDB_OPTIONS_reproducer_verify
120*37469061SJonas Devlieghere #include "CommandOptions.inc"
121*37469061SJonas Devlieghere 
1222451cbf0SJonas Devlieghere template <typename T>
1232451cbf0SJonas Devlieghere llvm::Expected<T> static ReadFromYAML(StringRef filename) {
1242451cbf0SJonas Devlieghere   auto error_or_file = MemoryBuffer::getFile(filename);
1252451cbf0SJonas Devlieghere   if (auto err = error_or_file.getError()) {
1262451cbf0SJonas Devlieghere     return errorCodeToError(err);
1272451cbf0SJonas Devlieghere   }
1282451cbf0SJonas Devlieghere 
1292451cbf0SJonas Devlieghere   T t;
1302451cbf0SJonas Devlieghere   yaml::Input yin((*error_or_file)->getBuffer());
1312451cbf0SJonas Devlieghere   yin >> t;
1322451cbf0SJonas Devlieghere 
1332451cbf0SJonas Devlieghere   if (auto err = yin.error()) {
1342451cbf0SJonas Devlieghere     return errorCodeToError(err);
1352451cbf0SJonas Devlieghere   }
1362451cbf0SJonas Devlieghere 
1372451cbf0SJonas Devlieghere   return t;
1382451cbf0SJonas Devlieghere }
1392451cbf0SJonas Devlieghere 
140*37469061SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) {
141*37469061SJonas Devlieghere   result.GetErrorStream().Printf("error: %s\n",
142*37469061SJonas Devlieghere                                  toString(std::move(err)).c_str());
143*37469061SJonas Devlieghere   result.SetStatus(eReturnStatusFailed);
144*37469061SJonas Devlieghere }
145*37469061SJonas Devlieghere 
146*37469061SJonas Devlieghere /// Create a loader from the given path if specified. Otherwise use the current
147*37469061SJonas Devlieghere /// loader used for replay.
148*37469061SJonas Devlieghere static Loader *
149*37469061SJonas Devlieghere GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage,
150*37469061SJonas Devlieghere                            CommandReturnObject &result,
151*37469061SJonas Devlieghere                            FileSpec reproducer_path) {
152*37469061SJonas Devlieghere   if (reproducer_path) {
153*37469061SJonas Devlieghere     loader_storage.emplace(reproducer_path);
154*37469061SJonas Devlieghere     Loader *loader = &(*loader_storage);
155*37469061SJonas Devlieghere     if (Error err = loader->LoadIndex()) {
156*37469061SJonas Devlieghere       // This is a hard error and will set the result to eReturnStatusFailed.
157*37469061SJonas Devlieghere       SetError(result, std::move(err));
158*37469061SJonas Devlieghere       return nullptr;
159*37469061SJonas Devlieghere     }
160*37469061SJonas Devlieghere     return loader;
161*37469061SJonas Devlieghere   }
162*37469061SJonas Devlieghere 
163*37469061SJonas Devlieghere   if (Loader *loader = Reproducer::Instance().GetLoader())
164*37469061SJonas Devlieghere     return loader;
165*37469061SJonas Devlieghere 
166*37469061SJonas Devlieghere   // This is a soft error because this is expected to fail during capture.
167*37469061SJonas Devlieghere   result.SetError("Not specifying a reproducer is only support during replay.");
168*37469061SJonas Devlieghere   result.SetStatus(eReturnStatusSuccessFinishNoResult);
169*37469061SJonas Devlieghere   return nullptr;
170*37469061SJonas Devlieghere }
171*37469061SJonas Devlieghere 
1729e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed {
1739e046f02SJonas Devlieghere public:
1749e046f02SJonas Devlieghere   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
175973d66eeSJonas Devlieghere       : CommandObjectParsed(
176973d66eeSJonas Devlieghere             interpreter, "reproducer generate",
177973d66eeSJonas Devlieghere             "Generate reproducer on disk. When the debugger is in capture "
178973d66eeSJonas Devlieghere             "mode, this command will output the reproducer to a directory on "
1790cf86da1SJonas Devlieghere             "disk and quit. In replay mode this command in a no-op.",
180973d66eeSJonas Devlieghere             nullptr) {}
1819e046f02SJonas Devlieghere 
1829e046f02SJonas Devlieghere   ~CommandObjectReproducerGenerate() override = default;
1839e046f02SJonas Devlieghere 
1849e046f02SJonas Devlieghere protected:
1859e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
1869e046f02SJonas Devlieghere     if (!command.empty()) {
1879e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
1889e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
1899e046f02SJonas Devlieghere       return false;
1909e046f02SJonas Devlieghere     }
1919e046f02SJonas Devlieghere 
19297fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
1939e046f02SJonas Devlieghere     if (auto generator = r.GetGenerator()) {
1949e046f02SJonas Devlieghere       generator->Keep();
195865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
196bb090bb1SJonas Devlieghere       // Make this operation a NO-OP in replay mode.
1972dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1982dca6538SJonas Devlieghere       return result.Succeeded();
1999e046f02SJonas Devlieghere     } else {
2009e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer generator");
2012dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusFailed);
2029e046f02SJonas Devlieghere       return false;
2039e046f02SJonas Devlieghere     }
2049e046f02SJonas Devlieghere 
2059e046f02SJonas Devlieghere     result.GetOutputStream()
2069e046f02SJonas Devlieghere         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
2071c5250abSJonas Devlieghere     result.GetOutputStream()
2081c5250abSJonas Devlieghere         << "Please have a look at the directory to assess if you're willing to "
2091c5250abSJonas Devlieghere            "share the contained information.\n";
2109e046f02SJonas Devlieghere 
2110cf86da1SJonas Devlieghere     m_interpreter.BroadcastEvent(
2120cf86da1SJonas Devlieghere         CommandInterpreter::eBroadcastBitQuitCommandReceived);
2130cf86da1SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
2149e046f02SJonas Devlieghere     return result.Succeeded();
2159e046f02SJonas Devlieghere   }
2169e046f02SJonas Devlieghere };
2179e046f02SJonas Devlieghere 
218c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed {
219c8dfe907SJonas Devlieghere public:
220c8dfe907SJonas Devlieghere   CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
221c8dfe907SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer xcrash",
222c8dfe907SJonas Devlieghere                             "Intentionally force  the debugger to crash in "
223c8dfe907SJonas Devlieghere                             "order to trigger and test reproducer generation.",
224c8dfe907SJonas Devlieghere                             nullptr) {}
225c8dfe907SJonas Devlieghere 
226c8dfe907SJonas Devlieghere   ~CommandObjectReproducerXCrash() override = default;
227c8dfe907SJonas Devlieghere 
228c8dfe907SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
229c8dfe907SJonas Devlieghere 
230c8dfe907SJonas Devlieghere   class CommandOptions : public Options {
231c8dfe907SJonas Devlieghere   public:
232c8dfe907SJonas Devlieghere     CommandOptions() : Options() {}
233c8dfe907SJonas Devlieghere 
234c8dfe907SJonas Devlieghere     ~CommandOptions() override = default;
235c8dfe907SJonas Devlieghere 
236c8dfe907SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
237c8dfe907SJonas Devlieghere                           ExecutionContext *execution_context) override {
238c8dfe907SJonas Devlieghere       Status error;
239c8dfe907SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
240c8dfe907SJonas Devlieghere 
241c8dfe907SJonas Devlieghere       switch (short_option) {
242c8dfe907SJonas Devlieghere       case 's':
243c8dfe907SJonas Devlieghere         signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
244c8dfe907SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
245c8dfe907SJonas Devlieghere         if (!error.Success())
246c8dfe907SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
247c8dfe907SJonas Devlieghere                                          option_arg.str().c_str());
248c8dfe907SJonas Devlieghere         break;
249c8dfe907SJonas Devlieghere       default:
250c8dfe907SJonas Devlieghere         llvm_unreachable("Unimplemented option");
251c8dfe907SJonas Devlieghere       }
252c8dfe907SJonas Devlieghere 
253c8dfe907SJonas Devlieghere       return error;
254c8dfe907SJonas Devlieghere     }
255c8dfe907SJonas Devlieghere 
256c8dfe907SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
257c8dfe907SJonas Devlieghere       signal = eReproducerCrashSigsegv;
258c8dfe907SJonas Devlieghere     }
259c8dfe907SJonas Devlieghere 
260c8dfe907SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
261c8dfe907SJonas Devlieghere       return makeArrayRef(g_reproducer_xcrash_options);
262c8dfe907SJonas Devlieghere     }
263c8dfe907SJonas Devlieghere 
264c8dfe907SJonas Devlieghere     ReproducerCrashSignal signal = eReproducerCrashSigsegv;
265c8dfe907SJonas Devlieghere   };
266c8dfe907SJonas Devlieghere 
267c8dfe907SJonas Devlieghere protected:
268c8dfe907SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
269c8dfe907SJonas Devlieghere     if (!command.empty()) {
270c8dfe907SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
271c8dfe907SJonas Devlieghere                                    m_cmd_name.c_str());
272c8dfe907SJonas Devlieghere       return false;
273c8dfe907SJonas Devlieghere     }
274c8dfe907SJonas Devlieghere 
275c8dfe907SJonas Devlieghere     auto &r = Reproducer::Instance();
276bb090bb1SJonas Devlieghere 
277bb090bb1SJonas Devlieghere     if (!r.IsCapturing() && !r.IsReplaying()) {
278c8dfe907SJonas Devlieghere       result.SetError(
279c8dfe907SJonas Devlieghere           "forcing a crash is only supported when capturing a reproducer.");
280c8dfe907SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
281c8dfe907SJonas Devlieghere       return false;
282c8dfe907SJonas Devlieghere     }
283c8dfe907SJonas Devlieghere 
284c8dfe907SJonas Devlieghere     switch (m_options.signal) {
285c8dfe907SJonas Devlieghere     case eReproducerCrashSigill:
286c8dfe907SJonas Devlieghere       std::raise(SIGILL);
287c8dfe907SJonas Devlieghere       break;
288c8dfe907SJonas Devlieghere     case eReproducerCrashSigsegv:
289c8dfe907SJonas Devlieghere       std::raise(SIGSEGV);
290c8dfe907SJonas Devlieghere       break;
291c8dfe907SJonas Devlieghere     }
292c8dfe907SJonas Devlieghere 
293c8dfe907SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
294c8dfe907SJonas Devlieghere     return result.Succeeded();
295c8dfe907SJonas Devlieghere   }
296c8dfe907SJonas Devlieghere 
297c8dfe907SJonas Devlieghere private:
298c8dfe907SJonas Devlieghere   CommandOptions m_options;
299c8dfe907SJonas Devlieghere };
300c8dfe907SJonas Devlieghere 
30115eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed {
3029e046f02SJonas Devlieghere public:
30315eacd74SJonas Devlieghere   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
304973d66eeSJonas Devlieghere       : CommandObjectParsed(
305973d66eeSJonas Devlieghere             interpreter, "reproducer status",
306c8dfe907SJonas Devlieghere             "Show the current reproducer status. In capture mode the "
307c8dfe907SJonas Devlieghere             "debugger "
308973d66eeSJonas Devlieghere             "is collecting all the information it needs to create a "
309973d66eeSJonas Devlieghere             "reproducer.  In replay mode the reproducer is replaying a "
310973d66eeSJonas Devlieghere             "reproducer. When the reproducers are off, no data is collected "
311973d66eeSJonas Devlieghere             "and no reproducer can be generated.",
312973d66eeSJonas Devlieghere             nullptr) {}
3139e046f02SJonas Devlieghere 
31415eacd74SJonas Devlieghere   ~CommandObjectReproducerStatus() override = default;
3159e046f02SJonas Devlieghere 
3169e046f02SJonas Devlieghere protected:
3179e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
31815eacd74SJonas Devlieghere     if (!command.empty()) {
31915eacd74SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
3209e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
3219e046f02SJonas Devlieghere       return false;
3229e046f02SJonas Devlieghere     }
3239e046f02SJonas Devlieghere 
32497fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
325865cd093SJonas Devlieghere     if (r.IsCapturing()) {
32615eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in capture mode.\n";
327865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
32815eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in replay mode.\n";
32915eacd74SJonas Devlieghere     } else {
33015eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is off.\n";
3319e046f02SJonas Devlieghere     }
3329e046f02SJonas Devlieghere 
333982a77b6SJonas Devlieghere     if (r.IsCapturing() || r.IsReplaying()) {
334982a77b6SJonas Devlieghere       result.GetOutputStream()
335982a77b6SJonas Devlieghere           << "Path: " << r.GetReproducerPath().GetPath() << '\n';
336982a77b6SJonas Devlieghere     }
337982a77b6SJonas Devlieghere 
338982a77b6SJonas Devlieghere     // Auto generate is hidden unless enabled because this is mostly for
339982a77b6SJonas Devlieghere     // development and testing.
340982a77b6SJonas Devlieghere     if (Generator *g = r.GetGenerator()) {
341982a77b6SJonas Devlieghere       if (g->IsAutoGenerate())
342982a77b6SJonas Devlieghere         result.GetOutputStream() << "Auto generate: on\n";
343982a77b6SJonas Devlieghere     }
344982a77b6SJonas Devlieghere 
34515eacd74SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishResult);
3469e046f02SJonas Devlieghere     return result.Succeeded();
3479e046f02SJonas Devlieghere   }
3489e046f02SJonas Devlieghere };
3499e046f02SJonas Devlieghere 
35097fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed {
35197fc8eb4SJonas Devlieghere public:
35297fc8eb4SJonas Devlieghere   CommandObjectReproducerDump(CommandInterpreter &interpreter)
35397fc8eb4SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer dump",
35464b7d955SJonas Devlieghere                             "Dump the information contained in a reproducer. "
35564b7d955SJonas Devlieghere                             "If no reproducer is specified during replay, it "
35664b7d955SJonas Devlieghere                             "dumps the content of the current reproducer.",
35797fc8eb4SJonas Devlieghere                             nullptr) {}
35897fc8eb4SJonas Devlieghere 
35997fc8eb4SJonas Devlieghere   ~CommandObjectReproducerDump() override = default;
36097fc8eb4SJonas Devlieghere 
36197fc8eb4SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
36297fc8eb4SJonas Devlieghere 
36397fc8eb4SJonas Devlieghere   class CommandOptions : public Options {
36497fc8eb4SJonas Devlieghere   public:
36597fc8eb4SJonas Devlieghere     CommandOptions() : Options(), file() {}
36697fc8eb4SJonas Devlieghere 
36797fc8eb4SJonas Devlieghere     ~CommandOptions() override = default;
36897fc8eb4SJonas Devlieghere 
36997fc8eb4SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
37097fc8eb4SJonas Devlieghere                           ExecutionContext *execution_context) override {
37197fc8eb4SJonas Devlieghere       Status error;
37297fc8eb4SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
37397fc8eb4SJonas Devlieghere 
37497fc8eb4SJonas Devlieghere       switch (short_option) {
37597fc8eb4SJonas Devlieghere       case 'f':
37697fc8eb4SJonas Devlieghere         file.SetFile(option_arg, FileSpec::Style::native);
37797fc8eb4SJonas Devlieghere         FileSystem::Instance().Resolve(file);
37897fc8eb4SJonas Devlieghere         break;
37997fc8eb4SJonas Devlieghere       case 'p':
38097fc8eb4SJonas Devlieghere         provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
38197fc8eb4SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
38297fc8eb4SJonas Devlieghere         if (!error.Success())
38397fc8eb4SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
38497fc8eb4SJonas Devlieghere                                          option_arg.str().c_str());
38597fc8eb4SJonas Devlieghere         break;
38697fc8eb4SJonas Devlieghere       default:
38797fc8eb4SJonas Devlieghere         llvm_unreachable("Unimplemented option");
38897fc8eb4SJonas Devlieghere       }
38997fc8eb4SJonas Devlieghere 
39097fc8eb4SJonas Devlieghere       return error;
39197fc8eb4SJonas Devlieghere     }
39297fc8eb4SJonas Devlieghere 
39397fc8eb4SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
39497fc8eb4SJonas Devlieghere       file.Clear();
39597fc8eb4SJonas Devlieghere       provider = eReproducerProviderNone;
39697fc8eb4SJonas Devlieghere     }
39797fc8eb4SJonas Devlieghere 
39897fc8eb4SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
39936eea5c3SJonas Devlieghere       return makeArrayRef(g_reproducer_dump_options);
40097fc8eb4SJonas Devlieghere     }
40197fc8eb4SJonas Devlieghere 
40297fc8eb4SJonas Devlieghere     FileSpec file;
40397fc8eb4SJonas Devlieghere     ReproducerProvider provider = eReproducerProviderNone;
40497fc8eb4SJonas Devlieghere   };
40597fc8eb4SJonas Devlieghere 
40697fc8eb4SJonas Devlieghere protected:
40797fc8eb4SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
40897fc8eb4SJonas Devlieghere     if (!command.empty()) {
40997fc8eb4SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
41097fc8eb4SJonas Devlieghere                                    m_cmd_name.c_str());
41197fc8eb4SJonas Devlieghere       return false;
41297fc8eb4SJonas Devlieghere     }
41397fc8eb4SJonas Devlieghere 
41497fc8eb4SJonas Devlieghere     llvm::Optional<Loader> loader_storage;
415*37469061SJonas Devlieghere     Loader *loader =
416*37469061SJonas Devlieghere         GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
417*37469061SJonas Devlieghere     if (!loader)
41897fc8eb4SJonas Devlieghere       return false;
41997fc8eb4SJonas Devlieghere 
42097fc8eb4SJonas Devlieghere     switch (m_options.provider) {
42197fc8eb4SJonas Devlieghere     case eReproducerProviderFiles: {
42297fc8eb4SJonas Devlieghere       FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
42397fc8eb4SJonas Devlieghere 
42497fc8eb4SJonas Devlieghere       // Read the VFS mapping.
42597fc8eb4SJonas Devlieghere       ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
42697fc8eb4SJonas Devlieghere           vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
42797fc8eb4SJonas Devlieghere       if (!buffer) {
42897fc8eb4SJonas Devlieghere         SetError(result, errorCodeToError(buffer.getError()));
42997fc8eb4SJonas Devlieghere         return false;
43097fc8eb4SJonas Devlieghere       }
43197fc8eb4SJonas Devlieghere 
43297fc8eb4SJonas Devlieghere       // Initialize a VFS from the given mapping.
43397fc8eb4SJonas Devlieghere       IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
43497fc8eb4SJonas Devlieghere           std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
43597fc8eb4SJonas Devlieghere 
43697fc8eb4SJonas Devlieghere       // Dump the VFS to a buffer.
43797fc8eb4SJonas Devlieghere       std::string str;
43897fc8eb4SJonas Devlieghere       raw_string_ostream os(str);
43997fc8eb4SJonas Devlieghere       static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os);
44097fc8eb4SJonas Devlieghere       os.flush();
44197fc8eb4SJonas Devlieghere 
44297fc8eb4SJonas Devlieghere       // Return the string.
44397fc8eb4SJonas Devlieghere       result.AppendMessage(str);
44497fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
44597fc8eb4SJonas Devlieghere       return true;
44697fc8eb4SJonas Devlieghere     }
447a842950bSJonas Devlieghere     case eReproducerProviderSymbolFiles: {
448a842950bSJonas Devlieghere       Expected<std::string> symbol_files =
449a842950bSJonas Devlieghere           loader->LoadBuffer<SymbolFileProvider>();
450a842950bSJonas Devlieghere       if (!symbol_files) {
451a842950bSJonas Devlieghere         SetError(result, symbol_files.takeError());
452a842950bSJonas Devlieghere         return false;
453a842950bSJonas Devlieghere       }
454a842950bSJonas Devlieghere 
455a842950bSJonas Devlieghere       std::vector<SymbolFileProvider::Entry> entries;
456a842950bSJonas Devlieghere       llvm::yaml::Input yin(*symbol_files);
457a842950bSJonas Devlieghere       yin >> entries;
458a842950bSJonas Devlieghere 
459a842950bSJonas Devlieghere       for (const auto &entry : entries) {
460a842950bSJonas Devlieghere         result.AppendMessageWithFormat("- uuid:        %s\n",
461a842950bSJonas Devlieghere                                        entry.uuid.c_str());
462a842950bSJonas Devlieghere         result.AppendMessageWithFormat("  module path: %s\n",
463a842950bSJonas Devlieghere                                        entry.module_path.c_str());
464a842950bSJonas Devlieghere         result.AppendMessageWithFormat("  symbol path: %s\n",
465a842950bSJonas Devlieghere                                        entry.symbol_path.c_str());
466a842950bSJonas Devlieghere       }
467a842950bSJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
468a842950bSJonas Devlieghere       return true;
469a842950bSJonas Devlieghere     }
47097fc8eb4SJonas Devlieghere     case eReproducerProviderVersion: {
471b2575da9SJonas Devlieghere       Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
472b2575da9SJonas Devlieghere       if (!version) {
473b2575da9SJonas Devlieghere         SetError(result, version.takeError());
47497fc8eb4SJonas Devlieghere         return false;
47597fc8eb4SJonas Devlieghere       }
476b2575da9SJonas Devlieghere       result.AppendMessage(*version);
47797fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
47897fc8eb4SJonas Devlieghere       return true;
47997fc8eb4SJonas Devlieghere     }
480f4f12012SJonas Devlieghere     case eReproducerProviderWorkingDirectory: {
481f4f12012SJonas Devlieghere       Expected<std::string> cwd =
48273af341bSJonas Devlieghere           repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
483f4f12012SJonas Devlieghere       if (!cwd) {
484f4f12012SJonas Devlieghere         SetError(result, cwd.takeError());
485f4f12012SJonas Devlieghere         return false;
486f4f12012SJonas Devlieghere       }
487f4f12012SJonas Devlieghere       result.AppendMessage(*cwd);
488f4f12012SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
489f4f12012SJonas Devlieghere       return true;
490f4f12012SJonas Devlieghere     }
49173af341bSJonas Devlieghere     case eReproducerProviderHomeDirectory: {
49273af341bSJonas Devlieghere       Expected<std::string> home =
49373af341bSJonas Devlieghere           repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
49473af341bSJonas Devlieghere       if (!home) {
49573af341bSJonas Devlieghere         SetError(result, home.takeError());
49673af341bSJonas Devlieghere         return false;
49773af341bSJonas Devlieghere       }
49873af341bSJonas Devlieghere       result.AppendMessage(*home);
49973af341bSJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
50073af341bSJonas Devlieghere       return true;
50173af341bSJonas Devlieghere     }
50297fc8eb4SJonas Devlieghere     case eReproducerProviderCommands: {
5031d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
5041d41d1bcSEric Christopher           repro::MultiLoader<repro::CommandProvider>::Create(loader);
5051d41d1bcSEric Christopher       if (!multi_loader) {
50697fc8eb4SJonas Devlieghere         SetError(result,
5074016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create command loader.",
5084016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
50997fc8eb4SJonas Devlieghere         return false;
51097fc8eb4SJonas Devlieghere       }
51197fc8eb4SJonas Devlieghere 
51297fc8eb4SJonas Devlieghere       // Iterate over the command files and dump them.
5131d41d1bcSEric Christopher       llvm::Optional<std::string> command_file;
5141d41d1bcSEric Christopher       while ((command_file = multi_loader->GetNextFile())) {
51597fc8eb4SJonas Devlieghere         if (!command_file)
51697fc8eb4SJonas Devlieghere           break;
51797fc8eb4SJonas Devlieghere 
51897fc8eb4SJonas Devlieghere         auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
51997fc8eb4SJonas Devlieghere         if (auto err = command_buffer.getError()) {
52097fc8eb4SJonas Devlieghere           SetError(result, errorCodeToError(err));
52197fc8eb4SJonas Devlieghere           return false;
52297fc8eb4SJonas Devlieghere         }
52397fc8eb4SJonas Devlieghere         result.AppendMessage((*command_buffer)->getBuffer());
52497fc8eb4SJonas Devlieghere       }
52597fc8eb4SJonas Devlieghere 
52697fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
52797fc8eb4SJonas Devlieghere       return true;
52897fc8eb4SJonas Devlieghere     }
52997fc8eb4SJonas Devlieghere     case eReproducerProviderGDB: {
5301d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
5311d41d1bcSEric Christopher           multi_loader =
5321d41d1bcSEric Christopher               repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
5334016c6b0SJonas Devlieghere 
5344016c6b0SJonas Devlieghere       if (!multi_loader) {
5354016c6b0SJonas Devlieghere         SetError(result,
5364016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create GDB loader.",
5374016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
5384016c6b0SJonas Devlieghere         return false;
5394016c6b0SJonas Devlieghere       }
5404016c6b0SJonas Devlieghere 
5411d41d1bcSEric Christopher       llvm::Optional<std::string> gdb_file;
5421d41d1bcSEric Christopher       while ((gdb_file = multi_loader->GetNextFile())) {
5432451cbf0SJonas Devlieghere         if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
5442451cbf0SJonas Devlieghere                 ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
5452451cbf0SJonas Devlieghere           for (GDBRemotePacket &packet : *packets) {
5468fc8d3feSJonas Devlieghere             packet.Dump(result.GetOutputStream());
5478fc8d3feSJonas Devlieghere           }
5482451cbf0SJonas Devlieghere         } else {
5492451cbf0SJonas Devlieghere           SetError(result, packets.takeError());
5502451cbf0SJonas Devlieghere           return false;
5512451cbf0SJonas Devlieghere         }
5522451cbf0SJonas Devlieghere       }
5532451cbf0SJonas Devlieghere 
5542451cbf0SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
5552451cbf0SJonas Devlieghere       return true;
5562451cbf0SJonas Devlieghere     }
5572451cbf0SJonas Devlieghere     case eReproducerProviderProcessInfo: {
5582451cbf0SJonas Devlieghere       std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
5592451cbf0SJonas Devlieghere           multi_loader =
5602451cbf0SJonas Devlieghere               repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
5612451cbf0SJonas Devlieghere 
5622451cbf0SJonas Devlieghere       if (!multi_loader) {
5632451cbf0SJonas Devlieghere         SetError(result, make_error<StringError>(
5642451cbf0SJonas Devlieghere                              llvm::inconvertibleErrorCode(),
5652451cbf0SJonas Devlieghere                              "Unable to create process info loader."));
5662451cbf0SJonas Devlieghere         return false;
5672451cbf0SJonas Devlieghere       }
5682451cbf0SJonas Devlieghere 
5692451cbf0SJonas Devlieghere       llvm::Optional<std::string> process_file;
5702451cbf0SJonas Devlieghere       while ((process_file = multi_loader->GetNextFile())) {
5712451cbf0SJonas Devlieghere         if (llvm::Expected<ProcessInstanceInfoList> infos =
5722451cbf0SJonas Devlieghere                 ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
5732451cbf0SJonas Devlieghere           for (ProcessInstanceInfo info : *infos)
5742451cbf0SJonas Devlieghere             info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
5752451cbf0SJonas Devlieghere         } else {
5762451cbf0SJonas Devlieghere           SetError(result, infos.takeError());
5772451cbf0SJonas Devlieghere           return false;
5782451cbf0SJonas Devlieghere         }
5791d41d1bcSEric Christopher       }
5808fc8d3feSJonas Devlieghere 
58197fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
58297fc8eb4SJonas Devlieghere       return true;
58397fc8eb4SJonas Devlieghere     }
58497fc8eb4SJonas Devlieghere     case eReproducerProviderNone:
58597fc8eb4SJonas Devlieghere       result.SetError("No valid provider specified.");
58697fc8eb4SJonas Devlieghere       return false;
58797fc8eb4SJonas Devlieghere     }
58897fc8eb4SJonas Devlieghere 
58997fc8eb4SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
59097fc8eb4SJonas Devlieghere     return result.Succeeded();
59197fc8eb4SJonas Devlieghere   }
59297fc8eb4SJonas Devlieghere 
59397fc8eb4SJonas Devlieghere private:
59497fc8eb4SJonas Devlieghere   CommandOptions m_options;
59597fc8eb4SJonas Devlieghere };
59697fc8eb4SJonas Devlieghere 
597*37469061SJonas Devlieghere class CommandObjectReproducerVerify : public CommandObjectParsed {
598*37469061SJonas Devlieghere public:
599*37469061SJonas Devlieghere   CommandObjectReproducerVerify(CommandInterpreter &interpreter)
600*37469061SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer verify",
601*37469061SJonas Devlieghere                             "Verify the contents of a reproducer. "
602*37469061SJonas Devlieghere                             "If no reproducer is specified during replay, it "
603*37469061SJonas Devlieghere                             "verifies the content of the current reproducer.",
604*37469061SJonas Devlieghere                             nullptr) {}
605*37469061SJonas Devlieghere 
606*37469061SJonas Devlieghere   ~CommandObjectReproducerVerify() override = default;
607*37469061SJonas Devlieghere 
608*37469061SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
609*37469061SJonas Devlieghere 
610*37469061SJonas Devlieghere   class CommandOptions : public Options {
611*37469061SJonas Devlieghere   public:
612*37469061SJonas Devlieghere     CommandOptions() : Options(), file() {}
613*37469061SJonas Devlieghere 
614*37469061SJonas Devlieghere     ~CommandOptions() override = default;
615*37469061SJonas Devlieghere 
616*37469061SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
617*37469061SJonas Devlieghere                           ExecutionContext *execution_context) override {
618*37469061SJonas Devlieghere       Status error;
619*37469061SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
620*37469061SJonas Devlieghere 
621*37469061SJonas Devlieghere       switch (short_option) {
622*37469061SJonas Devlieghere       case 'f':
623*37469061SJonas Devlieghere         file.SetFile(option_arg, FileSpec::Style::native);
624*37469061SJonas Devlieghere         FileSystem::Instance().Resolve(file);
625*37469061SJonas Devlieghere         break;
626*37469061SJonas Devlieghere       default:
627*37469061SJonas Devlieghere         llvm_unreachable("Unimplemented option");
628*37469061SJonas Devlieghere       }
629*37469061SJonas Devlieghere 
630*37469061SJonas Devlieghere       return error;
631*37469061SJonas Devlieghere     }
632*37469061SJonas Devlieghere 
633*37469061SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
634*37469061SJonas Devlieghere       file.Clear();
635*37469061SJonas Devlieghere     }
636*37469061SJonas Devlieghere 
637*37469061SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
638*37469061SJonas Devlieghere       return makeArrayRef(g_reproducer_verify_options);
639*37469061SJonas Devlieghere     }
640*37469061SJonas Devlieghere 
641*37469061SJonas Devlieghere     FileSpec file;
642*37469061SJonas Devlieghere   };
643*37469061SJonas Devlieghere 
644*37469061SJonas Devlieghere protected:
645*37469061SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
646*37469061SJonas Devlieghere     if (!command.empty()) {
647*37469061SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
648*37469061SJonas Devlieghere                                    m_cmd_name.c_str());
649*37469061SJonas Devlieghere       return false;
650*37469061SJonas Devlieghere     }
651*37469061SJonas Devlieghere 
652*37469061SJonas Devlieghere     llvm::Optional<Loader> loader_storage;
653*37469061SJonas Devlieghere     Loader *loader =
654*37469061SJonas Devlieghere         GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
655*37469061SJonas Devlieghere     if (!loader)
656*37469061SJonas Devlieghere       return false;
657*37469061SJonas Devlieghere 
658*37469061SJonas Devlieghere     bool errors = false;
659*37469061SJonas Devlieghere     auto error_callback = [&](llvm::StringRef error) {
660*37469061SJonas Devlieghere       errors = true;
661*37469061SJonas Devlieghere       result.AppendError(error);
662*37469061SJonas Devlieghere     };
663*37469061SJonas Devlieghere 
664*37469061SJonas Devlieghere     bool warnings = false;
665*37469061SJonas Devlieghere     auto warning_callback = [&](llvm::StringRef warning) {
666*37469061SJonas Devlieghere       warnings = true;
667*37469061SJonas Devlieghere       result.AppendWarning(warning);
668*37469061SJonas Devlieghere     };
669*37469061SJonas Devlieghere 
670*37469061SJonas Devlieghere     auto note_callback = [&](llvm::StringRef warning) {
671*37469061SJonas Devlieghere       result.AppendMessage(warning);
672*37469061SJonas Devlieghere     };
673*37469061SJonas Devlieghere 
674*37469061SJonas Devlieghere     Verifier verifier(loader);
675*37469061SJonas Devlieghere     verifier.Verify(error_callback, warning_callback, note_callback);
676*37469061SJonas Devlieghere 
677*37469061SJonas Devlieghere     if (warnings || errors) {
678*37469061SJonas Devlieghere       result.AppendMessage("reproducer verification failed");
679*37469061SJonas Devlieghere       result.SetStatus(eReturnStatusFailed);
680*37469061SJonas Devlieghere     } else {
681*37469061SJonas Devlieghere       result.AppendMessage("reproducer verification succeeded");
682*37469061SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
683*37469061SJonas Devlieghere     }
684*37469061SJonas Devlieghere 
685*37469061SJonas Devlieghere     return result.Succeeded();
686*37469061SJonas Devlieghere   }
687*37469061SJonas Devlieghere 
688*37469061SJonas Devlieghere private:
689*37469061SJonas Devlieghere   CommandOptions m_options;
690*37469061SJonas Devlieghere };
691*37469061SJonas Devlieghere 
6929e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer(
6939e046f02SJonas Devlieghere     CommandInterpreter &interpreter)
694973d66eeSJonas Devlieghere     : CommandObjectMultiword(
695973d66eeSJonas Devlieghere           interpreter, "reproducer",
696c8dfe907SJonas Devlieghere           "Commands for manipulating reproducers. Reproducers make it "
697c8dfe907SJonas Devlieghere           "possible "
69864b7d955SJonas Devlieghere           "to capture full debug sessions with all its dependencies. The "
69964b7d955SJonas Devlieghere           "resulting reproducer is used to replay the debug session while "
70064b7d955SJonas Devlieghere           "debugging the debugger.\n"
70164b7d955SJonas Devlieghere           "Because reproducers need the whole the debug session from "
70264b7d955SJonas Devlieghere           "beginning to end, you need to launch the debugger in capture or "
70364b7d955SJonas Devlieghere           "replay mode, commonly though the command line driver.\n"
70464b7d955SJonas Devlieghere           "Reproducers are unrelated record-replay debugging, as you cannot "
70564b7d955SJonas Devlieghere           "interact with the debugger during replay.\n",
706130ec068SJonas Devlieghere           "reproducer <subcommand> [<subcommand-options>]") {
7079e046f02SJonas Devlieghere   LoadSubCommand(
7089e046f02SJonas Devlieghere       "generate",
7099e046f02SJonas Devlieghere       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
71015eacd74SJonas Devlieghere   LoadSubCommand("status", CommandObjectSP(
71115eacd74SJonas Devlieghere                                new CommandObjectReproducerStatus(interpreter)));
71297fc8eb4SJonas Devlieghere   LoadSubCommand("dump",
71397fc8eb4SJonas Devlieghere                  CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
714*37469061SJonas Devlieghere   LoadSubCommand("verify", CommandObjectSP(
715*37469061SJonas Devlieghere                                new CommandObjectReproducerVerify(interpreter)));
716c8dfe907SJonas Devlieghere   LoadSubCommand("xcrash", CommandObjectSP(
717c8dfe907SJonas Devlieghere                                new CommandObjectReproducerXCrash(interpreter)));
7189e046f02SJonas Devlieghere }
7199e046f02SJonas Devlieghere 
7209e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default;
721