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,
3097fc8eb4SJonas Devlieghere   eReproducerProviderGDB,
312451cbf0SJonas Devlieghere   eReproducerProviderProcessInfo,
3297fc8eb4SJonas Devlieghere   eReproducerProviderVersion,
33f4f12012SJonas Devlieghere   eReproducerProviderWorkingDirectory,
34*73af341bSJonas Devlieghere   eReproducerProviderHomeDirectory,
3597fc8eb4SJonas Devlieghere   eReproducerProviderNone
3697fc8eb4SJonas Devlieghere };
3797fc8eb4SJonas Devlieghere 
3897fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
3997fc8eb4SJonas Devlieghere     {
4097fc8eb4SJonas Devlieghere         eReproducerProviderCommands,
4197fc8eb4SJonas Devlieghere         "commands",
4297fc8eb4SJonas Devlieghere         "Command Interpreter Commands",
4397fc8eb4SJonas Devlieghere     },
4497fc8eb4SJonas Devlieghere     {
4597fc8eb4SJonas Devlieghere         eReproducerProviderFiles,
4697fc8eb4SJonas Devlieghere         "files",
4797fc8eb4SJonas Devlieghere         "Files",
4897fc8eb4SJonas Devlieghere     },
4997fc8eb4SJonas Devlieghere     {
5097fc8eb4SJonas Devlieghere         eReproducerProviderGDB,
5197fc8eb4SJonas Devlieghere         "gdb",
5297fc8eb4SJonas Devlieghere         "GDB Remote Packets",
5397fc8eb4SJonas Devlieghere     },
5497fc8eb4SJonas Devlieghere     {
552451cbf0SJonas Devlieghere         eReproducerProviderProcessInfo,
562451cbf0SJonas Devlieghere         "processes",
572451cbf0SJonas Devlieghere         "Process Info",
582451cbf0SJonas Devlieghere     },
592451cbf0SJonas Devlieghere     {
6097fc8eb4SJonas Devlieghere         eReproducerProviderVersion,
6197fc8eb4SJonas Devlieghere         "version",
6297fc8eb4SJonas Devlieghere         "Version",
6397fc8eb4SJonas Devlieghere     },
6497fc8eb4SJonas Devlieghere     {
65f4f12012SJonas Devlieghere         eReproducerProviderWorkingDirectory,
66f4f12012SJonas Devlieghere         "cwd",
67f4f12012SJonas Devlieghere         "Working Directory",
68f4f12012SJonas Devlieghere     },
69f4f12012SJonas Devlieghere     {
70*73af341bSJonas Devlieghere         eReproducerProviderHomeDirectory,
71*73af341bSJonas Devlieghere         "home",
72*73af341bSJonas Devlieghere         "Home Directory",
73*73af341bSJonas Devlieghere     },
74*73af341bSJonas Devlieghere     {
7597fc8eb4SJonas Devlieghere         eReproducerProviderNone,
7697fc8eb4SJonas Devlieghere         "none",
7797fc8eb4SJonas Devlieghere         "None",
7897fc8eb4SJonas Devlieghere     },
7997fc8eb4SJonas Devlieghere };
8097fc8eb4SJonas Devlieghere 
8197fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() {
8297fc8eb4SJonas Devlieghere   return OptionEnumValues(g_reproducer_provider_type);
8397fc8eb4SJonas Devlieghere }
8497fc8eb4SJonas Devlieghere 
8536eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump
8697fc8eb4SJonas Devlieghere #include "CommandOptions.inc"
879e046f02SJonas Devlieghere 
88c8dfe907SJonas Devlieghere enum ReproducerCrashSignal {
89c8dfe907SJonas Devlieghere   eReproducerCrashSigill,
90c8dfe907SJonas Devlieghere   eReproducerCrashSigsegv,
91c8dfe907SJonas Devlieghere };
92c8dfe907SJonas Devlieghere 
93c8dfe907SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_signaltype[] = {
94c8dfe907SJonas Devlieghere     {
95c8dfe907SJonas Devlieghere         eReproducerCrashSigill,
96c8dfe907SJonas Devlieghere         "SIGILL",
97c8dfe907SJonas Devlieghere         "Illegal instruction",
98c8dfe907SJonas Devlieghere     },
99c8dfe907SJonas Devlieghere     {
100c8dfe907SJonas Devlieghere         eReproducerCrashSigsegv,
101c8dfe907SJonas Devlieghere         "SIGSEGV",
102c8dfe907SJonas Devlieghere         "Segmentation fault",
103c8dfe907SJonas Devlieghere     },
104c8dfe907SJonas Devlieghere };
105c8dfe907SJonas Devlieghere 
106c8dfe907SJonas Devlieghere static constexpr OptionEnumValues ReproducerSignalType() {
107c8dfe907SJonas Devlieghere   return OptionEnumValues(g_reproducer_signaltype);
108c8dfe907SJonas Devlieghere }
109c8dfe907SJonas Devlieghere 
110c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash
111c8dfe907SJonas Devlieghere #include "CommandOptions.inc"
112c8dfe907SJonas Devlieghere 
1132451cbf0SJonas Devlieghere template <typename T>
1142451cbf0SJonas Devlieghere llvm::Expected<T> static ReadFromYAML(StringRef filename) {
1152451cbf0SJonas Devlieghere   auto error_or_file = MemoryBuffer::getFile(filename);
1162451cbf0SJonas Devlieghere   if (auto err = error_or_file.getError()) {
1172451cbf0SJonas Devlieghere     return errorCodeToError(err);
1182451cbf0SJonas Devlieghere   }
1192451cbf0SJonas Devlieghere 
1202451cbf0SJonas Devlieghere   T t;
1212451cbf0SJonas Devlieghere   yaml::Input yin((*error_or_file)->getBuffer());
1222451cbf0SJonas Devlieghere   yin >> t;
1232451cbf0SJonas Devlieghere 
1242451cbf0SJonas Devlieghere   if (auto err = yin.error()) {
1252451cbf0SJonas Devlieghere     return errorCodeToError(err);
1262451cbf0SJonas Devlieghere   }
1272451cbf0SJonas Devlieghere 
1282451cbf0SJonas Devlieghere   return t;
1292451cbf0SJonas Devlieghere }
1302451cbf0SJonas Devlieghere 
1319e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed {
1329e046f02SJonas Devlieghere public:
1339e046f02SJonas Devlieghere   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
134973d66eeSJonas Devlieghere       : CommandObjectParsed(
135973d66eeSJonas Devlieghere             interpreter, "reproducer generate",
136973d66eeSJonas Devlieghere             "Generate reproducer on disk. When the debugger is in capture "
137973d66eeSJonas Devlieghere             "mode, this command will output the reproducer to a directory on "
1380cf86da1SJonas Devlieghere             "disk and quit. In replay mode this command in a no-op.",
139973d66eeSJonas Devlieghere             nullptr) {}
1409e046f02SJonas Devlieghere 
1419e046f02SJonas Devlieghere   ~CommandObjectReproducerGenerate() override = default;
1429e046f02SJonas Devlieghere 
1439e046f02SJonas Devlieghere protected:
1449e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
1459e046f02SJonas Devlieghere     if (!command.empty()) {
1469e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
1479e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
1489e046f02SJonas Devlieghere       return false;
1499e046f02SJonas Devlieghere     }
1509e046f02SJonas Devlieghere 
15197fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
1529e046f02SJonas Devlieghere     if (auto generator = r.GetGenerator()) {
1539e046f02SJonas Devlieghere       generator->Keep();
154865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
155bb090bb1SJonas Devlieghere       // Make this operation a NO-OP in replay mode.
1562dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1572dca6538SJonas Devlieghere       return result.Succeeded();
1589e046f02SJonas Devlieghere     } else {
1599e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer generator");
1602dca6538SJonas Devlieghere       result.SetStatus(eReturnStatusFailed);
1619e046f02SJonas Devlieghere       return false;
1629e046f02SJonas Devlieghere     }
1639e046f02SJonas Devlieghere 
1649e046f02SJonas Devlieghere     result.GetOutputStream()
1659e046f02SJonas Devlieghere         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
1661c5250abSJonas Devlieghere     result.GetOutputStream()
1671c5250abSJonas Devlieghere         << "Please have a look at the directory to assess if you're willing to "
1681c5250abSJonas Devlieghere            "share the contained information.\n";
1699e046f02SJonas Devlieghere 
1700cf86da1SJonas Devlieghere     m_interpreter.BroadcastEvent(
1710cf86da1SJonas Devlieghere         CommandInterpreter::eBroadcastBitQuitCommandReceived);
1720cf86da1SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
1739e046f02SJonas Devlieghere     return result.Succeeded();
1749e046f02SJonas Devlieghere   }
1759e046f02SJonas Devlieghere };
1769e046f02SJonas Devlieghere 
177c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed {
178c8dfe907SJonas Devlieghere public:
179c8dfe907SJonas Devlieghere   CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
180c8dfe907SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer xcrash",
181c8dfe907SJonas Devlieghere                             "Intentionally force  the debugger to crash in "
182c8dfe907SJonas Devlieghere                             "order to trigger and test reproducer generation.",
183c8dfe907SJonas Devlieghere                             nullptr) {}
184c8dfe907SJonas Devlieghere 
185c8dfe907SJonas Devlieghere   ~CommandObjectReproducerXCrash() override = default;
186c8dfe907SJonas Devlieghere 
187c8dfe907SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
188c8dfe907SJonas Devlieghere 
189c8dfe907SJonas Devlieghere   class CommandOptions : public Options {
190c8dfe907SJonas Devlieghere   public:
191c8dfe907SJonas Devlieghere     CommandOptions() : Options() {}
192c8dfe907SJonas Devlieghere 
193c8dfe907SJonas Devlieghere     ~CommandOptions() override = default;
194c8dfe907SJonas Devlieghere 
195c8dfe907SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
196c8dfe907SJonas Devlieghere                           ExecutionContext *execution_context) override {
197c8dfe907SJonas Devlieghere       Status error;
198c8dfe907SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
199c8dfe907SJonas Devlieghere 
200c8dfe907SJonas Devlieghere       switch (short_option) {
201c8dfe907SJonas Devlieghere       case 's':
202c8dfe907SJonas Devlieghere         signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
203c8dfe907SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
204c8dfe907SJonas Devlieghere         if (!error.Success())
205c8dfe907SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
206c8dfe907SJonas Devlieghere                                          option_arg.str().c_str());
207c8dfe907SJonas Devlieghere         break;
208c8dfe907SJonas Devlieghere       default:
209c8dfe907SJonas Devlieghere         llvm_unreachable("Unimplemented option");
210c8dfe907SJonas Devlieghere       }
211c8dfe907SJonas Devlieghere 
212c8dfe907SJonas Devlieghere       return error;
213c8dfe907SJonas Devlieghere     }
214c8dfe907SJonas Devlieghere 
215c8dfe907SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
216c8dfe907SJonas Devlieghere       signal = eReproducerCrashSigsegv;
217c8dfe907SJonas Devlieghere     }
218c8dfe907SJonas Devlieghere 
219c8dfe907SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
220c8dfe907SJonas Devlieghere       return makeArrayRef(g_reproducer_xcrash_options);
221c8dfe907SJonas Devlieghere     }
222c8dfe907SJonas Devlieghere 
223c8dfe907SJonas Devlieghere     ReproducerCrashSignal signal = eReproducerCrashSigsegv;
224c8dfe907SJonas Devlieghere   };
225c8dfe907SJonas Devlieghere 
226c8dfe907SJonas Devlieghere protected:
227c8dfe907SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
228c8dfe907SJonas Devlieghere     if (!command.empty()) {
229c8dfe907SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
230c8dfe907SJonas Devlieghere                                    m_cmd_name.c_str());
231c8dfe907SJonas Devlieghere       return false;
232c8dfe907SJonas Devlieghere     }
233c8dfe907SJonas Devlieghere 
234c8dfe907SJonas Devlieghere     auto &r = Reproducer::Instance();
235bb090bb1SJonas Devlieghere 
236bb090bb1SJonas Devlieghere     if (!r.IsCapturing() && !r.IsReplaying()) {
237c8dfe907SJonas Devlieghere       result.SetError(
238c8dfe907SJonas Devlieghere           "forcing a crash is only supported when capturing a reproducer.");
239c8dfe907SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
240c8dfe907SJonas Devlieghere       return false;
241c8dfe907SJonas Devlieghere     }
242c8dfe907SJonas Devlieghere 
243c8dfe907SJonas Devlieghere     switch (m_options.signal) {
244c8dfe907SJonas Devlieghere     case eReproducerCrashSigill:
245c8dfe907SJonas Devlieghere       std::raise(SIGILL);
246c8dfe907SJonas Devlieghere       break;
247c8dfe907SJonas Devlieghere     case eReproducerCrashSigsegv:
248c8dfe907SJonas Devlieghere       std::raise(SIGSEGV);
249c8dfe907SJonas Devlieghere       break;
250c8dfe907SJonas Devlieghere     }
251c8dfe907SJonas Devlieghere 
252c8dfe907SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
253c8dfe907SJonas Devlieghere     return result.Succeeded();
254c8dfe907SJonas Devlieghere   }
255c8dfe907SJonas Devlieghere 
256c8dfe907SJonas Devlieghere private:
257c8dfe907SJonas Devlieghere   CommandOptions m_options;
258c8dfe907SJonas Devlieghere };
259c8dfe907SJonas Devlieghere 
26015eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed {
2619e046f02SJonas Devlieghere public:
26215eacd74SJonas Devlieghere   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
263973d66eeSJonas Devlieghere       : CommandObjectParsed(
264973d66eeSJonas Devlieghere             interpreter, "reproducer status",
265c8dfe907SJonas Devlieghere             "Show the current reproducer status. In capture mode the "
266c8dfe907SJonas Devlieghere             "debugger "
267973d66eeSJonas Devlieghere             "is collecting all the information it needs to create a "
268973d66eeSJonas Devlieghere             "reproducer.  In replay mode the reproducer is replaying a "
269973d66eeSJonas Devlieghere             "reproducer. When the reproducers are off, no data is collected "
270973d66eeSJonas Devlieghere             "and no reproducer can be generated.",
271973d66eeSJonas Devlieghere             nullptr) {}
2729e046f02SJonas Devlieghere 
27315eacd74SJonas Devlieghere   ~CommandObjectReproducerStatus() override = default;
2749e046f02SJonas Devlieghere 
2759e046f02SJonas Devlieghere protected:
2769e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
27715eacd74SJonas Devlieghere     if (!command.empty()) {
27815eacd74SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
2799e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
2809e046f02SJonas Devlieghere       return false;
2819e046f02SJonas Devlieghere     }
2829e046f02SJonas Devlieghere 
28397fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
284865cd093SJonas Devlieghere     if (r.IsCapturing()) {
28515eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in capture mode.\n";
286865cd093SJonas Devlieghere     } else if (r.IsReplaying()) {
28715eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in replay mode.\n";
28815eacd74SJonas Devlieghere     } else {
28915eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is off.\n";
2909e046f02SJonas Devlieghere     }
2919e046f02SJonas Devlieghere 
292982a77b6SJonas Devlieghere     if (r.IsCapturing() || r.IsReplaying()) {
293982a77b6SJonas Devlieghere       result.GetOutputStream()
294982a77b6SJonas Devlieghere           << "Path: " << r.GetReproducerPath().GetPath() << '\n';
295982a77b6SJonas Devlieghere     }
296982a77b6SJonas Devlieghere 
297982a77b6SJonas Devlieghere     // Auto generate is hidden unless enabled because this is mostly for
298982a77b6SJonas Devlieghere     // development and testing.
299982a77b6SJonas Devlieghere     if (Generator *g = r.GetGenerator()) {
300982a77b6SJonas Devlieghere       if (g->IsAutoGenerate())
301982a77b6SJonas Devlieghere         result.GetOutputStream() << "Auto generate: on\n";
302982a77b6SJonas Devlieghere     }
303982a77b6SJonas Devlieghere 
30415eacd74SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishResult);
3059e046f02SJonas Devlieghere     return result.Succeeded();
3069e046f02SJonas Devlieghere   }
3079e046f02SJonas Devlieghere };
3089e046f02SJonas Devlieghere 
30997fc8eb4SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) {
31097fc8eb4SJonas Devlieghere   result.GetErrorStream().Printf("error: %s\n",
31197fc8eb4SJonas Devlieghere                                  toString(std::move(err)).c_str());
31297fc8eb4SJonas Devlieghere   result.SetStatus(eReturnStatusFailed);
31397fc8eb4SJonas Devlieghere }
31497fc8eb4SJonas Devlieghere 
31597fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed {
31697fc8eb4SJonas Devlieghere public:
31797fc8eb4SJonas Devlieghere   CommandObjectReproducerDump(CommandInterpreter &interpreter)
31897fc8eb4SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer dump",
31964b7d955SJonas Devlieghere                             "Dump the information contained in a reproducer. "
32064b7d955SJonas Devlieghere                             "If no reproducer is specified during replay, it "
32164b7d955SJonas Devlieghere                             "dumps the content of the current reproducer.",
32297fc8eb4SJonas Devlieghere                             nullptr) {}
32397fc8eb4SJonas Devlieghere 
32497fc8eb4SJonas Devlieghere   ~CommandObjectReproducerDump() override = default;
32597fc8eb4SJonas Devlieghere 
32697fc8eb4SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
32797fc8eb4SJonas Devlieghere 
32897fc8eb4SJonas Devlieghere   class CommandOptions : public Options {
32997fc8eb4SJonas Devlieghere   public:
33097fc8eb4SJonas Devlieghere     CommandOptions() : Options(), file() {}
33197fc8eb4SJonas Devlieghere 
33297fc8eb4SJonas Devlieghere     ~CommandOptions() override = default;
33397fc8eb4SJonas Devlieghere 
33497fc8eb4SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
33597fc8eb4SJonas Devlieghere                           ExecutionContext *execution_context) override {
33697fc8eb4SJonas Devlieghere       Status error;
33797fc8eb4SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
33897fc8eb4SJonas Devlieghere 
33997fc8eb4SJonas Devlieghere       switch (short_option) {
34097fc8eb4SJonas Devlieghere       case 'f':
34197fc8eb4SJonas Devlieghere         file.SetFile(option_arg, FileSpec::Style::native);
34297fc8eb4SJonas Devlieghere         FileSystem::Instance().Resolve(file);
34397fc8eb4SJonas Devlieghere         break;
34497fc8eb4SJonas Devlieghere       case 'p':
34597fc8eb4SJonas Devlieghere         provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
34697fc8eb4SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
34797fc8eb4SJonas Devlieghere         if (!error.Success())
34897fc8eb4SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
34997fc8eb4SJonas Devlieghere                                          option_arg.str().c_str());
35097fc8eb4SJonas Devlieghere         break;
35197fc8eb4SJonas Devlieghere       default:
35297fc8eb4SJonas Devlieghere         llvm_unreachable("Unimplemented option");
35397fc8eb4SJonas Devlieghere       }
35497fc8eb4SJonas Devlieghere 
35597fc8eb4SJonas Devlieghere       return error;
35697fc8eb4SJonas Devlieghere     }
35797fc8eb4SJonas Devlieghere 
35897fc8eb4SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
35997fc8eb4SJonas Devlieghere       file.Clear();
36097fc8eb4SJonas Devlieghere       provider = eReproducerProviderNone;
36197fc8eb4SJonas Devlieghere     }
36297fc8eb4SJonas Devlieghere 
36397fc8eb4SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
36436eea5c3SJonas Devlieghere       return makeArrayRef(g_reproducer_dump_options);
36597fc8eb4SJonas Devlieghere     }
36697fc8eb4SJonas Devlieghere 
36797fc8eb4SJonas Devlieghere     FileSpec file;
36897fc8eb4SJonas Devlieghere     ReproducerProvider provider = eReproducerProviderNone;
36997fc8eb4SJonas Devlieghere   };
37097fc8eb4SJonas Devlieghere 
37197fc8eb4SJonas Devlieghere protected:
37297fc8eb4SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
37397fc8eb4SJonas Devlieghere     if (!command.empty()) {
37497fc8eb4SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
37597fc8eb4SJonas Devlieghere                                    m_cmd_name.c_str());
37697fc8eb4SJonas Devlieghere       return false;
37797fc8eb4SJonas Devlieghere     }
37897fc8eb4SJonas Devlieghere 
37997fc8eb4SJonas Devlieghere     // If no reproducer path is specified, use the loader currently used for
38097fc8eb4SJonas Devlieghere     // replay. Otherwise create a new loader just for dumping.
38197fc8eb4SJonas Devlieghere     llvm::Optional<Loader> loader_storage;
38297fc8eb4SJonas Devlieghere     Loader *loader = nullptr;
38397fc8eb4SJonas Devlieghere     if (!m_options.file) {
38497fc8eb4SJonas Devlieghere       loader = Reproducer::Instance().GetLoader();
38597fc8eb4SJonas Devlieghere       if (loader == nullptr) {
38697fc8eb4SJonas Devlieghere         result.SetError(
38797fc8eb4SJonas Devlieghere             "Not specifying a reproducer is only support during replay.");
38897fc8eb4SJonas Devlieghere         result.SetStatus(eReturnStatusSuccessFinishNoResult);
38997fc8eb4SJonas Devlieghere         return false;
39097fc8eb4SJonas Devlieghere       }
39197fc8eb4SJonas Devlieghere     } else {
39297fc8eb4SJonas Devlieghere       loader_storage.emplace(m_options.file);
39397fc8eb4SJonas Devlieghere       loader = &(*loader_storage);
39497fc8eb4SJonas Devlieghere       if (Error err = loader->LoadIndex()) {
39597fc8eb4SJonas Devlieghere         SetError(result, std::move(err));
39697fc8eb4SJonas Devlieghere         return false;
39797fc8eb4SJonas Devlieghere       }
39897fc8eb4SJonas Devlieghere     }
39997fc8eb4SJonas Devlieghere 
40097fc8eb4SJonas Devlieghere     // If we get here we should have a valid loader.
40197fc8eb4SJonas Devlieghere     assert(loader);
40297fc8eb4SJonas Devlieghere 
40397fc8eb4SJonas Devlieghere     switch (m_options.provider) {
40497fc8eb4SJonas Devlieghere     case eReproducerProviderFiles: {
40597fc8eb4SJonas Devlieghere       FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
40697fc8eb4SJonas Devlieghere 
40797fc8eb4SJonas Devlieghere       // Read the VFS mapping.
40897fc8eb4SJonas Devlieghere       ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
40997fc8eb4SJonas Devlieghere           vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
41097fc8eb4SJonas Devlieghere       if (!buffer) {
41197fc8eb4SJonas Devlieghere         SetError(result, errorCodeToError(buffer.getError()));
41297fc8eb4SJonas Devlieghere         return false;
41397fc8eb4SJonas Devlieghere       }
41497fc8eb4SJonas Devlieghere 
41597fc8eb4SJonas Devlieghere       // Initialize a VFS from the given mapping.
41697fc8eb4SJonas Devlieghere       IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
41797fc8eb4SJonas Devlieghere           std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
41897fc8eb4SJonas Devlieghere 
41997fc8eb4SJonas Devlieghere       // Dump the VFS to a buffer.
42097fc8eb4SJonas Devlieghere       std::string str;
42197fc8eb4SJonas Devlieghere       raw_string_ostream os(str);
42297fc8eb4SJonas Devlieghere       static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os);
42397fc8eb4SJonas Devlieghere       os.flush();
42497fc8eb4SJonas Devlieghere 
42597fc8eb4SJonas Devlieghere       // Return the string.
42697fc8eb4SJonas Devlieghere       result.AppendMessage(str);
42797fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
42897fc8eb4SJonas Devlieghere       return true;
42997fc8eb4SJonas Devlieghere     }
43097fc8eb4SJonas Devlieghere     case eReproducerProviderVersion: {
431b2575da9SJonas Devlieghere       Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
432b2575da9SJonas Devlieghere       if (!version) {
433b2575da9SJonas Devlieghere         SetError(result, version.takeError());
43497fc8eb4SJonas Devlieghere         return false;
43597fc8eb4SJonas Devlieghere       }
436b2575da9SJonas Devlieghere       result.AppendMessage(*version);
43797fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
43897fc8eb4SJonas Devlieghere       return true;
43997fc8eb4SJonas Devlieghere     }
440f4f12012SJonas Devlieghere     case eReproducerProviderWorkingDirectory: {
441f4f12012SJonas Devlieghere       Expected<std::string> cwd =
442*73af341bSJonas Devlieghere           repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
443f4f12012SJonas Devlieghere       if (!cwd) {
444f4f12012SJonas Devlieghere         SetError(result, cwd.takeError());
445f4f12012SJonas Devlieghere         return false;
446f4f12012SJonas Devlieghere       }
447f4f12012SJonas Devlieghere       result.AppendMessage(*cwd);
448f4f12012SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
449f4f12012SJonas Devlieghere       return true;
450f4f12012SJonas Devlieghere     }
451*73af341bSJonas Devlieghere     case eReproducerProviderHomeDirectory: {
452*73af341bSJonas Devlieghere       Expected<std::string> home =
453*73af341bSJonas Devlieghere           repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
454*73af341bSJonas Devlieghere       if (!home) {
455*73af341bSJonas Devlieghere         SetError(result, home.takeError());
456*73af341bSJonas Devlieghere         return false;
457*73af341bSJonas Devlieghere       }
458*73af341bSJonas Devlieghere       result.AppendMessage(*home);
459*73af341bSJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
460*73af341bSJonas Devlieghere       return true;
461*73af341bSJonas Devlieghere     }
46297fc8eb4SJonas Devlieghere     case eReproducerProviderCommands: {
4631d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
4641d41d1bcSEric Christopher           repro::MultiLoader<repro::CommandProvider>::Create(loader);
4651d41d1bcSEric Christopher       if (!multi_loader) {
46697fc8eb4SJonas Devlieghere         SetError(result,
4674016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create command loader.",
4684016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
46997fc8eb4SJonas Devlieghere         return false;
47097fc8eb4SJonas Devlieghere       }
47197fc8eb4SJonas Devlieghere 
47297fc8eb4SJonas Devlieghere       // Iterate over the command files and dump them.
4731d41d1bcSEric Christopher       llvm::Optional<std::string> command_file;
4741d41d1bcSEric Christopher       while ((command_file = multi_loader->GetNextFile())) {
47597fc8eb4SJonas Devlieghere         if (!command_file)
47697fc8eb4SJonas Devlieghere           break;
47797fc8eb4SJonas Devlieghere 
47897fc8eb4SJonas Devlieghere         auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
47997fc8eb4SJonas Devlieghere         if (auto err = command_buffer.getError()) {
48097fc8eb4SJonas Devlieghere           SetError(result, errorCodeToError(err));
48197fc8eb4SJonas Devlieghere           return false;
48297fc8eb4SJonas Devlieghere         }
48397fc8eb4SJonas Devlieghere         result.AppendMessage((*command_buffer)->getBuffer());
48497fc8eb4SJonas Devlieghere       }
48597fc8eb4SJonas Devlieghere 
48697fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
48797fc8eb4SJonas Devlieghere       return true;
48897fc8eb4SJonas Devlieghere     }
48997fc8eb4SJonas Devlieghere     case eReproducerProviderGDB: {
4901d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
4911d41d1bcSEric Christopher           multi_loader =
4921d41d1bcSEric Christopher               repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
4934016c6b0SJonas Devlieghere 
4944016c6b0SJonas Devlieghere       if (!multi_loader) {
4954016c6b0SJonas Devlieghere         SetError(result,
4964016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create GDB loader.",
4974016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
4984016c6b0SJonas Devlieghere         return false;
4994016c6b0SJonas Devlieghere       }
5004016c6b0SJonas Devlieghere 
5011d41d1bcSEric Christopher       llvm::Optional<std::string> gdb_file;
5021d41d1bcSEric Christopher       while ((gdb_file = multi_loader->GetNextFile())) {
5032451cbf0SJonas Devlieghere         if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
5042451cbf0SJonas Devlieghere                 ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
5052451cbf0SJonas Devlieghere           for (GDBRemotePacket &packet : *packets) {
5068fc8d3feSJonas Devlieghere             packet.Dump(result.GetOutputStream());
5078fc8d3feSJonas Devlieghere           }
5082451cbf0SJonas Devlieghere         } else {
5092451cbf0SJonas Devlieghere           SetError(result, packets.takeError());
5102451cbf0SJonas Devlieghere           return false;
5112451cbf0SJonas Devlieghere         }
5122451cbf0SJonas Devlieghere       }
5132451cbf0SJonas Devlieghere 
5142451cbf0SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
5152451cbf0SJonas Devlieghere       return true;
5162451cbf0SJonas Devlieghere     }
5172451cbf0SJonas Devlieghere     case eReproducerProviderProcessInfo: {
5182451cbf0SJonas Devlieghere       std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
5192451cbf0SJonas Devlieghere           multi_loader =
5202451cbf0SJonas Devlieghere               repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
5212451cbf0SJonas Devlieghere 
5222451cbf0SJonas Devlieghere       if (!multi_loader) {
5232451cbf0SJonas Devlieghere         SetError(result, make_error<StringError>(
5242451cbf0SJonas Devlieghere                              llvm::inconvertibleErrorCode(),
5252451cbf0SJonas Devlieghere                              "Unable to create process info loader."));
5262451cbf0SJonas Devlieghere         return false;
5272451cbf0SJonas Devlieghere       }
5282451cbf0SJonas Devlieghere 
5292451cbf0SJonas Devlieghere       llvm::Optional<std::string> process_file;
5302451cbf0SJonas Devlieghere       while ((process_file = multi_loader->GetNextFile())) {
5312451cbf0SJonas Devlieghere         if (llvm::Expected<ProcessInstanceInfoList> infos =
5322451cbf0SJonas Devlieghere                 ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
5332451cbf0SJonas Devlieghere           for (ProcessInstanceInfo info : *infos)
5342451cbf0SJonas Devlieghere             info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
5352451cbf0SJonas Devlieghere         } else {
5362451cbf0SJonas Devlieghere           SetError(result, infos.takeError());
5372451cbf0SJonas Devlieghere           return false;
5382451cbf0SJonas Devlieghere         }
5391d41d1bcSEric Christopher       }
5408fc8d3feSJonas Devlieghere 
54197fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
54297fc8eb4SJonas Devlieghere       return true;
54397fc8eb4SJonas Devlieghere     }
54497fc8eb4SJonas Devlieghere     case eReproducerProviderNone:
54597fc8eb4SJonas Devlieghere       result.SetError("No valid provider specified.");
54697fc8eb4SJonas Devlieghere       return false;
54797fc8eb4SJonas Devlieghere     }
54897fc8eb4SJonas Devlieghere 
54997fc8eb4SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
55097fc8eb4SJonas Devlieghere     return result.Succeeded();
55197fc8eb4SJonas Devlieghere   }
55297fc8eb4SJonas Devlieghere 
55397fc8eb4SJonas Devlieghere private:
55497fc8eb4SJonas Devlieghere   CommandOptions m_options;
55597fc8eb4SJonas Devlieghere };
55697fc8eb4SJonas Devlieghere 
5579e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer(
5589e046f02SJonas Devlieghere     CommandInterpreter &interpreter)
559973d66eeSJonas Devlieghere     : CommandObjectMultiword(
560973d66eeSJonas Devlieghere           interpreter, "reproducer",
561c8dfe907SJonas Devlieghere           "Commands for manipulating reproducers. Reproducers make it "
562c8dfe907SJonas Devlieghere           "possible "
56364b7d955SJonas Devlieghere           "to capture full debug sessions with all its dependencies. The "
56464b7d955SJonas Devlieghere           "resulting reproducer is used to replay the debug session while "
56564b7d955SJonas Devlieghere           "debugging the debugger.\n"
56664b7d955SJonas Devlieghere           "Because reproducers need the whole the debug session from "
56764b7d955SJonas Devlieghere           "beginning to end, you need to launch the debugger in capture or "
56864b7d955SJonas Devlieghere           "replay mode, commonly though the command line driver.\n"
56964b7d955SJonas Devlieghere           "Reproducers are unrelated record-replay debugging, as you cannot "
57064b7d955SJonas Devlieghere           "interact with the debugger during replay.\n",
571130ec068SJonas Devlieghere           "reproducer <subcommand> [<subcommand-options>]") {
5729e046f02SJonas Devlieghere   LoadSubCommand(
5739e046f02SJonas Devlieghere       "generate",
5749e046f02SJonas Devlieghere       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
57515eacd74SJonas Devlieghere   LoadSubCommand("status", CommandObjectSP(
57615eacd74SJonas Devlieghere                                new CommandObjectReproducerStatus(interpreter)));
57797fc8eb4SJonas Devlieghere   LoadSubCommand("dump",
57897fc8eb4SJonas Devlieghere                  CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
579c8dfe907SJonas Devlieghere   LoadSubCommand("xcrash", CommandObjectSP(
580c8dfe907SJonas Devlieghere                                new CommandObjectReproducerXCrash(interpreter)));
5819e046f02SJonas Devlieghere }
5829e046f02SJonas Devlieghere 
5839e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default;
584