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 #include "lldb/Interpreter/OptionGroupBoolean.h" 199e046f02SJonas Devlieghere 209e046f02SJonas Devlieghere using namespace lldb; 2197fc8eb4SJonas Devlieghere using namespace llvm; 229e046f02SJonas Devlieghere using namespace lldb_private; 2397fc8eb4SJonas Devlieghere using namespace lldb_private::repro; 2497fc8eb4SJonas Devlieghere 2597fc8eb4SJonas Devlieghere enum ReproducerProvider { 2697fc8eb4SJonas Devlieghere eReproducerProviderCommands, 2797fc8eb4SJonas Devlieghere eReproducerProviderFiles, 2897fc8eb4SJonas Devlieghere eReproducerProviderGDB, 2997fc8eb4SJonas Devlieghere eReproducerProviderVersion, 30f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 3197fc8eb4SJonas Devlieghere eReproducerProviderNone 3297fc8eb4SJonas Devlieghere }; 3397fc8eb4SJonas Devlieghere 3497fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { 3597fc8eb4SJonas Devlieghere { 3697fc8eb4SJonas Devlieghere eReproducerProviderCommands, 3797fc8eb4SJonas Devlieghere "commands", 3897fc8eb4SJonas Devlieghere "Command Interpreter Commands", 3997fc8eb4SJonas Devlieghere }, 4097fc8eb4SJonas Devlieghere { 4197fc8eb4SJonas Devlieghere eReproducerProviderFiles, 4297fc8eb4SJonas Devlieghere "files", 4397fc8eb4SJonas Devlieghere "Files", 4497fc8eb4SJonas Devlieghere }, 4597fc8eb4SJonas Devlieghere { 4697fc8eb4SJonas Devlieghere eReproducerProviderGDB, 4797fc8eb4SJonas Devlieghere "gdb", 4897fc8eb4SJonas Devlieghere "GDB Remote Packets", 4997fc8eb4SJonas Devlieghere }, 5097fc8eb4SJonas Devlieghere { 5197fc8eb4SJonas Devlieghere eReproducerProviderVersion, 5297fc8eb4SJonas Devlieghere "version", 5397fc8eb4SJonas Devlieghere "Version", 5497fc8eb4SJonas Devlieghere }, 5597fc8eb4SJonas Devlieghere { 56f4f12012SJonas Devlieghere eReproducerProviderWorkingDirectory, 57f4f12012SJonas Devlieghere "cwd", 58f4f12012SJonas Devlieghere "Working Directory", 59f4f12012SJonas Devlieghere }, 60f4f12012SJonas Devlieghere { 6197fc8eb4SJonas Devlieghere eReproducerProviderNone, 6297fc8eb4SJonas Devlieghere "none", 6397fc8eb4SJonas Devlieghere "None", 6497fc8eb4SJonas Devlieghere }, 6597fc8eb4SJonas Devlieghere }; 6697fc8eb4SJonas Devlieghere 6797fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() { 6897fc8eb4SJonas Devlieghere return OptionEnumValues(g_reproducer_provider_type); 6997fc8eb4SJonas Devlieghere } 7097fc8eb4SJonas Devlieghere 7197fc8eb4SJonas Devlieghere #define LLDB_OPTIONS_reproducer 7297fc8eb4SJonas Devlieghere #include "CommandOptions.inc" 739e046f02SJonas Devlieghere 749e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed { 759e046f02SJonas Devlieghere public: 769e046f02SJonas Devlieghere CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 77973d66eeSJonas Devlieghere : CommandObjectParsed( 78973d66eeSJonas Devlieghere interpreter, "reproducer generate", 79973d66eeSJonas Devlieghere "Generate reproducer on disk. When the debugger is in capture " 80973d66eeSJonas Devlieghere "mode, this command will output the reproducer to a directory on " 81*0cf86da1SJonas Devlieghere "disk and quit. In replay mode this command in a no-op.", 82973d66eeSJonas Devlieghere nullptr) {} 839e046f02SJonas Devlieghere 849e046f02SJonas Devlieghere ~CommandObjectReproducerGenerate() override = default; 859e046f02SJonas Devlieghere 869e046f02SJonas Devlieghere protected: 879e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 889e046f02SJonas Devlieghere if (!command.empty()) { 899e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 909e046f02SJonas Devlieghere m_cmd_name.c_str()); 919e046f02SJonas Devlieghere return false; 929e046f02SJonas Devlieghere } 939e046f02SJonas Devlieghere 9497fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 959e046f02SJonas Devlieghere if (auto generator = r.GetGenerator()) { 969e046f02SJonas Devlieghere generator->Keep(); 97865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 982dca6538SJonas Devlieghere // Make this operation a NOP in replay mode. 992dca6538SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 1002dca6538SJonas Devlieghere return result.Succeeded(); 1019e046f02SJonas Devlieghere } else { 1029e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer generator"); 1032dca6538SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 1049e046f02SJonas Devlieghere return false; 1059e046f02SJonas Devlieghere } 1069e046f02SJonas Devlieghere 1079e046f02SJonas Devlieghere result.GetOutputStream() 1089e046f02SJonas Devlieghere << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 1091c5250abSJonas Devlieghere result.GetOutputStream() 1101c5250abSJonas Devlieghere << "Please have a look at the directory to assess if you're willing to " 1111c5250abSJonas Devlieghere "share the contained information.\n"; 1129e046f02SJonas Devlieghere 113*0cf86da1SJonas Devlieghere m_interpreter.BroadcastEvent( 114*0cf86da1SJonas Devlieghere CommandInterpreter::eBroadcastBitQuitCommandReceived); 115*0cf86da1SJonas Devlieghere result.SetStatus(eReturnStatusQuit); 1169e046f02SJonas Devlieghere return result.Succeeded(); 1179e046f02SJonas Devlieghere } 1189e046f02SJonas Devlieghere }; 1199e046f02SJonas Devlieghere 12015eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed { 1219e046f02SJonas Devlieghere public: 12215eacd74SJonas Devlieghere CommandObjectReproducerStatus(CommandInterpreter &interpreter) 123973d66eeSJonas Devlieghere : CommandObjectParsed( 124973d66eeSJonas Devlieghere interpreter, "reproducer status", 125973d66eeSJonas Devlieghere "Show the current reproducer status. In capture mode the debugger " 126973d66eeSJonas Devlieghere "is collecting all the information it needs to create a " 127973d66eeSJonas Devlieghere "reproducer. In replay mode the reproducer is replaying a " 128973d66eeSJonas Devlieghere "reproducer. When the reproducers are off, no data is collected " 129973d66eeSJonas Devlieghere "and no reproducer can be generated.", 130973d66eeSJonas Devlieghere nullptr) {} 1319e046f02SJonas Devlieghere 13215eacd74SJonas Devlieghere ~CommandObjectReproducerStatus() override = default; 1339e046f02SJonas Devlieghere 1349e046f02SJonas Devlieghere protected: 1359e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 13615eacd74SJonas Devlieghere if (!command.empty()) { 13715eacd74SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 1389e046f02SJonas Devlieghere m_cmd_name.c_str()); 1399e046f02SJonas Devlieghere return false; 1409e046f02SJonas Devlieghere } 1419e046f02SJonas Devlieghere 14297fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 143865cd093SJonas Devlieghere if (r.IsCapturing()) { 14415eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in capture mode.\n"; 145865cd093SJonas Devlieghere } else if (r.IsReplaying()) { 14615eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in replay mode.\n"; 14715eacd74SJonas Devlieghere } else { 14815eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is off.\n"; 1499e046f02SJonas Devlieghere } 1509e046f02SJonas Devlieghere 15115eacd74SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 1529e046f02SJonas Devlieghere return result.Succeeded(); 1539e046f02SJonas Devlieghere } 1549e046f02SJonas Devlieghere }; 1559e046f02SJonas Devlieghere 15697fc8eb4SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) { 15797fc8eb4SJonas Devlieghere result.GetErrorStream().Printf("error: %s\n", 15897fc8eb4SJonas Devlieghere toString(std::move(err)).c_str()); 15997fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 16097fc8eb4SJonas Devlieghere } 16197fc8eb4SJonas Devlieghere 16297fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed { 16397fc8eb4SJonas Devlieghere public: 16497fc8eb4SJonas Devlieghere CommandObjectReproducerDump(CommandInterpreter &interpreter) 16597fc8eb4SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer dump", 16664b7d955SJonas Devlieghere "Dump the information contained in a reproducer. " 16764b7d955SJonas Devlieghere "If no reproducer is specified during replay, it " 16864b7d955SJonas Devlieghere "dumps the content of the current reproducer.", 16997fc8eb4SJonas Devlieghere nullptr) {} 17097fc8eb4SJonas Devlieghere 17197fc8eb4SJonas Devlieghere ~CommandObjectReproducerDump() override = default; 17297fc8eb4SJonas Devlieghere 17397fc8eb4SJonas Devlieghere Options *GetOptions() override { return &m_options; } 17497fc8eb4SJonas Devlieghere 17597fc8eb4SJonas Devlieghere class CommandOptions : public Options { 17697fc8eb4SJonas Devlieghere public: 17797fc8eb4SJonas Devlieghere CommandOptions() : Options(), file() {} 17897fc8eb4SJonas Devlieghere 17997fc8eb4SJonas Devlieghere ~CommandOptions() override = default; 18097fc8eb4SJonas Devlieghere 18197fc8eb4SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 18297fc8eb4SJonas Devlieghere ExecutionContext *execution_context) override { 18397fc8eb4SJonas Devlieghere Status error; 18497fc8eb4SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 18597fc8eb4SJonas Devlieghere 18697fc8eb4SJonas Devlieghere switch (short_option) { 18797fc8eb4SJonas Devlieghere case 'f': 18897fc8eb4SJonas Devlieghere file.SetFile(option_arg, FileSpec::Style::native); 18997fc8eb4SJonas Devlieghere FileSystem::Instance().Resolve(file); 19097fc8eb4SJonas Devlieghere break; 19197fc8eb4SJonas Devlieghere case 'p': 19297fc8eb4SJonas Devlieghere provider = (ReproducerProvider)OptionArgParser::ToOptionEnum( 19397fc8eb4SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 19497fc8eb4SJonas Devlieghere if (!error.Success()) 19597fc8eb4SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for provider '%s'", 19697fc8eb4SJonas Devlieghere option_arg.str().c_str()); 19797fc8eb4SJonas Devlieghere break; 19897fc8eb4SJonas Devlieghere default: 19997fc8eb4SJonas Devlieghere llvm_unreachable("Unimplemented option"); 20097fc8eb4SJonas Devlieghere } 20197fc8eb4SJonas Devlieghere 20297fc8eb4SJonas Devlieghere return error; 20397fc8eb4SJonas Devlieghere } 20497fc8eb4SJonas Devlieghere 20597fc8eb4SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 20697fc8eb4SJonas Devlieghere file.Clear(); 20797fc8eb4SJonas Devlieghere provider = eReproducerProviderNone; 20897fc8eb4SJonas Devlieghere } 20997fc8eb4SJonas Devlieghere 21097fc8eb4SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 21197fc8eb4SJonas Devlieghere return makeArrayRef(g_reproducer_options); 21297fc8eb4SJonas Devlieghere } 21397fc8eb4SJonas Devlieghere 21497fc8eb4SJonas Devlieghere FileSpec file; 21597fc8eb4SJonas Devlieghere ReproducerProvider provider = eReproducerProviderNone; 21697fc8eb4SJonas Devlieghere }; 21797fc8eb4SJonas Devlieghere 21897fc8eb4SJonas Devlieghere protected: 21997fc8eb4SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 22097fc8eb4SJonas Devlieghere if (!command.empty()) { 22197fc8eb4SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 22297fc8eb4SJonas Devlieghere m_cmd_name.c_str()); 22397fc8eb4SJonas Devlieghere return false; 22497fc8eb4SJonas Devlieghere } 22597fc8eb4SJonas Devlieghere 22697fc8eb4SJonas Devlieghere // If no reproducer path is specified, use the loader currently used for 22797fc8eb4SJonas Devlieghere // replay. Otherwise create a new loader just for dumping. 22897fc8eb4SJonas Devlieghere llvm::Optional<Loader> loader_storage; 22997fc8eb4SJonas Devlieghere Loader *loader = nullptr; 23097fc8eb4SJonas Devlieghere if (!m_options.file) { 23197fc8eb4SJonas Devlieghere loader = Reproducer::Instance().GetLoader(); 23297fc8eb4SJonas Devlieghere if (loader == nullptr) { 23397fc8eb4SJonas Devlieghere result.SetError( 23497fc8eb4SJonas Devlieghere "Not specifying a reproducer is only support during replay."); 23597fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 23697fc8eb4SJonas Devlieghere return false; 23797fc8eb4SJonas Devlieghere } 23897fc8eb4SJonas Devlieghere } else { 23997fc8eb4SJonas Devlieghere loader_storage.emplace(m_options.file); 24097fc8eb4SJonas Devlieghere loader = &(*loader_storage); 24197fc8eb4SJonas Devlieghere if (Error err = loader->LoadIndex()) { 24297fc8eb4SJonas Devlieghere SetError(result, std::move(err)); 24397fc8eb4SJonas Devlieghere return false; 24497fc8eb4SJonas Devlieghere } 24597fc8eb4SJonas Devlieghere } 24697fc8eb4SJonas Devlieghere 24797fc8eb4SJonas Devlieghere // If we get here we should have a valid loader. 24897fc8eb4SJonas Devlieghere assert(loader); 24997fc8eb4SJonas Devlieghere 25097fc8eb4SJonas Devlieghere switch (m_options.provider) { 25197fc8eb4SJonas Devlieghere case eReproducerProviderFiles: { 25297fc8eb4SJonas Devlieghere FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>(); 25397fc8eb4SJonas Devlieghere 25497fc8eb4SJonas Devlieghere // Read the VFS mapping. 25597fc8eb4SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = 25697fc8eb4SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); 25797fc8eb4SJonas Devlieghere if (!buffer) { 25897fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(buffer.getError())); 25997fc8eb4SJonas Devlieghere return false; 26097fc8eb4SJonas Devlieghere } 26197fc8eb4SJonas Devlieghere 26297fc8eb4SJonas Devlieghere // Initialize a VFS from the given mapping. 26397fc8eb4SJonas Devlieghere IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML( 26497fc8eb4SJonas Devlieghere std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); 26597fc8eb4SJonas Devlieghere 26697fc8eb4SJonas Devlieghere // Dump the VFS to a buffer. 26797fc8eb4SJonas Devlieghere std::string str; 26897fc8eb4SJonas Devlieghere raw_string_ostream os(str); 26997fc8eb4SJonas Devlieghere static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os); 27097fc8eb4SJonas Devlieghere os.flush(); 27197fc8eb4SJonas Devlieghere 27297fc8eb4SJonas Devlieghere // Return the string. 27397fc8eb4SJonas Devlieghere result.AppendMessage(str); 27497fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 27597fc8eb4SJonas Devlieghere return true; 27697fc8eb4SJonas Devlieghere } 27797fc8eb4SJonas Devlieghere case eReproducerProviderVersion: { 278b2575da9SJonas Devlieghere Expected<std::string> version = loader->LoadBuffer<VersionProvider>(); 279b2575da9SJonas Devlieghere if (!version) { 280b2575da9SJonas Devlieghere SetError(result, version.takeError()); 28197fc8eb4SJonas Devlieghere return false; 28297fc8eb4SJonas Devlieghere } 283b2575da9SJonas Devlieghere result.AppendMessage(*version); 28497fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 28597fc8eb4SJonas Devlieghere return true; 28697fc8eb4SJonas Devlieghere } 287f4f12012SJonas Devlieghere case eReproducerProviderWorkingDirectory: { 288f4f12012SJonas Devlieghere Expected<std::string> cwd = 289f4f12012SJonas Devlieghere loader->LoadBuffer<WorkingDirectoryProvider>(); 290f4f12012SJonas Devlieghere if (!cwd) { 291f4f12012SJonas Devlieghere SetError(result, cwd.takeError()); 292f4f12012SJonas Devlieghere return false; 293f4f12012SJonas Devlieghere } 294f4f12012SJonas Devlieghere result.AppendMessage(*cwd); 295f4f12012SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 296f4f12012SJonas Devlieghere return true; 297f4f12012SJonas Devlieghere } 29897fc8eb4SJonas Devlieghere case eReproducerProviderCommands: { 29997fc8eb4SJonas Devlieghere // Create a new command loader. 30097fc8eb4SJonas Devlieghere std::unique_ptr<repro::CommandLoader> command_loader = 30197fc8eb4SJonas Devlieghere repro::CommandLoader::Create(loader); 30297fc8eb4SJonas Devlieghere if (!command_loader) { 30397fc8eb4SJonas Devlieghere SetError(result, 30497fc8eb4SJonas Devlieghere make_error<StringError>(llvm::inconvertibleErrorCode(), 30597fc8eb4SJonas Devlieghere "Unable to create command loader.")); 30697fc8eb4SJonas Devlieghere return false; 30797fc8eb4SJonas Devlieghere } 30897fc8eb4SJonas Devlieghere 30997fc8eb4SJonas Devlieghere // Iterate over the command files and dump them. 31097fc8eb4SJonas Devlieghere while (true) { 31197fc8eb4SJonas Devlieghere llvm::Optional<std::string> command_file = 31297fc8eb4SJonas Devlieghere command_loader->GetNextFile(); 31397fc8eb4SJonas Devlieghere if (!command_file) 31497fc8eb4SJonas Devlieghere break; 31597fc8eb4SJonas Devlieghere 31697fc8eb4SJonas Devlieghere auto command_buffer = llvm::MemoryBuffer::getFile(*command_file); 31797fc8eb4SJonas Devlieghere if (auto err = command_buffer.getError()) { 31897fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(err)); 31997fc8eb4SJonas Devlieghere return false; 32097fc8eb4SJonas Devlieghere } 32197fc8eb4SJonas Devlieghere result.AppendMessage((*command_buffer)->getBuffer()); 32297fc8eb4SJonas Devlieghere } 32397fc8eb4SJonas Devlieghere 32497fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 32597fc8eb4SJonas Devlieghere return true; 32697fc8eb4SJonas Devlieghere } 32797fc8eb4SJonas Devlieghere case eReproducerProviderGDB: { 3288fc8d3feSJonas Devlieghere FileSpec gdb_file = loader->GetFile<ProcessGDBRemoteProvider::Info>(); 3298fc8d3feSJonas Devlieghere auto error_or_file = MemoryBuffer::getFile(gdb_file.GetPath()); 3308fc8d3feSJonas Devlieghere if (auto err = error_or_file.getError()) { 3318fc8d3feSJonas Devlieghere SetError(result, errorCodeToError(err)); 3328fc8d3feSJonas Devlieghere return false; 3338fc8d3feSJonas Devlieghere } 3348fc8d3feSJonas Devlieghere 3358fc8d3feSJonas Devlieghere std::vector<GDBRemotePacket> packets; 3368fc8d3feSJonas Devlieghere yaml::Input yin((*error_or_file)->getBuffer()); 3378fc8d3feSJonas Devlieghere yin >> packets; 3388fc8d3feSJonas Devlieghere 3398fc8d3feSJonas Devlieghere if (auto err = yin.error()) { 3408fc8d3feSJonas Devlieghere SetError(result, errorCodeToError(err)); 3418fc8d3feSJonas Devlieghere return false; 3428fc8d3feSJonas Devlieghere } 3438fc8d3feSJonas Devlieghere 3448fc8d3feSJonas Devlieghere for (GDBRemotePacket &packet : packets) { 3458fc8d3feSJonas Devlieghere packet.Dump(result.GetOutputStream()); 3468fc8d3feSJonas Devlieghere } 3478fc8d3feSJonas Devlieghere 34897fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 34997fc8eb4SJonas Devlieghere return true; 35097fc8eb4SJonas Devlieghere } 35197fc8eb4SJonas Devlieghere case eReproducerProviderNone: 35297fc8eb4SJonas Devlieghere result.SetError("No valid provider specified."); 35397fc8eb4SJonas Devlieghere return false; 35497fc8eb4SJonas Devlieghere } 35597fc8eb4SJonas Devlieghere 35697fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 35797fc8eb4SJonas Devlieghere return result.Succeeded(); 35897fc8eb4SJonas Devlieghere } 35997fc8eb4SJonas Devlieghere 36097fc8eb4SJonas Devlieghere private: 36197fc8eb4SJonas Devlieghere CommandOptions m_options; 36297fc8eb4SJonas Devlieghere }; 36397fc8eb4SJonas Devlieghere 3649e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer( 3659e046f02SJonas Devlieghere CommandInterpreter &interpreter) 366973d66eeSJonas Devlieghere : CommandObjectMultiword( 367973d66eeSJonas Devlieghere interpreter, "reproducer", 36864b7d955SJonas Devlieghere "Commands for manipulating reproducers. Reproducers make it possible " 36964b7d955SJonas Devlieghere "to capture full debug sessions with all its dependencies. The " 37064b7d955SJonas Devlieghere "resulting reproducer is used to replay the debug session while " 37164b7d955SJonas Devlieghere "debugging the debugger.\n" 37264b7d955SJonas Devlieghere "Because reproducers need the whole the debug session from " 37364b7d955SJonas Devlieghere "beginning to end, you need to launch the debugger in capture or " 37464b7d955SJonas Devlieghere "replay mode, commonly though the command line driver.\n" 37564b7d955SJonas Devlieghere "Reproducers are unrelated record-replay debugging, as you cannot " 37664b7d955SJonas Devlieghere "interact with the debugger during replay.\n", 377130ec068SJonas Devlieghere "reproducer <subcommand> [<subcommand-options>]") { 3789e046f02SJonas Devlieghere LoadSubCommand( 3799e046f02SJonas Devlieghere "generate", 3809e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 38115eacd74SJonas Devlieghere LoadSubCommand("status", CommandObjectSP( 38215eacd74SJonas Devlieghere new CommandObjectReproducerStatus(interpreter))); 38397fc8eb4SJonas Devlieghere LoadSubCommand("dump", 38497fc8eb4SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerDump(interpreter))); 3859e046f02SJonas Devlieghere } 3869e046f02SJonas Devlieghere 3879e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default; 388