180814287SRaphael Isemann //===-- CommandObjectReproducer.cpp ---------------------------------------===// 29e046f02SJonas Devlieghere // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69e046f02SJonas Devlieghere // 79e046f02SJonas Devlieghere //===----------------------------------------------------------------------===// 89e046f02SJonas Devlieghere 99e046f02SJonas Devlieghere #include "CommandObjectReproducer.h" 109e046f02SJonas Devlieghere 112451cbf0SJonas Devlieghere #include "lldb/Host/HostInfo.h" 1297fc8eb4SJonas Devlieghere #include "lldb/Host/OptionParser.h" 13df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 149e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 159e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h" 162451cbf0SJonas Devlieghere #include "lldb/Utility/GDBRemote.h" 172451cbf0SJonas Devlieghere #include "lldb/Utility/ProcessInfo.h" 182451cbf0SJonas Devlieghere #include "lldb/Utility/Reproducer.h" 199e046f02SJonas Devlieghere 20c8dfe907SJonas Devlieghere #include <csignal> 21c8dfe907SJonas Devlieghere 229e046f02SJonas Devlieghere using namespace lldb; 2397fc8eb4SJonas Devlieghere using namespace llvm; 249e046f02SJonas Devlieghere using namespace lldb_private; 2597fc8eb4SJonas Devlieghere using namespace lldb_private::repro; 2697fc8eb4SJonas Devlieghere 2797fc8eb4SJonas Devlieghere enum ReproducerProvider { 2897fc8eb4SJonas Devlieghere eReproducerProviderCommands, 2997fc8eb4SJonas Devlieghere eReproducerProviderFiles, 30a842950bSJonas Devlieghere eReproducerProviderSymbolFiles, 3197fc8eb4SJonas Devlieghere eReproducerProviderGDB, 322451cbf0SJonas Devlieghere eReproducerProviderProcessInfo, 3397fc8eb4SJonas Devlieghere eReproducerProviderVersion, 34f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 3573af341bSJonas Devlieghere eReproducerProviderHomeDirectory, 3697fc8eb4SJonas Devlieghere eReproducerProviderNone 3797fc8eb4SJonas Devlieghere }; 3897fc8eb4SJonas Devlieghere 3997fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { 4097fc8eb4SJonas Devlieghere { 4197fc8eb4SJonas Devlieghere eReproducerProviderCommands, 4297fc8eb4SJonas Devlieghere "commands", 4397fc8eb4SJonas Devlieghere "Command Interpreter Commands", 4497fc8eb4SJonas Devlieghere }, 4597fc8eb4SJonas Devlieghere { 4697fc8eb4SJonas Devlieghere eReproducerProviderFiles, 4797fc8eb4SJonas Devlieghere "files", 4897fc8eb4SJonas Devlieghere "Files", 4997fc8eb4SJonas Devlieghere }, 5097fc8eb4SJonas Devlieghere { 51a842950bSJonas Devlieghere eReproducerProviderSymbolFiles, 52a842950bSJonas Devlieghere "symbol-files", 53a842950bSJonas Devlieghere "Symbol Files", 54a842950bSJonas Devlieghere }, 55a842950bSJonas Devlieghere { 5697fc8eb4SJonas Devlieghere eReproducerProviderGDB, 5797fc8eb4SJonas Devlieghere "gdb", 5897fc8eb4SJonas Devlieghere "GDB Remote Packets", 5997fc8eb4SJonas Devlieghere }, 6097fc8eb4SJonas Devlieghere { 612451cbf0SJonas Devlieghere eReproducerProviderProcessInfo, 622451cbf0SJonas Devlieghere "processes", 632451cbf0SJonas Devlieghere "Process Info", 642451cbf0SJonas Devlieghere }, 652451cbf0SJonas Devlieghere { 6697fc8eb4SJonas Devlieghere eReproducerProviderVersion, 6797fc8eb4SJonas Devlieghere "version", 6897fc8eb4SJonas Devlieghere "Version", 6997fc8eb4SJonas Devlieghere }, 7097fc8eb4SJonas Devlieghere { 71f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 72f4f12012SJonas Devlieghere "cwd", 73f4f12012SJonas Devlieghere "Working Directory", 74f4f12012SJonas Devlieghere }, 75f4f12012SJonas Devlieghere { 7673af341bSJonas Devlieghere eReproducerProviderHomeDirectory, 7773af341bSJonas Devlieghere "home", 7873af341bSJonas Devlieghere "Home Directory", 7973af341bSJonas Devlieghere }, 8073af341bSJonas Devlieghere { 8197fc8eb4SJonas Devlieghere eReproducerProviderNone, 8297fc8eb4SJonas Devlieghere "none", 8397fc8eb4SJonas Devlieghere "None", 8497fc8eb4SJonas Devlieghere }, 8597fc8eb4SJonas Devlieghere }; 8697fc8eb4SJonas Devlieghere 8797fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() { 8897fc8eb4SJonas Devlieghere return OptionEnumValues(g_reproducer_provider_type); 8997fc8eb4SJonas Devlieghere } 9097fc8eb4SJonas Devlieghere 9136eea5c3SJonas Devlieghere #define LLDB_OPTIONS_reproducer_dump 9297fc8eb4SJonas Devlieghere #include "CommandOptions.inc" 939e046f02SJonas Devlieghere 94c8dfe907SJonas Devlieghere enum ReproducerCrashSignal { 95c8dfe907SJonas Devlieghere eReproducerCrashSigill, 96c8dfe907SJonas Devlieghere eReproducerCrashSigsegv, 97c8dfe907SJonas Devlieghere }; 98c8dfe907SJonas Devlieghere 99c8dfe907SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_signaltype[] = { 100c8dfe907SJonas Devlieghere { 101c8dfe907SJonas Devlieghere eReproducerCrashSigill, 102c8dfe907SJonas Devlieghere "SIGILL", 103c8dfe907SJonas Devlieghere "Illegal instruction", 104c8dfe907SJonas Devlieghere }, 105c8dfe907SJonas Devlieghere { 106c8dfe907SJonas Devlieghere eReproducerCrashSigsegv, 107c8dfe907SJonas Devlieghere "SIGSEGV", 108c8dfe907SJonas Devlieghere "Segmentation fault", 109c8dfe907SJonas Devlieghere }, 110c8dfe907SJonas Devlieghere }; 111c8dfe907SJonas Devlieghere 112c8dfe907SJonas Devlieghere static constexpr OptionEnumValues ReproducerSignalType() { 113c8dfe907SJonas Devlieghere return OptionEnumValues(g_reproducer_signaltype); 114c8dfe907SJonas Devlieghere } 115c8dfe907SJonas Devlieghere 116c8dfe907SJonas Devlieghere #define LLDB_OPTIONS_reproducer_xcrash 117c8dfe907SJonas Devlieghere #include "CommandOptions.inc" 118c8dfe907SJonas Devlieghere 119*37469061SJonas Devlieghere #define LLDB_OPTIONS_reproducer_verify 120*37469061SJonas Devlieghere #include "CommandOptions.inc" 121*37469061SJonas Devlieghere 1222451cbf0SJonas Devlieghere template <typename T> 1232451cbf0SJonas Devlieghere llvm::Expected<T> static ReadFromYAML(StringRef filename) { 1242451cbf0SJonas Devlieghere auto error_or_file = MemoryBuffer::getFile(filename); 1252451cbf0SJonas Devlieghere if (auto err = error_or_file.getError()) { 1262451cbf0SJonas Devlieghere return errorCodeToError(err); 1272451cbf0SJonas Devlieghere } 1282451cbf0SJonas Devlieghere 1292451cbf0SJonas Devlieghere T t; 1302451cbf0SJonas Devlieghere yaml::Input yin((*error_or_file)->getBuffer()); 1312451cbf0SJonas Devlieghere yin >> t; 1322451cbf0SJonas Devlieghere 1332451cbf0SJonas Devlieghere if (auto err = yin.error()) { 1342451cbf0SJonas Devlieghere return errorCodeToError(err); 1352451cbf0SJonas Devlieghere } 1362451cbf0SJonas Devlieghere 1372451cbf0SJonas Devlieghere return t; 1382451cbf0SJonas Devlieghere } 1392451cbf0SJonas Devlieghere 140*37469061SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) { 141*37469061SJonas Devlieghere result.GetErrorStream().Printf("error: %s\n", 142*37469061SJonas Devlieghere toString(std::move(err)).c_str()); 143*37469061SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 144*37469061SJonas Devlieghere } 145*37469061SJonas Devlieghere 146*37469061SJonas Devlieghere /// Create a loader from the given path if specified. Otherwise use the current 147*37469061SJonas Devlieghere /// loader used for replay. 148*37469061SJonas Devlieghere static Loader * 149*37469061SJonas Devlieghere GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage, 150*37469061SJonas Devlieghere CommandReturnObject &result, 151*37469061SJonas Devlieghere FileSpec reproducer_path) { 152*37469061SJonas Devlieghere if (reproducer_path) { 153*37469061SJonas Devlieghere loader_storage.emplace(reproducer_path); 154*37469061SJonas Devlieghere Loader *loader = &(*loader_storage); 155*37469061SJonas Devlieghere if (Error err = loader->LoadIndex()) { 156*37469061SJonas Devlieghere // This is a hard error and will set the result to eReturnStatusFailed. 157*37469061SJonas Devlieghere SetError(result, std::move(err)); 158*37469061SJonas Devlieghere return nullptr; 159*37469061SJonas Devlieghere } 160*37469061SJonas Devlieghere return loader; 161*37469061SJonas Devlieghere } 162*37469061SJonas Devlieghere 163*37469061SJonas Devlieghere if (Loader *loader = Reproducer::Instance().GetLoader()) 164*37469061SJonas Devlieghere return loader; 165*37469061SJonas Devlieghere 166*37469061SJonas Devlieghere // This is a soft error because this is expected to fail during capture. 167*37469061SJonas Devlieghere result.SetError("Not specifying a reproducer is only support during replay."); 168*37469061SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 169*37469061SJonas Devlieghere return nullptr; 170*37469061SJonas Devlieghere } 171*37469061SJonas Devlieghere 1729e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed { 1739e046f02SJonas Devlieghere public: 1749e046f02SJonas Devlieghere CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 175973d66eeSJonas Devlieghere : CommandObjectParsed( 176973d66eeSJonas Devlieghere interpreter, "reproducer generate", 177973d66eeSJonas Devlieghere "Generate reproducer on disk. When the debugger is in capture " 178973d66eeSJonas Devlieghere "mode, this command will output the reproducer to a directory on " 1790cf86da1SJonas Devlieghere "disk and quit. In replay mode this command in a no-op.", 180973d66eeSJonas Devlieghere nullptr) {} 1819e046f02SJonas Devlieghere 1829e046f02SJonas Devlieghere ~CommandObjectReproducerGenerate() override = default; 1839e046f02SJonas Devlieghere 1849e046f02SJonas Devlieghere protected: 1859e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 1869e046f02SJonas Devlieghere if (!command.empty()) { 1879e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 1889e046f02SJonas Devlieghere m_cmd_name.c_str()); 1899e046f02SJonas Devlieghere return false; 1909e046f02SJonas Devlieghere } 1919e046f02SJonas Devlieghere 19297fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 1939e046f02SJonas Devlieghere if (auto generator = r.GetGenerator()) { 1949e046f02SJonas Devlieghere generator->Keep(); 195865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 196bb090bb1SJonas Devlieghere // Make this operation a NO-OP in replay mode. 1972dca6538SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 1982dca6538SJonas Devlieghere return result.Succeeded(); 1999e046f02SJonas Devlieghere } else { 2009e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer generator"); 2012dca6538SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 2029e046f02SJonas Devlieghere return false; 2039e046f02SJonas Devlieghere } 2049e046f02SJonas Devlieghere 2059e046f02SJonas Devlieghere result.GetOutputStream() 2069e046f02SJonas Devlieghere << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 2071c5250abSJonas Devlieghere result.GetOutputStream() 2081c5250abSJonas Devlieghere << "Please have a look at the directory to assess if you're willing to " 2091c5250abSJonas Devlieghere "share the contained information.\n"; 2109e046f02SJonas Devlieghere 2110cf86da1SJonas Devlieghere m_interpreter.BroadcastEvent( 2120cf86da1SJonas Devlieghere CommandInterpreter::eBroadcastBitQuitCommandReceived); 2130cf86da1SJonas Devlieghere result.SetStatus(eReturnStatusQuit); 2149e046f02SJonas Devlieghere return result.Succeeded(); 2159e046f02SJonas Devlieghere } 2169e046f02SJonas Devlieghere }; 2179e046f02SJonas Devlieghere 218c8dfe907SJonas Devlieghere class CommandObjectReproducerXCrash : public CommandObjectParsed { 219c8dfe907SJonas Devlieghere public: 220c8dfe907SJonas Devlieghere CommandObjectReproducerXCrash(CommandInterpreter &interpreter) 221c8dfe907SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer xcrash", 222c8dfe907SJonas Devlieghere "Intentionally force the debugger to crash in " 223c8dfe907SJonas Devlieghere "order to trigger and test reproducer generation.", 224c8dfe907SJonas Devlieghere nullptr) {} 225c8dfe907SJonas Devlieghere 226c8dfe907SJonas Devlieghere ~CommandObjectReproducerXCrash() override = default; 227c8dfe907SJonas Devlieghere 228c8dfe907SJonas Devlieghere Options *GetOptions() override { return &m_options; } 229c8dfe907SJonas Devlieghere 230c8dfe907SJonas Devlieghere class CommandOptions : public Options { 231c8dfe907SJonas Devlieghere public: 232c8dfe907SJonas Devlieghere CommandOptions() : Options() {} 233c8dfe907SJonas Devlieghere 234c8dfe907SJonas Devlieghere ~CommandOptions() override = default; 235c8dfe907SJonas Devlieghere 236c8dfe907SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 237c8dfe907SJonas Devlieghere ExecutionContext *execution_context) override { 238c8dfe907SJonas Devlieghere Status error; 239c8dfe907SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 240c8dfe907SJonas Devlieghere 241c8dfe907SJonas Devlieghere switch (short_option) { 242c8dfe907SJonas Devlieghere case 's': 243c8dfe907SJonas Devlieghere signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum( 244c8dfe907SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 245c8dfe907SJonas Devlieghere if (!error.Success()) 246c8dfe907SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for signal '%s'", 247c8dfe907SJonas Devlieghere option_arg.str().c_str()); 248c8dfe907SJonas Devlieghere break; 249c8dfe907SJonas Devlieghere default: 250c8dfe907SJonas Devlieghere llvm_unreachable("Unimplemented option"); 251c8dfe907SJonas Devlieghere } 252c8dfe907SJonas Devlieghere 253c8dfe907SJonas Devlieghere return error; 254c8dfe907SJonas Devlieghere } 255c8dfe907SJonas Devlieghere 256c8dfe907SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 257c8dfe907SJonas Devlieghere signal = eReproducerCrashSigsegv; 258c8dfe907SJonas Devlieghere } 259c8dfe907SJonas Devlieghere 260c8dfe907SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 261c8dfe907SJonas Devlieghere return makeArrayRef(g_reproducer_xcrash_options); 262c8dfe907SJonas Devlieghere } 263c8dfe907SJonas Devlieghere 264c8dfe907SJonas Devlieghere ReproducerCrashSignal signal = eReproducerCrashSigsegv; 265c8dfe907SJonas Devlieghere }; 266c8dfe907SJonas Devlieghere 267c8dfe907SJonas Devlieghere protected: 268c8dfe907SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 269c8dfe907SJonas Devlieghere if (!command.empty()) { 270c8dfe907SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 271c8dfe907SJonas Devlieghere m_cmd_name.c_str()); 272c8dfe907SJonas Devlieghere return false; 273c8dfe907SJonas Devlieghere } 274c8dfe907SJonas Devlieghere 275c8dfe907SJonas Devlieghere auto &r = Reproducer::Instance(); 276bb090bb1SJonas Devlieghere 277bb090bb1SJonas Devlieghere if (!r.IsCapturing() && !r.IsReplaying()) { 278c8dfe907SJonas Devlieghere result.SetError( 279c8dfe907SJonas Devlieghere "forcing a crash is only supported when capturing a reproducer."); 280c8dfe907SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 281c8dfe907SJonas Devlieghere return false; 282c8dfe907SJonas Devlieghere } 283c8dfe907SJonas Devlieghere 284c8dfe907SJonas Devlieghere switch (m_options.signal) { 285c8dfe907SJonas Devlieghere case eReproducerCrashSigill: 286c8dfe907SJonas Devlieghere std::raise(SIGILL); 287c8dfe907SJonas Devlieghere break; 288c8dfe907SJonas Devlieghere case eReproducerCrashSigsegv: 289c8dfe907SJonas Devlieghere std::raise(SIGSEGV); 290c8dfe907SJonas Devlieghere break; 291c8dfe907SJonas Devlieghere } 292c8dfe907SJonas Devlieghere 293c8dfe907SJonas Devlieghere result.SetStatus(eReturnStatusQuit); 294c8dfe907SJonas Devlieghere return result.Succeeded(); 295c8dfe907SJonas Devlieghere } 296c8dfe907SJonas Devlieghere 297c8dfe907SJonas Devlieghere private: 298c8dfe907SJonas Devlieghere CommandOptions m_options; 299c8dfe907SJonas Devlieghere }; 300c8dfe907SJonas Devlieghere 30115eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed { 3029e046f02SJonas Devlieghere public: 30315eacd74SJonas Devlieghere CommandObjectReproducerStatus(CommandInterpreter &interpreter) 304973d66eeSJonas Devlieghere : CommandObjectParsed( 305973d66eeSJonas Devlieghere interpreter, "reproducer status", 306c8dfe907SJonas Devlieghere "Show the current reproducer status. In capture mode the " 307c8dfe907SJonas Devlieghere "debugger " 308973d66eeSJonas Devlieghere "is collecting all the information it needs to create a " 309973d66eeSJonas Devlieghere "reproducer. In replay mode the reproducer is replaying a " 310973d66eeSJonas Devlieghere "reproducer. When the reproducers are off, no data is collected " 311973d66eeSJonas Devlieghere "and no reproducer can be generated.", 312973d66eeSJonas Devlieghere nullptr) {} 3139e046f02SJonas Devlieghere 31415eacd74SJonas Devlieghere ~CommandObjectReproducerStatus() override = default; 3159e046f02SJonas Devlieghere 3169e046f02SJonas Devlieghere protected: 3179e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 31815eacd74SJonas Devlieghere if (!command.empty()) { 31915eacd74SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 3209e046f02SJonas Devlieghere m_cmd_name.c_str()); 3219e046f02SJonas Devlieghere return false; 3229e046f02SJonas Devlieghere } 3239e046f02SJonas Devlieghere 32497fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 325865cd093SJonas Devlieghere if (r.IsCapturing()) { 32615eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in capture mode.\n"; 327865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 32815eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in replay mode.\n"; 32915eacd74SJonas Devlieghere } else { 33015eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is off.\n"; 3319e046f02SJonas Devlieghere } 3329e046f02SJonas Devlieghere 333982a77b6SJonas Devlieghere if (r.IsCapturing() || r.IsReplaying()) { 334982a77b6SJonas Devlieghere result.GetOutputStream() 335982a77b6SJonas Devlieghere << "Path: " << r.GetReproducerPath().GetPath() << '\n'; 336982a77b6SJonas Devlieghere } 337982a77b6SJonas Devlieghere 338982a77b6SJonas Devlieghere // Auto generate is hidden unless enabled because this is mostly for 339982a77b6SJonas Devlieghere // development and testing. 340982a77b6SJonas Devlieghere if (Generator *g = r.GetGenerator()) { 341982a77b6SJonas Devlieghere if (g->IsAutoGenerate()) 342982a77b6SJonas Devlieghere result.GetOutputStream() << "Auto generate: on\n"; 343982a77b6SJonas Devlieghere } 344982a77b6SJonas Devlieghere 34515eacd74SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 3469e046f02SJonas Devlieghere return result.Succeeded(); 3479e046f02SJonas Devlieghere } 3489e046f02SJonas Devlieghere }; 3499e046f02SJonas Devlieghere 35097fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed { 35197fc8eb4SJonas Devlieghere public: 35297fc8eb4SJonas Devlieghere CommandObjectReproducerDump(CommandInterpreter &interpreter) 35397fc8eb4SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer dump", 35464b7d955SJonas Devlieghere "Dump the information contained in a reproducer. " 35564b7d955SJonas Devlieghere "If no reproducer is specified during replay, it " 35664b7d955SJonas Devlieghere "dumps the content of the current reproducer.", 35797fc8eb4SJonas Devlieghere nullptr) {} 35897fc8eb4SJonas Devlieghere 35997fc8eb4SJonas Devlieghere ~CommandObjectReproducerDump() override = default; 36097fc8eb4SJonas Devlieghere 36197fc8eb4SJonas Devlieghere Options *GetOptions() override { return &m_options; } 36297fc8eb4SJonas Devlieghere 36397fc8eb4SJonas Devlieghere class CommandOptions : public Options { 36497fc8eb4SJonas Devlieghere public: 36597fc8eb4SJonas Devlieghere CommandOptions() : Options(), file() {} 36697fc8eb4SJonas Devlieghere 36797fc8eb4SJonas Devlieghere ~CommandOptions() override = default; 36897fc8eb4SJonas Devlieghere 36997fc8eb4SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 37097fc8eb4SJonas Devlieghere ExecutionContext *execution_context) override { 37197fc8eb4SJonas Devlieghere Status error; 37297fc8eb4SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 37397fc8eb4SJonas Devlieghere 37497fc8eb4SJonas Devlieghere switch (short_option) { 37597fc8eb4SJonas Devlieghere case 'f': 37697fc8eb4SJonas Devlieghere file.SetFile(option_arg, FileSpec::Style::native); 37797fc8eb4SJonas Devlieghere FileSystem::Instance().Resolve(file); 37897fc8eb4SJonas Devlieghere break; 37997fc8eb4SJonas Devlieghere case 'p': 38097fc8eb4SJonas Devlieghere provider = (ReproducerProvider)OptionArgParser::ToOptionEnum( 38197fc8eb4SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 38297fc8eb4SJonas Devlieghere if (!error.Success()) 38397fc8eb4SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for provider '%s'", 38497fc8eb4SJonas Devlieghere option_arg.str().c_str()); 38597fc8eb4SJonas Devlieghere break; 38697fc8eb4SJonas Devlieghere default: 38797fc8eb4SJonas Devlieghere llvm_unreachable("Unimplemented option"); 38897fc8eb4SJonas Devlieghere } 38997fc8eb4SJonas Devlieghere 39097fc8eb4SJonas Devlieghere return error; 39197fc8eb4SJonas Devlieghere } 39297fc8eb4SJonas Devlieghere 39397fc8eb4SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 39497fc8eb4SJonas Devlieghere file.Clear(); 39597fc8eb4SJonas Devlieghere provider = eReproducerProviderNone; 39697fc8eb4SJonas Devlieghere } 39797fc8eb4SJonas Devlieghere 39897fc8eb4SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 39936eea5c3SJonas Devlieghere return makeArrayRef(g_reproducer_dump_options); 40097fc8eb4SJonas Devlieghere } 40197fc8eb4SJonas Devlieghere 40297fc8eb4SJonas Devlieghere FileSpec file; 40397fc8eb4SJonas Devlieghere ReproducerProvider provider = eReproducerProviderNone; 40497fc8eb4SJonas Devlieghere }; 40597fc8eb4SJonas Devlieghere 40697fc8eb4SJonas Devlieghere protected: 40797fc8eb4SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 40897fc8eb4SJonas Devlieghere if (!command.empty()) { 40997fc8eb4SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 41097fc8eb4SJonas Devlieghere m_cmd_name.c_str()); 41197fc8eb4SJonas Devlieghere return false; 41297fc8eb4SJonas Devlieghere } 41397fc8eb4SJonas Devlieghere 41497fc8eb4SJonas Devlieghere llvm::Optional<Loader> loader_storage; 415*37469061SJonas Devlieghere Loader *loader = 416*37469061SJonas Devlieghere GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); 417*37469061SJonas Devlieghere if (!loader) 41897fc8eb4SJonas Devlieghere return false; 41997fc8eb4SJonas Devlieghere 42097fc8eb4SJonas Devlieghere switch (m_options.provider) { 42197fc8eb4SJonas Devlieghere case eReproducerProviderFiles: { 42297fc8eb4SJonas Devlieghere FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>(); 42397fc8eb4SJonas Devlieghere 42497fc8eb4SJonas Devlieghere // Read the VFS mapping. 42597fc8eb4SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = 42697fc8eb4SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); 42797fc8eb4SJonas Devlieghere if (!buffer) { 42897fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(buffer.getError())); 42997fc8eb4SJonas Devlieghere return false; 43097fc8eb4SJonas Devlieghere } 43197fc8eb4SJonas Devlieghere 43297fc8eb4SJonas Devlieghere // Initialize a VFS from the given mapping. 43397fc8eb4SJonas Devlieghere IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML( 43497fc8eb4SJonas Devlieghere std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); 43597fc8eb4SJonas Devlieghere 43697fc8eb4SJonas Devlieghere // Dump the VFS to a buffer. 43797fc8eb4SJonas Devlieghere std::string str; 43897fc8eb4SJonas Devlieghere raw_string_ostream os(str); 43997fc8eb4SJonas Devlieghere static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os); 44097fc8eb4SJonas Devlieghere os.flush(); 44197fc8eb4SJonas Devlieghere 44297fc8eb4SJonas Devlieghere // Return the string. 44397fc8eb4SJonas Devlieghere result.AppendMessage(str); 44497fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 44597fc8eb4SJonas Devlieghere return true; 44697fc8eb4SJonas Devlieghere } 447a842950bSJonas Devlieghere case eReproducerProviderSymbolFiles: { 448a842950bSJonas Devlieghere Expected<std::string> symbol_files = 449a842950bSJonas Devlieghere loader->LoadBuffer<SymbolFileProvider>(); 450a842950bSJonas Devlieghere if (!symbol_files) { 451a842950bSJonas Devlieghere SetError(result, symbol_files.takeError()); 452a842950bSJonas Devlieghere return false; 453a842950bSJonas Devlieghere } 454a842950bSJonas Devlieghere 455a842950bSJonas Devlieghere std::vector<SymbolFileProvider::Entry> entries; 456a842950bSJonas Devlieghere llvm::yaml::Input yin(*symbol_files); 457a842950bSJonas Devlieghere yin >> entries; 458a842950bSJonas Devlieghere 459a842950bSJonas Devlieghere for (const auto &entry : entries) { 460a842950bSJonas Devlieghere result.AppendMessageWithFormat("- uuid: %s\n", 461a842950bSJonas Devlieghere entry.uuid.c_str()); 462a842950bSJonas Devlieghere result.AppendMessageWithFormat(" module path: %s\n", 463a842950bSJonas Devlieghere entry.module_path.c_str()); 464a842950bSJonas Devlieghere result.AppendMessageWithFormat(" symbol path: %s\n", 465a842950bSJonas Devlieghere entry.symbol_path.c_str()); 466a842950bSJonas Devlieghere } 467a842950bSJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 468a842950bSJonas Devlieghere return true; 469a842950bSJonas Devlieghere } 47097fc8eb4SJonas Devlieghere case eReproducerProviderVersion: { 471b2575da9SJonas Devlieghere Expected<std::string> version = loader->LoadBuffer<VersionProvider>(); 472b2575da9SJonas Devlieghere if (!version) { 473b2575da9SJonas Devlieghere SetError(result, version.takeError()); 47497fc8eb4SJonas Devlieghere return false; 47597fc8eb4SJonas Devlieghere } 476b2575da9SJonas Devlieghere result.AppendMessage(*version); 47797fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 47897fc8eb4SJonas Devlieghere return true; 47997fc8eb4SJonas Devlieghere } 480f4f12012SJonas Devlieghere case eReproducerProviderWorkingDirectory: { 481f4f12012SJonas Devlieghere Expected<std::string> cwd = 48273af341bSJonas Devlieghere repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader); 483f4f12012SJonas Devlieghere if (!cwd) { 484f4f12012SJonas Devlieghere SetError(result, cwd.takeError()); 485f4f12012SJonas Devlieghere return false; 486f4f12012SJonas Devlieghere } 487f4f12012SJonas Devlieghere result.AppendMessage(*cwd); 488f4f12012SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 489f4f12012SJonas Devlieghere return true; 490f4f12012SJonas Devlieghere } 49173af341bSJonas Devlieghere case eReproducerProviderHomeDirectory: { 49273af341bSJonas Devlieghere Expected<std::string> home = 49373af341bSJonas Devlieghere repro::GetDirectoryFrom<HomeDirectoryProvider>(loader); 49473af341bSJonas Devlieghere if (!home) { 49573af341bSJonas Devlieghere SetError(result, home.takeError()); 49673af341bSJonas Devlieghere return false; 49773af341bSJonas Devlieghere } 49873af341bSJonas Devlieghere result.AppendMessage(*home); 49973af341bSJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 50073af341bSJonas Devlieghere return true; 50173af341bSJonas Devlieghere } 50297fc8eb4SJonas Devlieghere case eReproducerProviderCommands: { 5031d41d1bcSEric Christopher std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader = 5041d41d1bcSEric Christopher repro::MultiLoader<repro::CommandProvider>::Create(loader); 5051d41d1bcSEric Christopher if (!multi_loader) { 50697fc8eb4SJonas Devlieghere SetError(result, 5074016c6b0SJonas Devlieghere make_error<StringError>("Unable to create command loader.", 5084016c6b0SJonas Devlieghere llvm::inconvertibleErrorCode())); 50997fc8eb4SJonas Devlieghere return false; 51097fc8eb4SJonas Devlieghere } 51197fc8eb4SJonas Devlieghere 51297fc8eb4SJonas Devlieghere // Iterate over the command files and dump them. 5131d41d1bcSEric Christopher llvm::Optional<std::string> command_file; 5141d41d1bcSEric Christopher while ((command_file = multi_loader->GetNextFile())) { 51597fc8eb4SJonas Devlieghere if (!command_file) 51697fc8eb4SJonas Devlieghere break; 51797fc8eb4SJonas Devlieghere 51897fc8eb4SJonas Devlieghere auto command_buffer = llvm::MemoryBuffer::getFile(*command_file); 51997fc8eb4SJonas Devlieghere if (auto err = command_buffer.getError()) { 52097fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(err)); 52197fc8eb4SJonas Devlieghere return false; 52297fc8eb4SJonas Devlieghere } 52397fc8eb4SJonas Devlieghere result.AppendMessage((*command_buffer)->getBuffer()); 52497fc8eb4SJonas Devlieghere } 52597fc8eb4SJonas Devlieghere 52697fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 52797fc8eb4SJonas Devlieghere return true; 52897fc8eb4SJonas Devlieghere } 52997fc8eb4SJonas Devlieghere case eReproducerProviderGDB: { 5301d41d1bcSEric Christopher std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> 5311d41d1bcSEric Christopher multi_loader = 5321d41d1bcSEric Christopher repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader); 5334016c6b0SJonas Devlieghere 5344016c6b0SJonas Devlieghere if (!multi_loader) { 5354016c6b0SJonas Devlieghere SetError(result, 5364016c6b0SJonas Devlieghere make_error<StringError>("Unable to create GDB loader.", 5374016c6b0SJonas Devlieghere llvm::inconvertibleErrorCode())); 5384016c6b0SJonas Devlieghere return false; 5394016c6b0SJonas Devlieghere } 5404016c6b0SJonas Devlieghere 5411d41d1bcSEric Christopher llvm::Optional<std::string> gdb_file; 5421d41d1bcSEric Christopher while ((gdb_file = multi_loader->GetNextFile())) { 5432451cbf0SJonas Devlieghere if (llvm::Expected<std::vector<GDBRemotePacket>> packets = 5442451cbf0SJonas Devlieghere ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) { 5452451cbf0SJonas Devlieghere for (GDBRemotePacket &packet : *packets) { 5468fc8d3feSJonas Devlieghere packet.Dump(result.GetOutputStream()); 5478fc8d3feSJonas Devlieghere } 5482451cbf0SJonas Devlieghere } else { 5492451cbf0SJonas Devlieghere SetError(result, packets.takeError()); 5502451cbf0SJonas Devlieghere return false; 5512451cbf0SJonas Devlieghere } 5522451cbf0SJonas Devlieghere } 5532451cbf0SJonas Devlieghere 5542451cbf0SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 5552451cbf0SJonas Devlieghere return true; 5562451cbf0SJonas Devlieghere } 5572451cbf0SJonas Devlieghere case eReproducerProviderProcessInfo: { 5582451cbf0SJonas Devlieghere std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>> 5592451cbf0SJonas Devlieghere multi_loader = 5602451cbf0SJonas Devlieghere repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader); 5612451cbf0SJonas Devlieghere 5622451cbf0SJonas Devlieghere if (!multi_loader) { 5632451cbf0SJonas Devlieghere SetError(result, make_error<StringError>( 5642451cbf0SJonas Devlieghere llvm::inconvertibleErrorCode(), 5652451cbf0SJonas Devlieghere "Unable to create process info loader.")); 5662451cbf0SJonas Devlieghere return false; 5672451cbf0SJonas Devlieghere } 5682451cbf0SJonas Devlieghere 5692451cbf0SJonas Devlieghere llvm::Optional<std::string> process_file; 5702451cbf0SJonas Devlieghere while ((process_file = multi_loader->GetNextFile())) { 5712451cbf0SJonas Devlieghere if (llvm::Expected<ProcessInstanceInfoList> infos = 5722451cbf0SJonas Devlieghere ReadFromYAML<ProcessInstanceInfoList>(*process_file)) { 5732451cbf0SJonas Devlieghere for (ProcessInstanceInfo info : *infos) 5742451cbf0SJonas Devlieghere info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver()); 5752451cbf0SJonas Devlieghere } else { 5762451cbf0SJonas Devlieghere SetError(result, infos.takeError()); 5772451cbf0SJonas Devlieghere return false; 5782451cbf0SJonas Devlieghere } 5791d41d1bcSEric Christopher } 5808fc8d3feSJonas Devlieghere 58197fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 58297fc8eb4SJonas Devlieghere return true; 58397fc8eb4SJonas Devlieghere } 58497fc8eb4SJonas Devlieghere case eReproducerProviderNone: 58597fc8eb4SJonas Devlieghere result.SetError("No valid provider specified."); 58697fc8eb4SJonas Devlieghere return false; 58797fc8eb4SJonas Devlieghere } 58897fc8eb4SJonas Devlieghere 58997fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 59097fc8eb4SJonas Devlieghere return result.Succeeded(); 59197fc8eb4SJonas Devlieghere } 59297fc8eb4SJonas Devlieghere 59397fc8eb4SJonas Devlieghere private: 59497fc8eb4SJonas Devlieghere CommandOptions m_options; 59597fc8eb4SJonas Devlieghere }; 59697fc8eb4SJonas Devlieghere 597*37469061SJonas Devlieghere class CommandObjectReproducerVerify : public CommandObjectParsed { 598*37469061SJonas Devlieghere public: 599*37469061SJonas Devlieghere CommandObjectReproducerVerify(CommandInterpreter &interpreter) 600*37469061SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer verify", 601*37469061SJonas Devlieghere "Verify the contents of a reproducer. " 602*37469061SJonas Devlieghere "If no reproducer is specified during replay, it " 603*37469061SJonas Devlieghere "verifies the content of the current reproducer.", 604*37469061SJonas Devlieghere nullptr) {} 605*37469061SJonas Devlieghere 606*37469061SJonas Devlieghere ~CommandObjectReproducerVerify() override = default; 607*37469061SJonas Devlieghere 608*37469061SJonas Devlieghere Options *GetOptions() override { return &m_options; } 609*37469061SJonas Devlieghere 610*37469061SJonas Devlieghere class CommandOptions : public Options { 611*37469061SJonas Devlieghere public: 612*37469061SJonas Devlieghere CommandOptions() : Options(), file() {} 613*37469061SJonas Devlieghere 614*37469061SJonas Devlieghere ~CommandOptions() override = default; 615*37469061SJonas Devlieghere 616*37469061SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 617*37469061SJonas Devlieghere ExecutionContext *execution_context) override { 618*37469061SJonas Devlieghere Status error; 619*37469061SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 620*37469061SJonas Devlieghere 621*37469061SJonas Devlieghere switch (short_option) { 622*37469061SJonas Devlieghere case 'f': 623*37469061SJonas Devlieghere file.SetFile(option_arg, FileSpec::Style::native); 624*37469061SJonas Devlieghere FileSystem::Instance().Resolve(file); 625*37469061SJonas Devlieghere break; 626*37469061SJonas Devlieghere default: 627*37469061SJonas Devlieghere llvm_unreachable("Unimplemented option"); 628*37469061SJonas Devlieghere } 629*37469061SJonas Devlieghere 630*37469061SJonas Devlieghere return error; 631*37469061SJonas Devlieghere } 632*37469061SJonas Devlieghere 633*37469061SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 634*37469061SJonas Devlieghere file.Clear(); 635*37469061SJonas Devlieghere } 636*37469061SJonas Devlieghere 637*37469061SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 638*37469061SJonas Devlieghere return makeArrayRef(g_reproducer_verify_options); 639*37469061SJonas Devlieghere } 640*37469061SJonas Devlieghere 641*37469061SJonas Devlieghere FileSpec file; 642*37469061SJonas Devlieghere }; 643*37469061SJonas Devlieghere 644*37469061SJonas Devlieghere protected: 645*37469061SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 646*37469061SJonas Devlieghere if (!command.empty()) { 647*37469061SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 648*37469061SJonas Devlieghere m_cmd_name.c_str()); 649*37469061SJonas Devlieghere return false; 650*37469061SJonas Devlieghere } 651*37469061SJonas Devlieghere 652*37469061SJonas Devlieghere llvm::Optional<Loader> loader_storage; 653*37469061SJonas Devlieghere Loader *loader = 654*37469061SJonas Devlieghere GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); 655*37469061SJonas Devlieghere if (!loader) 656*37469061SJonas Devlieghere return false; 657*37469061SJonas Devlieghere 658*37469061SJonas Devlieghere bool errors = false; 659*37469061SJonas Devlieghere auto error_callback = [&](llvm::StringRef error) { 660*37469061SJonas Devlieghere errors = true; 661*37469061SJonas Devlieghere result.AppendError(error); 662*37469061SJonas Devlieghere }; 663*37469061SJonas Devlieghere 664*37469061SJonas Devlieghere bool warnings = false; 665*37469061SJonas Devlieghere auto warning_callback = [&](llvm::StringRef warning) { 666*37469061SJonas Devlieghere warnings = true; 667*37469061SJonas Devlieghere result.AppendWarning(warning); 668*37469061SJonas Devlieghere }; 669*37469061SJonas Devlieghere 670*37469061SJonas Devlieghere auto note_callback = [&](llvm::StringRef warning) { 671*37469061SJonas Devlieghere result.AppendMessage(warning); 672*37469061SJonas Devlieghere }; 673*37469061SJonas Devlieghere 674*37469061SJonas Devlieghere Verifier verifier(loader); 675*37469061SJonas Devlieghere verifier.Verify(error_callback, warning_callback, note_callback); 676*37469061SJonas Devlieghere 677*37469061SJonas Devlieghere if (warnings || errors) { 678*37469061SJonas Devlieghere result.AppendMessage("reproducer verification failed"); 679*37469061SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 680*37469061SJonas Devlieghere } else { 681*37469061SJonas Devlieghere result.AppendMessage("reproducer verification succeeded"); 682*37469061SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 683*37469061SJonas Devlieghere } 684*37469061SJonas Devlieghere 685*37469061SJonas Devlieghere return result.Succeeded(); 686*37469061SJonas Devlieghere } 687*37469061SJonas Devlieghere 688*37469061SJonas Devlieghere private: 689*37469061SJonas Devlieghere CommandOptions m_options; 690*37469061SJonas Devlieghere }; 691*37469061SJonas Devlieghere 6929e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer( 6939e046f02SJonas Devlieghere CommandInterpreter &interpreter) 694973d66eeSJonas Devlieghere : CommandObjectMultiword( 695973d66eeSJonas Devlieghere interpreter, "reproducer", 696c8dfe907SJonas Devlieghere "Commands for manipulating reproducers. Reproducers make it " 697c8dfe907SJonas Devlieghere "possible " 69864b7d955SJonas Devlieghere "to capture full debug sessions with all its dependencies. The " 69964b7d955SJonas Devlieghere "resulting reproducer is used to replay the debug session while " 70064b7d955SJonas Devlieghere "debugging the debugger.\n" 70164b7d955SJonas Devlieghere "Because reproducers need the whole the debug session from " 70264b7d955SJonas Devlieghere "beginning to end, you need to launch the debugger in capture or " 70364b7d955SJonas Devlieghere "replay mode, commonly though the command line driver.\n" 70464b7d955SJonas Devlieghere "Reproducers are unrelated record-replay debugging, as you cannot " 70564b7d955SJonas Devlieghere "interact with the debugger during replay.\n", 706130ec068SJonas Devlieghere "reproducer <subcommand> [<subcommand-options>]") { 7079e046f02SJonas Devlieghere LoadSubCommand( 7089e046f02SJonas Devlieghere "generate", 7099e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 71015eacd74SJonas Devlieghere LoadSubCommand("status", CommandObjectSP( 71115eacd74SJonas Devlieghere new CommandObjectReproducerStatus(interpreter))); 71297fc8eb4SJonas Devlieghere LoadSubCommand("dump", 71397fc8eb4SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerDump(interpreter))); 714*37469061SJonas Devlieghere LoadSubCommand("verify", CommandObjectSP( 715*37469061SJonas Devlieghere new CommandObjectReproducerVerify(interpreter))); 716c8dfe907SJonas Devlieghere LoadSubCommand("xcrash", CommandObjectSP( 717c8dfe907SJonas Devlieghere new CommandObjectReproducerXCrash(interpreter))); 7189e046f02SJonas Devlieghere } 7199e046f02SJonas Devlieghere 7209e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default; 721