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