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"
14*7ced9fffSJonas Devlieghere #include "lldb/Interpreter/CommandOptionArgumentTable.h"
159e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h"
169e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h"
172451cbf0SJonas Devlieghere #include "lldb/Utility/GDBRemote.h"
182451cbf0SJonas Devlieghere #include "lldb/Utility/ProcessInfo.h"
192451cbf0SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
209e046f02SJonas Devlieghere 
21c8dfe907SJonas Devlieghere #include <csignal>
22c8dfe907SJonas Devlieghere 
239e046f02SJonas Devlieghere using namespace lldb;
2497fc8eb4SJonas Devlieghere using namespace llvm;
259e046f02SJonas Devlieghere using namespace lldb_private;
2697fc8eb4SJonas Devlieghere using namespace lldb_private::repro;
2797fc8eb4SJonas Devlieghere 
2836eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump
2997fc8eb4SJonas Devlieghere #include "CommandOptions.inc"
309e046f02SJonas Devlieghere 
31c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash
32c8dfe907SJonas Devlieghere #include "CommandOptions.inc"
33c8dfe907SJonas Devlieghere 
3437469061SJonas Devlieghere #define LLDB_OPTIONS_reproducer_verify
3537469061SJonas Devlieghere #include "CommandOptions.inc"
3637469061SJonas Devlieghere 
372451cbf0SJonas Devlieghere template <typename T>
ReadFromYAML(StringRef filename)382451cbf0SJonas Devlieghere llvm::Expected<T> static ReadFromYAML(StringRef filename) {
392451cbf0SJonas Devlieghere   auto error_or_file = MemoryBuffer::getFile(filename);
402451cbf0SJonas Devlieghere   if (auto err = error_or_file.getError()) {
412451cbf0SJonas Devlieghere     return errorCodeToError(err);
422451cbf0SJonas Devlieghere   }
432451cbf0SJonas Devlieghere 
442451cbf0SJonas Devlieghere   T t;
452451cbf0SJonas Devlieghere   yaml::Input yin((*error_or_file)->getBuffer());
462451cbf0SJonas Devlieghere   yin >> t;
472451cbf0SJonas Devlieghere 
482451cbf0SJonas Devlieghere   if (auto err = yin.error()) {
492451cbf0SJonas Devlieghere     return errorCodeToError(err);
502451cbf0SJonas Devlieghere   }
512451cbf0SJonas Devlieghere 
522451cbf0SJonas Devlieghere   return t;
532451cbf0SJonas Devlieghere }
542451cbf0SJonas Devlieghere 
SetError(CommandReturnObject & result,Error err)5537469061SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) {
56a8dd7094SDavid Spickett   result.AppendError(toString(std::move(err)));
5737469061SJonas Devlieghere }
5837469061SJonas Devlieghere 
5937469061SJonas Devlieghere /// Create a loader from the given path if specified. Otherwise use the current
6037469061SJonas Devlieghere /// loader used for replay.
6137469061SJonas Devlieghere static Loader *
GetLoaderFromPathOrCurrent(llvm::Optional<Loader> & loader_storage,CommandReturnObject & result,FileSpec reproducer_path)6237469061SJonas Devlieghere GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage,
6337469061SJonas Devlieghere                            CommandReturnObject &result,
6437469061SJonas Devlieghere                            FileSpec reproducer_path) {
6537469061SJonas Devlieghere   if (reproducer_path) {
6637469061SJonas Devlieghere     loader_storage.emplace(reproducer_path);
6737469061SJonas Devlieghere     Loader *loader = &(*loader_storage);
6837469061SJonas Devlieghere     if (Error err = loader->LoadIndex()) {
6937469061SJonas Devlieghere       // This is a hard error and will set the result to eReturnStatusFailed.
7037469061SJonas Devlieghere       SetError(result, std::move(err));
7137469061SJonas Devlieghere       return nullptr;
7237469061SJonas Devlieghere     }
7337469061SJonas Devlieghere     return loader;
7437469061SJonas Devlieghere   }
7537469061SJonas Devlieghere 
7637469061SJonas Devlieghere   if (Loader *loader = Reproducer::Instance().GetLoader())
7737469061SJonas Devlieghere     return loader;
7837469061SJonas Devlieghere 
7937469061SJonas Devlieghere   // This is a soft error because this is expected to fail during capture.
801b1c8e4aSDavid Spickett   result.AppendError(
811b1c8e4aSDavid Spickett       "Not specifying a reproducer is only support during replay.");
8237469061SJonas Devlieghere   result.SetStatus(eReturnStatusSuccessFinishNoResult);
8337469061SJonas Devlieghere   return nullptr;
8437469061SJonas Devlieghere }
8537469061SJonas Devlieghere 
869e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed {
879e046f02SJonas Devlieghere public:
CommandObjectReproducerGenerate(CommandInterpreter & interpreter)889e046f02SJonas Devlieghere   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
89973d66eeSJonas Devlieghere       : CommandObjectParsed(
90973d66eeSJonas Devlieghere             interpreter, "reproducer generate",
91973d66eeSJonas Devlieghere             "Generate reproducer on disk. When the debugger is in capture "
92973d66eeSJonas Devlieghere             "mode, this command will output the reproducer to a directory on "
930cf86da1SJonas Devlieghere             "disk and quit. In replay mode this command in a no-op.",
94973d66eeSJonas Devlieghere             nullptr) {}
959e046f02SJonas Devlieghere 
969e046f02SJonas Devlieghere   ~CommandObjectReproducerGenerate() override = default;
979e046f02SJonas Devlieghere 
989e046f02SJonas Devlieghere protected:
DoExecute(Args & command,CommandReturnObject & result)999e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
10097fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
1019e046f02SJonas Devlieghere     if (auto generator = r.GetGenerator()) {
1029e046f02SJonas Devlieghere       generator->Keep();
1039e046f02SJonas Devlieghere     } else {
1049e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer generator");
1059e046f02SJonas Devlieghere       return false;
1069e046f02SJonas Devlieghere     }
1079e046f02SJonas Devlieghere 
1089e046f02SJonas Devlieghere     result.GetOutputStream()
1099e046f02SJonas Devlieghere         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
1101c5250abSJonas Devlieghere     result.GetOutputStream()
1111c5250abSJonas Devlieghere         << "Please have a look at the directory to assess if you're willing to "
1121c5250abSJonas Devlieghere            "share the contained information.\n";
1139e046f02SJonas Devlieghere 
1140cf86da1SJonas Devlieghere     m_interpreter.BroadcastEvent(
1150cf86da1SJonas Devlieghere         CommandInterpreter::eBroadcastBitQuitCommandReceived);
1160cf86da1SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
1179e046f02SJonas Devlieghere     return result.Succeeded();
1189e046f02SJonas Devlieghere   }
1199e046f02SJonas Devlieghere };
1209e046f02SJonas Devlieghere 
121c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed {
122c8dfe907SJonas Devlieghere public:
CommandObjectReproducerXCrash(CommandInterpreter & interpreter)123c8dfe907SJonas Devlieghere   CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
124c8dfe907SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer xcrash",
125c8dfe907SJonas Devlieghere                             "Intentionally force  the debugger to crash in "
126c8dfe907SJonas Devlieghere                             "order to trigger and test reproducer generation.",
127c8dfe907SJonas Devlieghere                             nullptr) {}
128c8dfe907SJonas Devlieghere 
129c8dfe907SJonas Devlieghere   ~CommandObjectReproducerXCrash() override = default;
130c8dfe907SJonas Devlieghere 
GetOptions()131c8dfe907SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
132c8dfe907SJonas Devlieghere 
133c8dfe907SJonas Devlieghere   class CommandOptions : public Options {
134c8dfe907SJonas Devlieghere   public:
13524f9a2f5SShafik Yaghmour     CommandOptions() = default;
136c8dfe907SJonas Devlieghere 
137c8dfe907SJonas Devlieghere     ~CommandOptions() override = default;
138c8dfe907SJonas Devlieghere 
SetOptionValue(uint32_t option_idx,StringRef option_arg,ExecutionContext * execution_context)139c8dfe907SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
140c8dfe907SJonas Devlieghere                           ExecutionContext *execution_context) override {
141c8dfe907SJonas Devlieghere       Status error;
142c8dfe907SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
143c8dfe907SJonas Devlieghere 
144c8dfe907SJonas Devlieghere       switch (short_option) {
145c8dfe907SJonas Devlieghere       case 's':
146c8dfe907SJonas Devlieghere         signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
147c8dfe907SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
148c8dfe907SJonas Devlieghere         if (!error.Success())
149c8dfe907SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
150c8dfe907SJonas Devlieghere                                          option_arg.str().c_str());
151c8dfe907SJonas Devlieghere         break;
152c8dfe907SJonas Devlieghere       default:
153c8dfe907SJonas Devlieghere         llvm_unreachable("Unimplemented option");
154c8dfe907SJonas Devlieghere       }
155c8dfe907SJonas Devlieghere 
156c8dfe907SJonas Devlieghere       return error;
157c8dfe907SJonas Devlieghere     }
158c8dfe907SJonas Devlieghere 
OptionParsingStarting(ExecutionContext * execution_context)159c8dfe907SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
160c8dfe907SJonas Devlieghere       signal = eReproducerCrashSigsegv;
161c8dfe907SJonas Devlieghere     }
162c8dfe907SJonas Devlieghere 
GetDefinitions()163c8dfe907SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
164c8dfe907SJonas Devlieghere       return makeArrayRef(g_reproducer_xcrash_options);
165c8dfe907SJonas Devlieghere     }
166c8dfe907SJonas Devlieghere 
167c8dfe907SJonas Devlieghere     ReproducerCrashSignal signal = eReproducerCrashSigsegv;
168c8dfe907SJonas Devlieghere   };
169c8dfe907SJonas Devlieghere 
170c8dfe907SJonas Devlieghere protected:
DoExecute(Args & command,CommandReturnObject & result)171c8dfe907SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
172c8dfe907SJonas Devlieghere     auto &r = Reproducer::Instance();
173bb090bb1SJonas Devlieghere 
174fa126069SJonas Devlieghere     if (!r.IsCapturing()) {
1751b1c8e4aSDavid Spickett       result.AppendError(
176c8dfe907SJonas Devlieghere           "forcing a crash is only supported when capturing a reproducer.");
177c8dfe907SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
178c8dfe907SJonas Devlieghere       return false;
179c8dfe907SJonas Devlieghere     }
180c8dfe907SJonas Devlieghere 
181c8dfe907SJonas Devlieghere     switch (m_options.signal) {
182c8dfe907SJonas Devlieghere     case eReproducerCrashSigill:
183c8dfe907SJonas Devlieghere       std::raise(SIGILL);
184c8dfe907SJonas Devlieghere       break;
185c8dfe907SJonas Devlieghere     case eReproducerCrashSigsegv:
186c8dfe907SJonas Devlieghere       std::raise(SIGSEGV);
187c8dfe907SJonas Devlieghere       break;
188c8dfe907SJonas Devlieghere     }
189c8dfe907SJonas Devlieghere 
190c8dfe907SJonas Devlieghere     result.SetStatus(eReturnStatusQuit);
191c8dfe907SJonas Devlieghere     return result.Succeeded();
192c8dfe907SJonas Devlieghere   }
193c8dfe907SJonas Devlieghere 
194c8dfe907SJonas Devlieghere private:
195c8dfe907SJonas Devlieghere   CommandOptions m_options;
196c8dfe907SJonas Devlieghere };
197c8dfe907SJonas Devlieghere 
19815eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed {
1999e046f02SJonas Devlieghere public:
CommandObjectReproducerStatus(CommandInterpreter & interpreter)20015eacd74SJonas Devlieghere   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
201973d66eeSJonas Devlieghere       : CommandObjectParsed(
202973d66eeSJonas Devlieghere             interpreter, "reproducer status",
203c8dfe907SJonas Devlieghere             "Show the current reproducer status. In capture mode the "
204c8dfe907SJonas Devlieghere             "debugger "
205973d66eeSJonas Devlieghere             "is collecting all the information it needs to create a "
206973d66eeSJonas Devlieghere             "reproducer.  In replay mode the reproducer is replaying a "
207973d66eeSJonas Devlieghere             "reproducer. When the reproducers are off, no data is collected "
208973d66eeSJonas Devlieghere             "and no reproducer can be generated.",
209973d66eeSJonas Devlieghere             nullptr) {}
2109e046f02SJonas Devlieghere 
21115eacd74SJonas Devlieghere   ~CommandObjectReproducerStatus() override = default;
2129e046f02SJonas Devlieghere 
2139e046f02SJonas Devlieghere protected:
DoExecute(Args & command,CommandReturnObject & result)2149e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
21597fc8eb4SJonas Devlieghere     auto &r = Reproducer::Instance();
216865cd093SJonas Devlieghere     if (r.IsCapturing()) {
21715eacd74SJonas Devlieghere       result.GetOutputStream() << "Reproducer is in capture mode.\n";
218982a77b6SJonas Devlieghere       result.GetOutputStream()
219982a77b6SJonas Devlieghere           << "Path: " << r.GetReproducerPath().GetPath() << '\n';
220fa126069SJonas Devlieghere     } else {
221fa126069SJonas Devlieghere       result.GetOutputStream() << "Reproducer is off.\n";
222982a77b6SJonas Devlieghere     }
223982a77b6SJonas Devlieghere 
224982a77b6SJonas Devlieghere     // Auto generate is hidden unless enabled because this is mostly for
225982a77b6SJonas Devlieghere     // development and testing.
226982a77b6SJonas Devlieghere     if (Generator *g = r.GetGenerator()) {
227982a77b6SJonas Devlieghere       if (g->IsAutoGenerate())
228982a77b6SJonas Devlieghere         result.GetOutputStream() << "Auto generate: on\n";
229982a77b6SJonas Devlieghere     }
230982a77b6SJonas Devlieghere 
23115eacd74SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishResult);
2329e046f02SJonas Devlieghere     return result.Succeeded();
2339e046f02SJonas Devlieghere   }
2349e046f02SJonas Devlieghere };
2359e046f02SJonas Devlieghere 
23697fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed {
23797fc8eb4SJonas Devlieghere public:
CommandObjectReproducerDump(CommandInterpreter & interpreter)23897fc8eb4SJonas Devlieghere   CommandObjectReproducerDump(CommandInterpreter &interpreter)
23997fc8eb4SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer dump",
24064b7d955SJonas Devlieghere                             "Dump the information contained in a reproducer. "
24164b7d955SJonas Devlieghere                             "If no reproducer is specified during replay, it "
24264b7d955SJonas Devlieghere                             "dumps the content of the current reproducer.",
24397fc8eb4SJonas Devlieghere                             nullptr) {}
24497fc8eb4SJonas Devlieghere 
24597fc8eb4SJonas Devlieghere   ~CommandObjectReproducerDump() override = default;
24697fc8eb4SJonas Devlieghere 
GetOptions()24797fc8eb4SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
24897fc8eb4SJonas Devlieghere 
24997fc8eb4SJonas Devlieghere   class CommandOptions : public Options {
25097fc8eb4SJonas Devlieghere   public:
25124f9a2f5SShafik Yaghmour     CommandOptions() = default;
25297fc8eb4SJonas Devlieghere 
25397fc8eb4SJonas Devlieghere     ~CommandOptions() override = default;
25497fc8eb4SJonas Devlieghere 
SetOptionValue(uint32_t option_idx,StringRef option_arg,ExecutionContext * execution_context)25597fc8eb4SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
25697fc8eb4SJonas Devlieghere                           ExecutionContext *execution_context) override {
25797fc8eb4SJonas Devlieghere       Status error;
25897fc8eb4SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
25997fc8eb4SJonas Devlieghere 
26097fc8eb4SJonas Devlieghere       switch (short_option) {
26197fc8eb4SJonas Devlieghere       case 'f':
26297fc8eb4SJonas Devlieghere         file.SetFile(option_arg, FileSpec::Style::native);
26397fc8eb4SJonas Devlieghere         FileSystem::Instance().Resolve(file);
26497fc8eb4SJonas Devlieghere         break;
26597fc8eb4SJonas Devlieghere       case 'p':
26697fc8eb4SJonas Devlieghere         provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
26797fc8eb4SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
26897fc8eb4SJonas Devlieghere         if (!error.Success())
26997fc8eb4SJonas Devlieghere           error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
27097fc8eb4SJonas Devlieghere                                          option_arg.str().c_str());
27197fc8eb4SJonas Devlieghere         break;
27297fc8eb4SJonas Devlieghere       default:
27397fc8eb4SJonas Devlieghere         llvm_unreachable("Unimplemented option");
27497fc8eb4SJonas Devlieghere       }
27597fc8eb4SJonas Devlieghere 
27697fc8eb4SJonas Devlieghere       return error;
27797fc8eb4SJonas Devlieghere     }
27897fc8eb4SJonas Devlieghere 
OptionParsingStarting(ExecutionContext * execution_context)27997fc8eb4SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
28097fc8eb4SJonas Devlieghere       file.Clear();
28197fc8eb4SJonas Devlieghere       provider = eReproducerProviderNone;
28297fc8eb4SJonas Devlieghere     }
28397fc8eb4SJonas Devlieghere 
GetDefinitions()28497fc8eb4SJonas Devlieghere     ArrayRef<OptionDefinition> GetDefinitions() override {
28536eea5c3SJonas Devlieghere       return makeArrayRef(g_reproducer_dump_options);
28697fc8eb4SJonas Devlieghere     }
28797fc8eb4SJonas Devlieghere 
28897fc8eb4SJonas Devlieghere     FileSpec file;
28997fc8eb4SJonas Devlieghere     ReproducerProvider provider = eReproducerProviderNone;
29097fc8eb4SJonas Devlieghere   };
29197fc8eb4SJonas Devlieghere 
29297fc8eb4SJonas Devlieghere protected:
DoExecute(Args & command,CommandReturnObject & result)29397fc8eb4SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
29497fc8eb4SJonas Devlieghere     llvm::Optional<Loader> loader_storage;
29537469061SJonas Devlieghere     Loader *loader =
29637469061SJonas Devlieghere         GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
29737469061SJonas Devlieghere     if (!loader)
29897fc8eb4SJonas Devlieghere       return false;
29997fc8eb4SJonas Devlieghere 
30097fc8eb4SJonas Devlieghere     switch (m_options.provider) {
30197fc8eb4SJonas Devlieghere     case eReproducerProviderFiles: {
30297fc8eb4SJonas Devlieghere       FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
30397fc8eb4SJonas Devlieghere 
30497fc8eb4SJonas Devlieghere       // Read the VFS mapping.
30597fc8eb4SJonas Devlieghere       ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
30697fc8eb4SJonas Devlieghere           vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
30797fc8eb4SJonas Devlieghere       if (!buffer) {
30897fc8eb4SJonas Devlieghere         SetError(result, errorCodeToError(buffer.getError()));
30997fc8eb4SJonas Devlieghere         return false;
31097fc8eb4SJonas Devlieghere       }
31197fc8eb4SJonas Devlieghere 
31297fc8eb4SJonas Devlieghere       // Initialize a VFS from the given mapping.
31397fc8eb4SJonas Devlieghere       IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
31497fc8eb4SJonas Devlieghere           std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
31597fc8eb4SJonas Devlieghere 
31697fc8eb4SJonas Devlieghere       // Dump the VFS to a buffer.
31797fc8eb4SJonas Devlieghere       std::string str;
31897fc8eb4SJonas Devlieghere       raw_string_ostream os(str);
319cc63ae42SBen Barham       static_cast<vfs::RedirectingFileSystem &>(*vfs).print(os);
32097fc8eb4SJonas Devlieghere       os.flush();
32197fc8eb4SJonas Devlieghere 
32297fc8eb4SJonas Devlieghere       // Return the string.
32397fc8eb4SJonas Devlieghere       result.AppendMessage(str);
32497fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
32597fc8eb4SJonas Devlieghere       return true;
32697fc8eb4SJonas Devlieghere     }
327a842950bSJonas Devlieghere     case eReproducerProviderSymbolFiles: {
328a842950bSJonas Devlieghere       Expected<std::string> symbol_files =
329a842950bSJonas Devlieghere           loader->LoadBuffer<SymbolFileProvider>();
330a842950bSJonas Devlieghere       if (!symbol_files) {
331a842950bSJonas Devlieghere         SetError(result, symbol_files.takeError());
332a842950bSJonas Devlieghere         return false;
333a842950bSJonas Devlieghere       }
334a842950bSJonas Devlieghere 
335a842950bSJonas Devlieghere       std::vector<SymbolFileProvider::Entry> entries;
336a842950bSJonas Devlieghere       llvm::yaml::Input yin(*symbol_files);
337a842950bSJonas Devlieghere       yin >> entries;
338a842950bSJonas Devlieghere 
339a842950bSJonas Devlieghere       for (const auto &entry : entries) {
340a842950bSJonas Devlieghere         result.AppendMessageWithFormat("- uuid:        %s\n",
341a842950bSJonas Devlieghere                                        entry.uuid.c_str());
342a842950bSJonas Devlieghere         result.AppendMessageWithFormat("  module path: %s\n",
343a842950bSJonas Devlieghere                                        entry.module_path.c_str());
344a842950bSJonas Devlieghere         result.AppendMessageWithFormat("  symbol path: %s\n",
345a842950bSJonas Devlieghere                                        entry.symbol_path.c_str());
346a842950bSJonas Devlieghere       }
347a842950bSJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
348a842950bSJonas Devlieghere       return true;
349a842950bSJonas Devlieghere     }
35097fc8eb4SJonas Devlieghere     case eReproducerProviderVersion: {
351b2575da9SJonas Devlieghere       Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
352b2575da9SJonas Devlieghere       if (!version) {
353b2575da9SJonas Devlieghere         SetError(result, version.takeError());
35497fc8eb4SJonas Devlieghere         return false;
35597fc8eb4SJonas Devlieghere       }
356b2575da9SJonas Devlieghere       result.AppendMessage(*version);
35797fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
35897fc8eb4SJonas Devlieghere       return true;
35997fc8eb4SJonas Devlieghere     }
360f4f12012SJonas Devlieghere     case eReproducerProviderWorkingDirectory: {
361f4f12012SJonas Devlieghere       Expected<std::string> cwd =
36273af341bSJonas Devlieghere           repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
363f4f12012SJonas Devlieghere       if (!cwd) {
364f4f12012SJonas Devlieghere         SetError(result, cwd.takeError());
365f4f12012SJonas Devlieghere         return false;
366f4f12012SJonas Devlieghere       }
367f4f12012SJonas Devlieghere       result.AppendMessage(*cwd);
368f4f12012SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
369f4f12012SJonas Devlieghere       return true;
370f4f12012SJonas Devlieghere     }
37173af341bSJonas Devlieghere     case eReproducerProviderHomeDirectory: {
37273af341bSJonas Devlieghere       Expected<std::string> home =
37373af341bSJonas Devlieghere           repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
37473af341bSJonas Devlieghere       if (!home) {
37573af341bSJonas Devlieghere         SetError(result, home.takeError());
37673af341bSJonas Devlieghere         return false;
37773af341bSJonas Devlieghere       }
37873af341bSJonas Devlieghere       result.AppendMessage(*home);
37973af341bSJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
38073af341bSJonas Devlieghere       return true;
38173af341bSJonas Devlieghere     }
38297fc8eb4SJonas Devlieghere     case eReproducerProviderCommands: {
3831d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
3841d41d1bcSEric Christopher           repro::MultiLoader<repro::CommandProvider>::Create(loader);
3851d41d1bcSEric Christopher       if (!multi_loader) {
38697fc8eb4SJonas Devlieghere         SetError(result,
3874016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create command loader.",
3884016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
38997fc8eb4SJonas Devlieghere         return false;
39097fc8eb4SJonas Devlieghere       }
39197fc8eb4SJonas Devlieghere 
39297fc8eb4SJonas Devlieghere       // Iterate over the command files and dump them.
3931d41d1bcSEric Christopher       llvm::Optional<std::string> command_file;
3941d41d1bcSEric Christopher       while ((command_file = multi_loader->GetNextFile())) {
39597fc8eb4SJonas Devlieghere         if (!command_file)
39697fc8eb4SJonas Devlieghere           break;
39797fc8eb4SJonas Devlieghere 
39897fc8eb4SJonas Devlieghere         auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
39997fc8eb4SJonas Devlieghere         if (auto err = command_buffer.getError()) {
40097fc8eb4SJonas Devlieghere           SetError(result, errorCodeToError(err));
40197fc8eb4SJonas Devlieghere           return false;
40297fc8eb4SJonas Devlieghere         }
40397fc8eb4SJonas Devlieghere         result.AppendMessage((*command_buffer)->getBuffer());
40497fc8eb4SJonas Devlieghere       }
40597fc8eb4SJonas Devlieghere 
40697fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
40797fc8eb4SJonas Devlieghere       return true;
40897fc8eb4SJonas Devlieghere     }
40997fc8eb4SJonas Devlieghere     case eReproducerProviderGDB: {
4101d41d1bcSEric Christopher       std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
4111d41d1bcSEric Christopher           multi_loader =
4121d41d1bcSEric Christopher               repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
4134016c6b0SJonas Devlieghere 
4144016c6b0SJonas Devlieghere       if (!multi_loader) {
4154016c6b0SJonas Devlieghere         SetError(result,
4164016c6b0SJonas Devlieghere                  make_error<StringError>("Unable to create GDB loader.",
4174016c6b0SJonas Devlieghere                                          llvm::inconvertibleErrorCode()));
4184016c6b0SJonas Devlieghere         return false;
4194016c6b0SJonas Devlieghere       }
4204016c6b0SJonas Devlieghere 
4211d41d1bcSEric Christopher       llvm::Optional<std::string> gdb_file;
4221d41d1bcSEric Christopher       while ((gdb_file = multi_loader->GetNextFile())) {
4232451cbf0SJonas Devlieghere         if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
4242451cbf0SJonas Devlieghere                 ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
4252451cbf0SJonas Devlieghere           for (GDBRemotePacket &packet : *packets) {
4268fc8d3feSJonas Devlieghere             packet.Dump(result.GetOutputStream());
4278fc8d3feSJonas Devlieghere           }
4282451cbf0SJonas Devlieghere         } else {
4292451cbf0SJonas Devlieghere           SetError(result, packets.takeError());
4302451cbf0SJonas Devlieghere           return false;
4312451cbf0SJonas Devlieghere         }
4322451cbf0SJonas Devlieghere       }
4332451cbf0SJonas Devlieghere 
4342451cbf0SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
4352451cbf0SJonas Devlieghere       return true;
4362451cbf0SJonas Devlieghere     }
4372451cbf0SJonas Devlieghere     case eReproducerProviderProcessInfo: {
4382451cbf0SJonas Devlieghere       std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
4392451cbf0SJonas Devlieghere           multi_loader =
4402451cbf0SJonas Devlieghere               repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
4412451cbf0SJonas Devlieghere 
4422451cbf0SJonas Devlieghere       if (!multi_loader) {
4432451cbf0SJonas Devlieghere         SetError(result, make_error<StringError>(
4442451cbf0SJonas Devlieghere                              llvm::inconvertibleErrorCode(),
4452451cbf0SJonas Devlieghere                              "Unable to create process info loader."));
4462451cbf0SJonas Devlieghere         return false;
4472451cbf0SJonas Devlieghere       }
4482451cbf0SJonas Devlieghere 
4492451cbf0SJonas Devlieghere       llvm::Optional<std::string> process_file;
4502451cbf0SJonas Devlieghere       while ((process_file = multi_loader->GetNextFile())) {
4512451cbf0SJonas Devlieghere         if (llvm::Expected<ProcessInstanceInfoList> infos =
4522451cbf0SJonas Devlieghere                 ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
4532451cbf0SJonas Devlieghere           for (ProcessInstanceInfo info : *infos)
4542451cbf0SJonas Devlieghere             info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
4552451cbf0SJonas Devlieghere         } else {
4562451cbf0SJonas Devlieghere           SetError(result, infos.takeError());
4572451cbf0SJonas Devlieghere           return false;
4582451cbf0SJonas Devlieghere         }
4591d41d1bcSEric Christopher       }
4608fc8d3feSJonas Devlieghere 
46197fc8eb4SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishResult);
46297fc8eb4SJonas Devlieghere       return true;
46397fc8eb4SJonas Devlieghere     }
46497fc8eb4SJonas Devlieghere     case eReproducerProviderNone:
4651b1c8e4aSDavid Spickett       result.AppendError("No valid provider specified.");
46697fc8eb4SJonas Devlieghere       return false;
46797fc8eb4SJonas Devlieghere     }
46897fc8eb4SJonas Devlieghere 
46997fc8eb4SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
47097fc8eb4SJonas Devlieghere     return result.Succeeded();
47197fc8eb4SJonas Devlieghere   }
47297fc8eb4SJonas Devlieghere 
47397fc8eb4SJonas Devlieghere private:
47497fc8eb4SJonas Devlieghere   CommandOptions m_options;
47597fc8eb4SJonas Devlieghere };
47697fc8eb4SJonas Devlieghere 
CommandObjectReproducer(CommandInterpreter & interpreter)4779e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer(
4789e046f02SJonas Devlieghere     CommandInterpreter &interpreter)
479973d66eeSJonas Devlieghere     : CommandObjectMultiword(
480973d66eeSJonas Devlieghere           interpreter, "reproducer",
481c8dfe907SJonas Devlieghere           "Commands for manipulating reproducers. Reproducers make it "
482c8dfe907SJonas Devlieghere           "possible "
48364b7d955SJonas Devlieghere           "to capture full debug sessions with all its dependencies. The "
48464b7d955SJonas Devlieghere           "resulting reproducer is used to replay the debug session while "
48564b7d955SJonas Devlieghere           "debugging the debugger.\n"
48664b7d955SJonas Devlieghere           "Because reproducers need the whole the debug session from "
48764b7d955SJonas Devlieghere           "beginning to end, you need to launch the debugger in capture or "
48864b7d955SJonas Devlieghere           "replay mode, commonly though the command line driver.\n"
48964b7d955SJonas Devlieghere           "Reproducers are unrelated record-replay debugging, as you cannot "
49064b7d955SJonas Devlieghere           "interact with the debugger during replay.\n",
491130ec068SJonas Devlieghere           "reproducer <subcommand> [<subcommand-options>]") {
4929e046f02SJonas Devlieghere   LoadSubCommand(
4939e046f02SJonas Devlieghere       "generate",
4949e046f02SJonas Devlieghere       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
49515eacd74SJonas Devlieghere   LoadSubCommand("status", CommandObjectSP(
49615eacd74SJonas Devlieghere                                new CommandObjectReproducerStatus(interpreter)));
49797fc8eb4SJonas Devlieghere   LoadSubCommand("dump",
49897fc8eb4SJonas Devlieghere                  CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
499c8dfe907SJonas Devlieghere   LoadSubCommand("xcrash", CommandObjectSP(
500c8dfe907SJonas Devlieghere                                new CommandObjectReproducerXCrash(interpreter)));
5019e046f02SJonas Devlieghere }
5029e046f02SJonas Devlieghere 
5039e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default;
504