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