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 11*2451cbf0SJonas Devlieghere #include "lldb/Host/HostInfo.h" 1297fc8eb4SJonas Devlieghere #include "lldb/Host/OptionParser.h" 13df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 149e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 159e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h" 16*2451cbf0SJonas Devlieghere #include "lldb/Utility/GDBRemote.h" 17*2451cbf0SJonas Devlieghere #include "lldb/Utility/ProcessInfo.h" 18*2451cbf0SJonas Devlieghere #include "lldb/Utility/Reproducer.h" 199e046f02SJonas Devlieghere 20c8dfe907SJonas Devlieghere #include <csignal> 21c8dfe907SJonas Devlieghere 229e046f02SJonas Devlieghere using namespace lldb; 2397fc8eb4SJonas Devlieghere using namespace llvm; 249e046f02SJonas Devlieghere using namespace lldb_private; 2597fc8eb4SJonas Devlieghere using namespace lldb_private::repro; 2697fc8eb4SJonas Devlieghere 2797fc8eb4SJonas Devlieghere enum ReproducerProvider { 2897fc8eb4SJonas Devlieghere eReproducerProviderCommands, 2997fc8eb4SJonas Devlieghere eReproducerProviderFiles, 3097fc8eb4SJonas Devlieghere eReproducerProviderGDB, 31*2451cbf0SJonas Devlieghere eReproducerProviderProcessInfo, 3297fc8eb4SJonas Devlieghere eReproducerProviderVersion, 33f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 3497fc8eb4SJonas Devlieghere eReproducerProviderNone 3597fc8eb4SJonas Devlieghere }; 3697fc8eb4SJonas Devlieghere 3797fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { 3897fc8eb4SJonas Devlieghere { 3997fc8eb4SJonas Devlieghere eReproducerProviderCommands, 4097fc8eb4SJonas Devlieghere "commands", 4197fc8eb4SJonas Devlieghere "Command Interpreter Commands", 4297fc8eb4SJonas Devlieghere }, 4397fc8eb4SJonas Devlieghere { 4497fc8eb4SJonas Devlieghere eReproducerProviderFiles, 4597fc8eb4SJonas Devlieghere "files", 4697fc8eb4SJonas Devlieghere "Files", 4797fc8eb4SJonas Devlieghere }, 4897fc8eb4SJonas Devlieghere { 4997fc8eb4SJonas Devlieghere eReproducerProviderGDB, 5097fc8eb4SJonas Devlieghere "gdb", 5197fc8eb4SJonas Devlieghere "GDB Remote Packets", 5297fc8eb4SJonas Devlieghere }, 5397fc8eb4SJonas Devlieghere { 54*2451cbf0SJonas Devlieghere eReproducerProviderProcessInfo, 55*2451cbf0SJonas Devlieghere "processes", 56*2451cbf0SJonas Devlieghere "Process Info", 57*2451cbf0SJonas Devlieghere }, 58*2451cbf0SJonas Devlieghere { 5997fc8eb4SJonas Devlieghere eReproducerProviderVersion, 6097fc8eb4SJonas Devlieghere "version", 6197fc8eb4SJonas Devlieghere "Version", 6297fc8eb4SJonas Devlieghere }, 6397fc8eb4SJonas Devlieghere { 64f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 65f4f12012SJonas Devlieghere "cwd", 66f4f12012SJonas Devlieghere "Working Directory", 67f4f12012SJonas Devlieghere }, 68f4f12012SJonas Devlieghere { 6997fc8eb4SJonas Devlieghere eReproducerProviderNone, 7097fc8eb4SJonas Devlieghere "none", 7197fc8eb4SJonas Devlieghere "None", 7297fc8eb4SJonas Devlieghere }, 7397fc8eb4SJonas Devlieghere }; 7497fc8eb4SJonas Devlieghere 7597fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() { 7697fc8eb4SJonas Devlieghere return OptionEnumValues(g_reproducer_provider_type); 7797fc8eb4SJonas Devlieghere } 7897fc8eb4SJonas Devlieghere 7936eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump 8097fc8eb4SJonas Devlieghere #include "CommandOptions.inc" 819e046f02SJonas Devlieghere 82c8dfe907SJonas Devlieghere enum ReproducerCrashSignal { 83c8dfe907SJonas Devlieghere eReproducerCrashSigill, 84c8dfe907SJonas Devlieghere eReproducerCrashSigsegv, 85c8dfe907SJonas Devlieghere }; 86c8dfe907SJonas Devlieghere 87c8dfe907SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_signaltype[] = { 88c8dfe907SJonas Devlieghere { 89c8dfe907SJonas Devlieghere eReproducerCrashSigill, 90c8dfe907SJonas Devlieghere "SIGILL", 91c8dfe907SJonas Devlieghere "Illegal instruction", 92c8dfe907SJonas Devlieghere }, 93c8dfe907SJonas Devlieghere { 94c8dfe907SJonas Devlieghere eReproducerCrashSigsegv, 95c8dfe907SJonas Devlieghere "SIGSEGV", 96c8dfe907SJonas Devlieghere "Segmentation fault", 97c8dfe907SJonas Devlieghere }, 98c8dfe907SJonas Devlieghere }; 99c8dfe907SJonas Devlieghere 100c8dfe907SJonas Devlieghere static constexpr OptionEnumValues ReproducerSignalType() { 101c8dfe907SJonas Devlieghere return OptionEnumValues(g_reproducer_signaltype); 102c8dfe907SJonas Devlieghere } 103c8dfe907SJonas Devlieghere 104c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash 105c8dfe907SJonas Devlieghere #include "CommandOptions.inc" 106c8dfe907SJonas Devlieghere 107*2451cbf0SJonas Devlieghere template <typename T> 108*2451cbf0SJonas Devlieghere llvm::Expected<T> static ReadFromYAML(StringRef filename) { 109*2451cbf0SJonas Devlieghere auto error_or_file = MemoryBuffer::getFile(filename); 110*2451cbf0SJonas Devlieghere if (auto err = error_or_file.getError()) { 111*2451cbf0SJonas Devlieghere return errorCodeToError(err); 112*2451cbf0SJonas Devlieghere } 113*2451cbf0SJonas Devlieghere 114*2451cbf0SJonas Devlieghere T t; 115*2451cbf0SJonas Devlieghere yaml::Input yin((*error_or_file)->getBuffer()); 116*2451cbf0SJonas Devlieghere yin >> t; 117*2451cbf0SJonas Devlieghere 118*2451cbf0SJonas Devlieghere if (auto err = yin.error()) { 119*2451cbf0SJonas Devlieghere return errorCodeToError(err); 120*2451cbf0SJonas Devlieghere } 121*2451cbf0SJonas Devlieghere 122*2451cbf0SJonas Devlieghere return t; 123*2451cbf0SJonas Devlieghere } 124*2451cbf0SJonas Devlieghere 1259e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed { 1269e046f02SJonas Devlieghere public: 1279e046f02SJonas Devlieghere CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 128973d66eeSJonas Devlieghere : CommandObjectParsed( 129973d66eeSJonas Devlieghere interpreter, "reproducer generate", 130973d66eeSJonas Devlieghere "Generate reproducer on disk. When the debugger is in capture " 131973d66eeSJonas Devlieghere "mode, this command will output the reproducer to a directory on " 1320cf86da1SJonas Devlieghere "disk and quit. In replay mode this command in a no-op.", 133973d66eeSJonas Devlieghere nullptr) {} 1349e046f02SJonas Devlieghere 1359e046f02SJonas Devlieghere ~CommandObjectReproducerGenerate() override = default; 1369e046f02SJonas Devlieghere 1379e046f02SJonas Devlieghere protected: 1389e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 1399e046f02SJonas Devlieghere if (!command.empty()) { 1409e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 1419e046f02SJonas Devlieghere m_cmd_name.c_str()); 1429e046f02SJonas Devlieghere return false; 1439e046f02SJonas Devlieghere } 1449e046f02SJonas Devlieghere 14597fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 1469e046f02SJonas Devlieghere if (auto generator = r.GetGenerator()) { 1479e046f02SJonas Devlieghere generator->Keep(); 148865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 149bb090bb1SJonas Devlieghere // Make this operation a NO-OP in replay mode. 1502dca6538SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 1512dca6538SJonas Devlieghere return result.Succeeded(); 1529e046f02SJonas Devlieghere } else { 1539e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer generator"); 1542dca6538SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 1559e046f02SJonas Devlieghere return false; 1569e046f02SJonas Devlieghere } 1579e046f02SJonas Devlieghere 1589e046f02SJonas Devlieghere result.GetOutputStream() 1599e046f02SJonas Devlieghere << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 1601c5250abSJonas Devlieghere result.GetOutputStream() 1611c5250abSJonas Devlieghere << "Please have a look at the directory to assess if you're willing to " 1621c5250abSJonas Devlieghere "share the contained information.\n"; 1639e046f02SJonas Devlieghere 1640cf86da1SJonas Devlieghere m_interpreter.BroadcastEvent( 1650cf86da1SJonas Devlieghere CommandInterpreter::eBroadcastBitQuitCommandReceived); 1660cf86da1SJonas Devlieghere result.SetStatus(eReturnStatusQuit); 1679e046f02SJonas Devlieghere return result.Succeeded(); 1689e046f02SJonas Devlieghere } 1699e046f02SJonas Devlieghere }; 1709e046f02SJonas Devlieghere 171c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed { 172c8dfe907SJonas Devlieghere public: 173c8dfe907SJonas Devlieghere CommandObjectReproducerXCrash(CommandInterpreter &interpreter) 174c8dfe907SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer xcrash", 175c8dfe907SJonas Devlieghere "Intentionally force the debugger to crash in " 176c8dfe907SJonas Devlieghere "order to trigger and test reproducer generation.", 177c8dfe907SJonas Devlieghere nullptr) {} 178c8dfe907SJonas Devlieghere 179c8dfe907SJonas Devlieghere ~CommandObjectReproducerXCrash() override = default; 180c8dfe907SJonas Devlieghere 181c8dfe907SJonas Devlieghere Options *GetOptions() override { return &m_options; } 182c8dfe907SJonas Devlieghere 183c8dfe907SJonas Devlieghere class CommandOptions : public Options { 184c8dfe907SJonas Devlieghere public: 185c8dfe907SJonas Devlieghere CommandOptions() : Options() {} 186c8dfe907SJonas Devlieghere 187c8dfe907SJonas Devlieghere ~CommandOptions() override = default; 188c8dfe907SJonas Devlieghere 189c8dfe907SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 190c8dfe907SJonas Devlieghere ExecutionContext *execution_context) override { 191c8dfe907SJonas Devlieghere Status error; 192c8dfe907SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 193c8dfe907SJonas Devlieghere 194c8dfe907SJonas Devlieghere switch (short_option) { 195c8dfe907SJonas Devlieghere case 's': 196c8dfe907SJonas Devlieghere signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum( 197c8dfe907SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 198c8dfe907SJonas Devlieghere if (!error.Success()) 199c8dfe907SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for signal '%s'", 200c8dfe907SJonas Devlieghere option_arg.str().c_str()); 201c8dfe907SJonas Devlieghere break; 202c8dfe907SJonas Devlieghere default: 203c8dfe907SJonas Devlieghere llvm_unreachable("Unimplemented option"); 204c8dfe907SJonas Devlieghere } 205c8dfe907SJonas Devlieghere 206c8dfe907SJonas Devlieghere return error; 207c8dfe907SJonas Devlieghere } 208c8dfe907SJonas Devlieghere 209c8dfe907SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 210c8dfe907SJonas Devlieghere signal = eReproducerCrashSigsegv; 211c8dfe907SJonas Devlieghere } 212c8dfe907SJonas Devlieghere 213c8dfe907SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 214c8dfe907SJonas Devlieghere return makeArrayRef(g_reproducer_xcrash_options); 215c8dfe907SJonas Devlieghere } 216c8dfe907SJonas Devlieghere 217c8dfe907SJonas Devlieghere ReproducerCrashSignal signal = eReproducerCrashSigsegv; 218c8dfe907SJonas Devlieghere }; 219c8dfe907SJonas Devlieghere 220c8dfe907SJonas Devlieghere protected: 221c8dfe907SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 222c8dfe907SJonas Devlieghere if (!command.empty()) { 223c8dfe907SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 224c8dfe907SJonas Devlieghere m_cmd_name.c_str()); 225c8dfe907SJonas Devlieghere return false; 226c8dfe907SJonas Devlieghere } 227c8dfe907SJonas Devlieghere 228c8dfe907SJonas Devlieghere auto &r = Reproducer::Instance(); 229bb090bb1SJonas Devlieghere 230bb090bb1SJonas Devlieghere if (!r.IsCapturing() && !r.IsReplaying()) { 231c8dfe907SJonas Devlieghere result.SetError( 232c8dfe907SJonas Devlieghere "forcing a crash is only supported when capturing a reproducer."); 233c8dfe907SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 234c8dfe907SJonas Devlieghere return false; 235c8dfe907SJonas Devlieghere } 236c8dfe907SJonas Devlieghere 237c8dfe907SJonas Devlieghere switch (m_options.signal) { 238c8dfe907SJonas Devlieghere case eReproducerCrashSigill: 239c8dfe907SJonas Devlieghere std::raise(SIGILL); 240c8dfe907SJonas Devlieghere break; 241c8dfe907SJonas Devlieghere case eReproducerCrashSigsegv: 242c8dfe907SJonas Devlieghere std::raise(SIGSEGV); 243c8dfe907SJonas Devlieghere break; 244c8dfe907SJonas Devlieghere } 245c8dfe907SJonas Devlieghere 246c8dfe907SJonas Devlieghere result.SetStatus(eReturnStatusQuit); 247c8dfe907SJonas Devlieghere return result.Succeeded(); 248c8dfe907SJonas Devlieghere } 249c8dfe907SJonas Devlieghere 250c8dfe907SJonas Devlieghere private: 251c8dfe907SJonas Devlieghere CommandOptions m_options; 252c8dfe907SJonas Devlieghere }; 253c8dfe907SJonas Devlieghere 25415eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed { 2559e046f02SJonas Devlieghere public: 25615eacd74SJonas Devlieghere CommandObjectReproducerStatus(CommandInterpreter &interpreter) 257973d66eeSJonas Devlieghere : CommandObjectParsed( 258973d66eeSJonas Devlieghere interpreter, "reproducer status", 259c8dfe907SJonas Devlieghere "Show the current reproducer status. In capture mode the " 260c8dfe907SJonas Devlieghere "debugger " 261973d66eeSJonas Devlieghere "is collecting all the information it needs to create a " 262973d66eeSJonas Devlieghere "reproducer. In replay mode the reproducer is replaying a " 263973d66eeSJonas Devlieghere "reproducer. When the reproducers are off, no data is collected " 264973d66eeSJonas Devlieghere "and no reproducer can be generated.", 265973d66eeSJonas Devlieghere nullptr) {} 2669e046f02SJonas Devlieghere 26715eacd74SJonas Devlieghere ~CommandObjectReproducerStatus() override = default; 2689e046f02SJonas Devlieghere 2699e046f02SJonas Devlieghere protected: 2709e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 27115eacd74SJonas Devlieghere if (!command.empty()) { 27215eacd74SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 2739e046f02SJonas Devlieghere m_cmd_name.c_str()); 2749e046f02SJonas Devlieghere return false; 2759e046f02SJonas Devlieghere } 2769e046f02SJonas Devlieghere 27797fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 278865cd093SJonas Devlieghere if (r.IsCapturing()) { 27915eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in capture mode.\n"; 280865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 28115eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in replay mode.\n"; 28215eacd74SJonas Devlieghere } else { 28315eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is off.\n"; 2849e046f02SJonas Devlieghere } 2859e046f02SJonas Devlieghere 286982a77b6SJonas Devlieghere if (r.IsCapturing() || r.IsReplaying()) { 287982a77b6SJonas Devlieghere result.GetOutputStream() 288982a77b6SJonas Devlieghere << "Path: " << r.GetReproducerPath().GetPath() << '\n'; 289982a77b6SJonas Devlieghere } 290982a77b6SJonas Devlieghere 291982a77b6SJonas Devlieghere // Auto generate is hidden unless enabled because this is mostly for 292982a77b6SJonas Devlieghere // development and testing. 293982a77b6SJonas Devlieghere if (Generator *g = r.GetGenerator()) { 294982a77b6SJonas Devlieghere if (g->IsAutoGenerate()) 295982a77b6SJonas Devlieghere result.GetOutputStream() << "Auto generate: on\n"; 296982a77b6SJonas Devlieghere } 297982a77b6SJonas Devlieghere 29815eacd74SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 2999e046f02SJonas Devlieghere return result.Succeeded(); 3009e046f02SJonas Devlieghere } 3019e046f02SJonas Devlieghere }; 3029e046f02SJonas Devlieghere 30397fc8eb4SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) { 30497fc8eb4SJonas Devlieghere result.GetErrorStream().Printf("error: %s\n", 30597fc8eb4SJonas Devlieghere toString(std::move(err)).c_str()); 30697fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 30797fc8eb4SJonas Devlieghere } 30897fc8eb4SJonas Devlieghere 30997fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed { 31097fc8eb4SJonas Devlieghere public: 31197fc8eb4SJonas Devlieghere CommandObjectReproducerDump(CommandInterpreter &interpreter) 31297fc8eb4SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer dump", 31364b7d955SJonas Devlieghere "Dump the information contained in a reproducer. " 31464b7d955SJonas Devlieghere "If no reproducer is specified during replay, it " 31564b7d955SJonas Devlieghere "dumps the content of the current reproducer.", 31697fc8eb4SJonas Devlieghere nullptr) {} 31797fc8eb4SJonas Devlieghere 31897fc8eb4SJonas Devlieghere ~CommandObjectReproducerDump() override = default; 31997fc8eb4SJonas Devlieghere 32097fc8eb4SJonas Devlieghere Options *GetOptions() override { return &m_options; } 32197fc8eb4SJonas Devlieghere 32297fc8eb4SJonas Devlieghere class CommandOptions : public Options { 32397fc8eb4SJonas Devlieghere public: 32497fc8eb4SJonas Devlieghere CommandOptions() : Options(), file() {} 32597fc8eb4SJonas Devlieghere 32697fc8eb4SJonas Devlieghere ~CommandOptions() override = default; 32797fc8eb4SJonas Devlieghere 32897fc8eb4SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 32997fc8eb4SJonas Devlieghere ExecutionContext *execution_context) override { 33097fc8eb4SJonas Devlieghere Status error; 33197fc8eb4SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 33297fc8eb4SJonas Devlieghere 33397fc8eb4SJonas Devlieghere switch (short_option) { 33497fc8eb4SJonas Devlieghere case 'f': 33597fc8eb4SJonas Devlieghere file.SetFile(option_arg, FileSpec::Style::native); 33697fc8eb4SJonas Devlieghere FileSystem::Instance().Resolve(file); 33797fc8eb4SJonas Devlieghere break; 33897fc8eb4SJonas Devlieghere case 'p': 33997fc8eb4SJonas Devlieghere provider = (ReproducerProvider)OptionArgParser::ToOptionEnum( 34097fc8eb4SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 34197fc8eb4SJonas Devlieghere if (!error.Success()) 34297fc8eb4SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for provider '%s'", 34397fc8eb4SJonas Devlieghere option_arg.str().c_str()); 34497fc8eb4SJonas Devlieghere break; 34597fc8eb4SJonas Devlieghere default: 34697fc8eb4SJonas Devlieghere llvm_unreachable("Unimplemented option"); 34797fc8eb4SJonas Devlieghere } 34897fc8eb4SJonas Devlieghere 34997fc8eb4SJonas Devlieghere return error; 35097fc8eb4SJonas Devlieghere } 35197fc8eb4SJonas Devlieghere 35297fc8eb4SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 35397fc8eb4SJonas Devlieghere file.Clear(); 35497fc8eb4SJonas Devlieghere provider = eReproducerProviderNone; 35597fc8eb4SJonas Devlieghere } 35697fc8eb4SJonas Devlieghere 35797fc8eb4SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 35836eea5c3SJonas Devlieghere return makeArrayRef(g_reproducer_dump_options); 35997fc8eb4SJonas Devlieghere } 36097fc8eb4SJonas Devlieghere 36197fc8eb4SJonas Devlieghere FileSpec file; 36297fc8eb4SJonas Devlieghere ReproducerProvider provider = eReproducerProviderNone; 36397fc8eb4SJonas Devlieghere }; 36497fc8eb4SJonas Devlieghere 36597fc8eb4SJonas Devlieghere protected: 36697fc8eb4SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 36797fc8eb4SJonas Devlieghere if (!command.empty()) { 36897fc8eb4SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 36997fc8eb4SJonas Devlieghere m_cmd_name.c_str()); 37097fc8eb4SJonas Devlieghere return false; 37197fc8eb4SJonas Devlieghere } 37297fc8eb4SJonas Devlieghere 37397fc8eb4SJonas Devlieghere // If no reproducer path is specified, use the loader currently used for 37497fc8eb4SJonas Devlieghere // replay. Otherwise create a new loader just for dumping. 37597fc8eb4SJonas Devlieghere llvm::Optional<Loader> loader_storage; 37697fc8eb4SJonas Devlieghere Loader *loader = nullptr; 37797fc8eb4SJonas Devlieghere if (!m_options.file) { 37897fc8eb4SJonas Devlieghere loader = Reproducer::Instance().GetLoader(); 37997fc8eb4SJonas Devlieghere if (loader == nullptr) { 38097fc8eb4SJonas Devlieghere result.SetError( 38197fc8eb4SJonas Devlieghere "Not specifying a reproducer is only support during replay."); 38297fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 38397fc8eb4SJonas Devlieghere return false; 38497fc8eb4SJonas Devlieghere } 38597fc8eb4SJonas Devlieghere } else { 38697fc8eb4SJonas Devlieghere loader_storage.emplace(m_options.file); 38797fc8eb4SJonas Devlieghere loader = &(*loader_storage); 38897fc8eb4SJonas Devlieghere if (Error err = loader->LoadIndex()) { 38997fc8eb4SJonas Devlieghere SetError(result, std::move(err)); 39097fc8eb4SJonas Devlieghere return false; 39197fc8eb4SJonas Devlieghere } 39297fc8eb4SJonas Devlieghere } 39397fc8eb4SJonas Devlieghere 39497fc8eb4SJonas Devlieghere // If we get here we should have a valid loader. 39597fc8eb4SJonas Devlieghere assert(loader); 39697fc8eb4SJonas Devlieghere 39797fc8eb4SJonas Devlieghere switch (m_options.provider) { 39897fc8eb4SJonas Devlieghere case eReproducerProviderFiles: { 39997fc8eb4SJonas Devlieghere FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>(); 40097fc8eb4SJonas Devlieghere 40197fc8eb4SJonas Devlieghere // Read the VFS mapping. 40297fc8eb4SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = 40397fc8eb4SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); 40497fc8eb4SJonas Devlieghere if (!buffer) { 40597fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(buffer.getError())); 40697fc8eb4SJonas Devlieghere return false; 40797fc8eb4SJonas Devlieghere } 40897fc8eb4SJonas Devlieghere 40997fc8eb4SJonas Devlieghere // Initialize a VFS from the given mapping. 41097fc8eb4SJonas Devlieghere IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML( 41197fc8eb4SJonas Devlieghere std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); 41297fc8eb4SJonas Devlieghere 41397fc8eb4SJonas Devlieghere // Dump the VFS to a buffer. 41497fc8eb4SJonas Devlieghere std::string str; 41597fc8eb4SJonas Devlieghere raw_string_ostream os(str); 41697fc8eb4SJonas Devlieghere static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os); 41797fc8eb4SJonas Devlieghere os.flush(); 41897fc8eb4SJonas Devlieghere 41997fc8eb4SJonas Devlieghere // Return the string. 42097fc8eb4SJonas Devlieghere result.AppendMessage(str); 42197fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 42297fc8eb4SJonas Devlieghere return true; 42397fc8eb4SJonas Devlieghere } 42497fc8eb4SJonas Devlieghere case eReproducerProviderVersion: { 425b2575da9SJonas Devlieghere Expected<std::string> version = loader->LoadBuffer<VersionProvider>(); 426b2575da9SJonas Devlieghere if (!version) { 427b2575da9SJonas Devlieghere SetError(result, version.takeError()); 42897fc8eb4SJonas Devlieghere return false; 42997fc8eb4SJonas Devlieghere } 430b2575da9SJonas Devlieghere result.AppendMessage(*version); 43197fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 43297fc8eb4SJonas Devlieghere return true; 43397fc8eb4SJonas Devlieghere } 434f4f12012SJonas Devlieghere case eReproducerProviderWorkingDirectory: { 435f4f12012SJonas Devlieghere Expected<std::string> cwd = 436f4f12012SJonas Devlieghere loader->LoadBuffer<WorkingDirectoryProvider>(); 437f4f12012SJonas Devlieghere if (!cwd) { 438f4f12012SJonas Devlieghere SetError(result, cwd.takeError()); 439f4f12012SJonas Devlieghere return false; 440f4f12012SJonas Devlieghere } 441f4f12012SJonas Devlieghere result.AppendMessage(*cwd); 442f4f12012SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 443f4f12012SJonas Devlieghere return true; 444f4f12012SJonas Devlieghere } 44597fc8eb4SJonas Devlieghere case eReproducerProviderCommands: { 4461d41d1bcSEric Christopher std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader = 4471d41d1bcSEric Christopher repro::MultiLoader<repro::CommandProvider>::Create(loader); 4481d41d1bcSEric Christopher if (!multi_loader) { 44997fc8eb4SJonas Devlieghere SetError(result, 4504016c6b0SJonas Devlieghere make_error<StringError>("Unable to create command loader.", 4514016c6b0SJonas Devlieghere llvm::inconvertibleErrorCode())); 45297fc8eb4SJonas Devlieghere return false; 45397fc8eb4SJonas Devlieghere } 45497fc8eb4SJonas Devlieghere 45597fc8eb4SJonas Devlieghere // Iterate over the command files and dump them. 4561d41d1bcSEric Christopher llvm::Optional<std::string> command_file; 4571d41d1bcSEric Christopher while ((command_file = multi_loader->GetNextFile())) { 45897fc8eb4SJonas Devlieghere if (!command_file) 45997fc8eb4SJonas Devlieghere break; 46097fc8eb4SJonas Devlieghere 46197fc8eb4SJonas Devlieghere auto command_buffer = llvm::MemoryBuffer::getFile(*command_file); 46297fc8eb4SJonas Devlieghere if (auto err = command_buffer.getError()) { 46397fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(err)); 46497fc8eb4SJonas Devlieghere return false; 46597fc8eb4SJonas Devlieghere } 46697fc8eb4SJonas Devlieghere result.AppendMessage((*command_buffer)->getBuffer()); 46797fc8eb4SJonas Devlieghere } 46897fc8eb4SJonas Devlieghere 46997fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 47097fc8eb4SJonas Devlieghere return true; 47197fc8eb4SJonas Devlieghere } 47297fc8eb4SJonas Devlieghere case eReproducerProviderGDB: { 4731d41d1bcSEric Christopher std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> 4741d41d1bcSEric Christopher multi_loader = 4751d41d1bcSEric Christopher repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader); 4764016c6b0SJonas Devlieghere 4774016c6b0SJonas Devlieghere if (!multi_loader) { 4784016c6b0SJonas Devlieghere SetError(result, 4794016c6b0SJonas Devlieghere make_error<StringError>("Unable to create GDB loader.", 4804016c6b0SJonas Devlieghere llvm::inconvertibleErrorCode())); 4814016c6b0SJonas Devlieghere return false; 4824016c6b0SJonas Devlieghere } 4834016c6b0SJonas Devlieghere 4841d41d1bcSEric Christopher llvm::Optional<std::string> gdb_file; 4851d41d1bcSEric Christopher while ((gdb_file = multi_loader->GetNextFile())) { 486*2451cbf0SJonas Devlieghere if (llvm::Expected<std::vector<GDBRemotePacket>> packets = 487*2451cbf0SJonas Devlieghere ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) { 488*2451cbf0SJonas Devlieghere for (GDBRemotePacket &packet : *packets) { 4898fc8d3feSJonas Devlieghere packet.Dump(result.GetOutputStream()); 4908fc8d3feSJonas Devlieghere } 491*2451cbf0SJonas Devlieghere } else { 492*2451cbf0SJonas Devlieghere SetError(result, packets.takeError()); 493*2451cbf0SJonas Devlieghere return false; 494*2451cbf0SJonas Devlieghere } 495*2451cbf0SJonas Devlieghere } 496*2451cbf0SJonas Devlieghere 497*2451cbf0SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 498*2451cbf0SJonas Devlieghere return true; 499*2451cbf0SJonas Devlieghere } 500*2451cbf0SJonas Devlieghere case eReproducerProviderProcessInfo: { 501*2451cbf0SJonas Devlieghere std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>> 502*2451cbf0SJonas Devlieghere multi_loader = 503*2451cbf0SJonas Devlieghere repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader); 504*2451cbf0SJonas Devlieghere 505*2451cbf0SJonas Devlieghere if (!multi_loader) { 506*2451cbf0SJonas Devlieghere SetError(result, make_error<StringError>( 507*2451cbf0SJonas Devlieghere llvm::inconvertibleErrorCode(), 508*2451cbf0SJonas Devlieghere "Unable to create process info loader.")); 509*2451cbf0SJonas Devlieghere return false; 510*2451cbf0SJonas Devlieghere } 511*2451cbf0SJonas Devlieghere 512*2451cbf0SJonas Devlieghere llvm::Optional<std::string> process_file; 513*2451cbf0SJonas Devlieghere while ((process_file = multi_loader->GetNextFile())) { 514*2451cbf0SJonas Devlieghere if (llvm::Expected<ProcessInstanceInfoList> infos = 515*2451cbf0SJonas Devlieghere ReadFromYAML<ProcessInstanceInfoList>(*process_file)) { 516*2451cbf0SJonas Devlieghere for (ProcessInstanceInfo info : *infos) 517*2451cbf0SJonas Devlieghere info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver()); 518*2451cbf0SJonas Devlieghere } else { 519*2451cbf0SJonas Devlieghere SetError(result, infos.takeError()); 520*2451cbf0SJonas Devlieghere return false; 521*2451cbf0SJonas Devlieghere } 5221d41d1bcSEric Christopher } 5238fc8d3feSJonas Devlieghere 52497fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 52597fc8eb4SJonas Devlieghere return true; 52697fc8eb4SJonas Devlieghere } 52797fc8eb4SJonas Devlieghere case eReproducerProviderNone: 52897fc8eb4SJonas Devlieghere result.SetError("No valid provider specified."); 52997fc8eb4SJonas Devlieghere return false; 53097fc8eb4SJonas Devlieghere } 53197fc8eb4SJonas Devlieghere 53297fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 53397fc8eb4SJonas Devlieghere return result.Succeeded(); 53497fc8eb4SJonas Devlieghere } 53597fc8eb4SJonas Devlieghere 53697fc8eb4SJonas Devlieghere private: 53797fc8eb4SJonas Devlieghere CommandOptions m_options; 53897fc8eb4SJonas Devlieghere }; 53997fc8eb4SJonas Devlieghere 5409e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer( 5419e046f02SJonas Devlieghere CommandInterpreter &interpreter) 542973d66eeSJonas Devlieghere : CommandObjectMultiword( 543973d66eeSJonas Devlieghere interpreter, "reproducer", 544c8dfe907SJonas Devlieghere "Commands for manipulating reproducers. Reproducers make it " 545c8dfe907SJonas Devlieghere "possible " 54664b7d955SJonas Devlieghere "to capture full debug sessions with all its dependencies. The " 54764b7d955SJonas Devlieghere "resulting reproducer is used to replay the debug session while " 54864b7d955SJonas Devlieghere "debugging the debugger.\n" 54964b7d955SJonas Devlieghere "Because reproducers need the whole the debug session from " 55064b7d955SJonas Devlieghere "beginning to end, you need to launch the debugger in capture or " 55164b7d955SJonas Devlieghere "replay mode, commonly though the command line driver.\n" 55264b7d955SJonas Devlieghere "Reproducers are unrelated record-replay debugging, as you cannot " 55364b7d955SJonas Devlieghere "interact with the debugger during replay.\n", 554130ec068SJonas Devlieghere "reproducer <subcommand> [<subcommand-options>]") { 5559e046f02SJonas Devlieghere LoadSubCommand( 5569e046f02SJonas Devlieghere "generate", 5579e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 55815eacd74SJonas Devlieghere LoadSubCommand("status", CommandObjectSP( 55915eacd74SJonas Devlieghere new CommandObjectReproducerStatus(interpreter))); 56097fc8eb4SJonas Devlieghere LoadSubCommand("dump", 56197fc8eb4SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerDump(interpreter))); 562c8dfe907SJonas Devlieghere LoadSubCommand("xcrash", CommandObjectSP( 563c8dfe907SJonas Devlieghere new CommandObjectReproducerXCrash(interpreter))); 5649e046f02SJonas Devlieghere } 5659e046f02SJonas Devlieghere 5669e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default; 567