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 11*97fc8eb4SJonas Devlieghere #include "lldb/Host/OptionParser.h" 129e046f02SJonas Devlieghere #include "lldb/Utility/Reproducer.h" 139e046f02SJonas Devlieghere 14df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 159e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 169e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h" 179e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionGroupBoolean.h" 189e046f02SJonas Devlieghere 199e046f02SJonas Devlieghere using namespace lldb; 20*97fc8eb4SJonas Devlieghere using namespace llvm; 219e046f02SJonas Devlieghere using namespace lldb_private; 22*97fc8eb4SJonas Devlieghere using namespace lldb_private::repro; 23*97fc8eb4SJonas Devlieghere 24*97fc8eb4SJonas Devlieghere enum ReproducerProvider { 25*97fc8eb4SJonas Devlieghere eReproducerProviderCommands, 26*97fc8eb4SJonas Devlieghere eReproducerProviderFiles, 27*97fc8eb4SJonas Devlieghere eReproducerProviderGDB, 28*97fc8eb4SJonas Devlieghere eReproducerProviderVersion, 29*97fc8eb4SJonas Devlieghere eReproducerProviderNone 30*97fc8eb4SJonas Devlieghere }; 31*97fc8eb4SJonas Devlieghere 32*97fc8eb4SJonas Devlieghere static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { 33*97fc8eb4SJonas Devlieghere { 34*97fc8eb4SJonas Devlieghere eReproducerProviderCommands, 35*97fc8eb4SJonas Devlieghere "commands", 36*97fc8eb4SJonas Devlieghere "Command Interpreter Commands", 37*97fc8eb4SJonas Devlieghere }, 38*97fc8eb4SJonas Devlieghere { 39*97fc8eb4SJonas Devlieghere eReproducerProviderFiles, 40*97fc8eb4SJonas Devlieghere "files", 41*97fc8eb4SJonas Devlieghere "Files", 42*97fc8eb4SJonas Devlieghere }, 43*97fc8eb4SJonas Devlieghere { 44*97fc8eb4SJonas Devlieghere eReproducerProviderGDB, 45*97fc8eb4SJonas Devlieghere "gdb", 46*97fc8eb4SJonas Devlieghere "GDB Remote Packets", 47*97fc8eb4SJonas Devlieghere }, 48*97fc8eb4SJonas Devlieghere { 49*97fc8eb4SJonas Devlieghere eReproducerProviderVersion, 50*97fc8eb4SJonas Devlieghere "version", 51*97fc8eb4SJonas Devlieghere "Version", 52*97fc8eb4SJonas Devlieghere }, 53*97fc8eb4SJonas Devlieghere { 54*97fc8eb4SJonas Devlieghere eReproducerProviderNone, 55*97fc8eb4SJonas Devlieghere "none", 56*97fc8eb4SJonas Devlieghere "None", 57*97fc8eb4SJonas Devlieghere }, 58*97fc8eb4SJonas Devlieghere }; 59*97fc8eb4SJonas Devlieghere 60*97fc8eb4SJonas Devlieghere static constexpr OptionEnumValues ReproducerProviderType() { 61*97fc8eb4SJonas Devlieghere return OptionEnumValues(g_reproducer_provider_type); 62*97fc8eb4SJonas Devlieghere } 63*97fc8eb4SJonas Devlieghere 64*97fc8eb4SJonas Devlieghere #define LLDB_OPTIONS_reproducer 65*97fc8eb4SJonas Devlieghere #include "CommandOptions.inc" 669e046f02SJonas Devlieghere 679e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed { 689e046f02SJonas Devlieghere public: 699e046f02SJonas Devlieghere CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 70973d66eeSJonas Devlieghere : CommandObjectParsed( 71973d66eeSJonas Devlieghere interpreter, "reproducer generate", 72973d66eeSJonas Devlieghere "Generate reproducer on disk. When the debugger is in capture " 73973d66eeSJonas Devlieghere "mode, this command will output the reproducer to a directory on " 74973d66eeSJonas Devlieghere "disk. In replay mode this command in a no-op.", 75973d66eeSJonas Devlieghere nullptr) {} 769e046f02SJonas Devlieghere 779e046f02SJonas Devlieghere ~CommandObjectReproducerGenerate() override = default; 789e046f02SJonas Devlieghere 799e046f02SJonas Devlieghere protected: 809e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 819e046f02SJonas Devlieghere if (!command.empty()) { 829e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 839e046f02SJonas Devlieghere m_cmd_name.c_str()); 849e046f02SJonas Devlieghere return false; 859e046f02SJonas Devlieghere } 869e046f02SJonas Devlieghere 87*97fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 889e046f02SJonas Devlieghere if (auto generator = r.GetGenerator()) { 899e046f02SJonas Devlieghere generator->Keep(); 902dca6538SJonas Devlieghere } else if (r.GetLoader()) { 912dca6538SJonas Devlieghere // Make this operation a NOP in replay mode. 922dca6538SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 932dca6538SJonas Devlieghere return result.Succeeded(); 949e046f02SJonas Devlieghere } else { 959e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer generator"); 962dca6538SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 979e046f02SJonas Devlieghere return false; 989e046f02SJonas Devlieghere } 999e046f02SJonas Devlieghere 1009e046f02SJonas Devlieghere result.GetOutputStream() 1019e046f02SJonas Devlieghere << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 1021c5250abSJonas Devlieghere result.GetOutputStream() 1031c5250abSJonas Devlieghere << "Please have a look at the directory to assess if you're willing to " 1041c5250abSJonas Devlieghere "share the contained information.\n"; 1059e046f02SJonas Devlieghere 1069e046f02SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 1079e046f02SJonas Devlieghere return result.Succeeded(); 1089e046f02SJonas Devlieghere } 1099e046f02SJonas Devlieghere }; 1109e046f02SJonas Devlieghere 11115eacd74SJonas Devlieghere class CommandObjectReproducerStatus : public CommandObjectParsed { 1129e046f02SJonas Devlieghere public: 11315eacd74SJonas Devlieghere CommandObjectReproducerStatus(CommandInterpreter &interpreter) 114973d66eeSJonas Devlieghere : CommandObjectParsed( 115973d66eeSJonas Devlieghere interpreter, "reproducer status", 116973d66eeSJonas Devlieghere "Show the current reproducer status. In capture mode the debugger " 117973d66eeSJonas Devlieghere "is collecting all the information it needs to create a " 118973d66eeSJonas Devlieghere "reproducer. In replay mode the reproducer is replaying a " 119973d66eeSJonas Devlieghere "reproducer. When the reproducers are off, no data is collected " 120973d66eeSJonas Devlieghere "and no reproducer can be generated.", 121973d66eeSJonas Devlieghere nullptr) {} 1229e046f02SJonas Devlieghere 12315eacd74SJonas Devlieghere ~CommandObjectReproducerStatus() override = default; 1249e046f02SJonas Devlieghere 1259e046f02SJonas Devlieghere protected: 1269e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 12715eacd74SJonas Devlieghere if (!command.empty()) { 12815eacd74SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 1299e046f02SJonas Devlieghere m_cmd_name.c_str()); 1309e046f02SJonas Devlieghere return false; 1319e046f02SJonas Devlieghere } 1329e046f02SJonas Devlieghere 133*97fc8eb4SJonas Devlieghere auto &r = Reproducer::Instance(); 13452f8f343SZachary Turner if (r.GetGenerator()) { 13515eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in capture mode.\n"; 13652f8f343SZachary Turner } else if (r.GetLoader()) { 13715eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is in replay mode.\n"; 13815eacd74SJonas Devlieghere } else { 13915eacd74SJonas Devlieghere result.GetOutputStream() << "Reproducer is off.\n"; 1409e046f02SJonas Devlieghere } 1419e046f02SJonas Devlieghere 14215eacd74SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 1439e046f02SJonas Devlieghere return result.Succeeded(); 1449e046f02SJonas Devlieghere } 1459e046f02SJonas Devlieghere }; 1469e046f02SJonas Devlieghere 147*97fc8eb4SJonas Devlieghere static void SetError(CommandReturnObject &result, Error err) { 148*97fc8eb4SJonas Devlieghere result.GetErrorStream().Printf("error: %s\n", 149*97fc8eb4SJonas Devlieghere toString(std::move(err)).c_str()); 150*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 151*97fc8eb4SJonas Devlieghere } 152*97fc8eb4SJonas Devlieghere 153*97fc8eb4SJonas Devlieghere class CommandObjectReproducerDump : public CommandObjectParsed { 154*97fc8eb4SJonas Devlieghere public: 155*97fc8eb4SJonas Devlieghere CommandObjectReproducerDump(CommandInterpreter &interpreter) 156*97fc8eb4SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer dump", 157*97fc8eb4SJonas Devlieghere "Dump the information contained in a reproducer.", 158*97fc8eb4SJonas Devlieghere nullptr) {} 159*97fc8eb4SJonas Devlieghere 160*97fc8eb4SJonas Devlieghere ~CommandObjectReproducerDump() override = default; 161*97fc8eb4SJonas Devlieghere 162*97fc8eb4SJonas Devlieghere Options *GetOptions() override { return &m_options; } 163*97fc8eb4SJonas Devlieghere 164*97fc8eb4SJonas Devlieghere class CommandOptions : public Options { 165*97fc8eb4SJonas Devlieghere public: 166*97fc8eb4SJonas Devlieghere CommandOptions() : Options(), file() {} 167*97fc8eb4SJonas Devlieghere 168*97fc8eb4SJonas Devlieghere ~CommandOptions() override = default; 169*97fc8eb4SJonas Devlieghere 170*97fc8eb4SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 171*97fc8eb4SJonas Devlieghere ExecutionContext *execution_context) override { 172*97fc8eb4SJonas Devlieghere Status error; 173*97fc8eb4SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 174*97fc8eb4SJonas Devlieghere 175*97fc8eb4SJonas Devlieghere switch (short_option) { 176*97fc8eb4SJonas Devlieghere case 'f': 177*97fc8eb4SJonas Devlieghere file.SetFile(option_arg, FileSpec::Style::native); 178*97fc8eb4SJonas Devlieghere FileSystem::Instance().Resolve(file); 179*97fc8eb4SJonas Devlieghere break; 180*97fc8eb4SJonas Devlieghere case 'p': 181*97fc8eb4SJonas Devlieghere provider = (ReproducerProvider)OptionArgParser::ToOptionEnum( 182*97fc8eb4SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 183*97fc8eb4SJonas Devlieghere if (!error.Success()) 184*97fc8eb4SJonas Devlieghere error.SetErrorStringWithFormat("unrecognized value for provider '%s'", 185*97fc8eb4SJonas Devlieghere option_arg.str().c_str()); 186*97fc8eb4SJonas Devlieghere break; 187*97fc8eb4SJonas Devlieghere default: 188*97fc8eb4SJonas Devlieghere llvm_unreachable("Unimplemented option"); 189*97fc8eb4SJonas Devlieghere } 190*97fc8eb4SJonas Devlieghere 191*97fc8eb4SJonas Devlieghere return error; 192*97fc8eb4SJonas Devlieghere } 193*97fc8eb4SJonas Devlieghere 194*97fc8eb4SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 195*97fc8eb4SJonas Devlieghere file.Clear(); 196*97fc8eb4SJonas Devlieghere provider = eReproducerProviderNone; 197*97fc8eb4SJonas Devlieghere } 198*97fc8eb4SJonas Devlieghere 199*97fc8eb4SJonas Devlieghere ArrayRef<OptionDefinition> GetDefinitions() override { 200*97fc8eb4SJonas Devlieghere return makeArrayRef(g_reproducer_options); 201*97fc8eb4SJonas Devlieghere } 202*97fc8eb4SJonas Devlieghere 203*97fc8eb4SJonas Devlieghere FileSpec file; 204*97fc8eb4SJonas Devlieghere ReproducerProvider provider = eReproducerProviderNone; 205*97fc8eb4SJonas Devlieghere }; 206*97fc8eb4SJonas Devlieghere 207*97fc8eb4SJonas Devlieghere protected: 208*97fc8eb4SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 209*97fc8eb4SJonas Devlieghere if (!command.empty()) { 210*97fc8eb4SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 211*97fc8eb4SJonas Devlieghere m_cmd_name.c_str()); 212*97fc8eb4SJonas Devlieghere return false; 213*97fc8eb4SJonas Devlieghere } 214*97fc8eb4SJonas Devlieghere 215*97fc8eb4SJonas Devlieghere // If no reproducer path is specified, use the loader currently used for 216*97fc8eb4SJonas Devlieghere // replay. Otherwise create a new loader just for dumping. 217*97fc8eb4SJonas Devlieghere llvm::Optional<Loader> loader_storage; 218*97fc8eb4SJonas Devlieghere Loader *loader = nullptr; 219*97fc8eb4SJonas Devlieghere if (!m_options.file) { 220*97fc8eb4SJonas Devlieghere loader = Reproducer::Instance().GetLoader(); 221*97fc8eb4SJonas Devlieghere if (loader == nullptr) { 222*97fc8eb4SJonas Devlieghere result.SetError( 223*97fc8eb4SJonas Devlieghere "Not specifying a reproducer is only support during replay."); 224*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 225*97fc8eb4SJonas Devlieghere return false; 226*97fc8eb4SJonas Devlieghere } 227*97fc8eb4SJonas Devlieghere } else { 228*97fc8eb4SJonas Devlieghere loader_storage.emplace(m_options.file); 229*97fc8eb4SJonas Devlieghere loader = &(*loader_storage); 230*97fc8eb4SJonas Devlieghere if (Error err = loader->LoadIndex()) { 231*97fc8eb4SJonas Devlieghere SetError(result, std::move(err)); 232*97fc8eb4SJonas Devlieghere return false; 233*97fc8eb4SJonas Devlieghere } 234*97fc8eb4SJonas Devlieghere } 235*97fc8eb4SJonas Devlieghere 236*97fc8eb4SJonas Devlieghere // If we get here we should have a valid loader. 237*97fc8eb4SJonas Devlieghere assert(loader); 238*97fc8eb4SJonas Devlieghere 239*97fc8eb4SJonas Devlieghere switch (m_options.provider) { 240*97fc8eb4SJonas Devlieghere case eReproducerProviderFiles: { 241*97fc8eb4SJonas Devlieghere FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>(); 242*97fc8eb4SJonas Devlieghere 243*97fc8eb4SJonas Devlieghere // Read the VFS mapping. 244*97fc8eb4SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = 245*97fc8eb4SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); 246*97fc8eb4SJonas Devlieghere if (!buffer) { 247*97fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(buffer.getError())); 248*97fc8eb4SJonas Devlieghere return false; 249*97fc8eb4SJonas Devlieghere } 250*97fc8eb4SJonas Devlieghere 251*97fc8eb4SJonas Devlieghere // Initialize a VFS from the given mapping. 252*97fc8eb4SJonas Devlieghere IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML( 253*97fc8eb4SJonas Devlieghere std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); 254*97fc8eb4SJonas Devlieghere 255*97fc8eb4SJonas Devlieghere // Dump the VFS to a buffer. 256*97fc8eb4SJonas Devlieghere std::string str; 257*97fc8eb4SJonas Devlieghere raw_string_ostream os(str); 258*97fc8eb4SJonas Devlieghere static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os); 259*97fc8eb4SJonas Devlieghere os.flush(); 260*97fc8eb4SJonas Devlieghere 261*97fc8eb4SJonas Devlieghere // Return the string. 262*97fc8eb4SJonas Devlieghere result.AppendMessage(str); 263*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 264*97fc8eb4SJonas Devlieghere return true; 265*97fc8eb4SJonas Devlieghere } 266*97fc8eb4SJonas Devlieghere case eReproducerProviderVersion: { 267*97fc8eb4SJonas Devlieghere FileSpec version_file = loader->GetFile<VersionProvider::Info>(); 268*97fc8eb4SJonas Devlieghere 269*97fc8eb4SJonas Devlieghere // Load the version info into a buffer. 270*97fc8eb4SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = 271*97fc8eb4SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(version_file.GetPath()); 272*97fc8eb4SJonas Devlieghere if (!buffer) { 273*97fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(buffer.getError())); 274*97fc8eb4SJonas Devlieghere return false; 275*97fc8eb4SJonas Devlieghere } 276*97fc8eb4SJonas Devlieghere 277*97fc8eb4SJonas Devlieghere // Return the version string. 278*97fc8eb4SJonas Devlieghere StringRef version = (*buffer)->getBuffer(); 279*97fc8eb4SJonas Devlieghere result.AppendMessage(version.str()); 280*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 281*97fc8eb4SJonas Devlieghere return true; 282*97fc8eb4SJonas Devlieghere } 283*97fc8eb4SJonas Devlieghere case eReproducerProviderCommands: { 284*97fc8eb4SJonas Devlieghere // Create a new command loader. 285*97fc8eb4SJonas Devlieghere std::unique_ptr<repro::CommandLoader> command_loader = 286*97fc8eb4SJonas Devlieghere repro::CommandLoader::Create(loader); 287*97fc8eb4SJonas Devlieghere if (!command_loader) { 288*97fc8eb4SJonas Devlieghere SetError(result, 289*97fc8eb4SJonas Devlieghere make_error<StringError>(llvm::inconvertibleErrorCode(), 290*97fc8eb4SJonas Devlieghere "Unable to create command loader.")); 291*97fc8eb4SJonas Devlieghere return false; 292*97fc8eb4SJonas Devlieghere } 293*97fc8eb4SJonas Devlieghere 294*97fc8eb4SJonas Devlieghere // Iterate over the command files and dump them. 295*97fc8eb4SJonas Devlieghere while (true) { 296*97fc8eb4SJonas Devlieghere llvm::Optional<std::string> command_file = 297*97fc8eb4SJonas Devlieghere command_loader->GetNextFile(); 298*97fc8eb4SJonas Devlieghere if (!command_file) 299*97fc8eb4SJonas Devlieghere break; 300*97fc8eb4SJonas Devlieghere 301*97fc8eb4SJonas Devlieghere auto command_buffer = llvm::MemoryBuffer::getFile(*command_file); 302*97fc8eb4SJonas Devlieghere if (auto err = command_buffer.getError()) { 303*97fc8eb4SJonas Devlieghere SetError(result, errorCodeToError(err)); 304*97fc8eb4SJonas Devlieghere return false; 305*97fc8eb4SJonas Devlieghere } 306*97fc8eb4SJonas Devlieghere result.AppendMessage((*command_buffer)->getBuffer()); 307*97fc8eb4SJonas Devlieghere } 308*97fc8eb4SJonas Devlieghere 309*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 310*97fc8eb4SJonas Devlieghere return true; 311*97fc8eb4SJonas Devlieghere } 312*97fc8eb4SJonas Devlieghere case eReproducerProviderGDB: { 313*97fc8eb4SJonas Devlieghere // FIXME: Dumping the GDB remote packets means moving the 314*97fc8eb4SJonas Devlieghere // (de)serialization code out of the GDB-remote plugin. 315*97fc8eb4SJonas Devlieghere result.AppendMessage("Dumping GDB remote packets isn't implemented yet."); 316*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 317*97fc8eb4SJonas Devlieghere return true; 318*97fc8eb4SJonas Devlieghere } 319*97fc8eb4SJonas Devlieghere case eReproducerProviderNone: 320*97fc8eb4SJonas Devlieghere result.SetError("No valid provider specified."); 321*97fc8eb4SJonas Devlieghere return false; 322*97fc8eb4SJonas Devlieghere } 323*97fc8eb4SJonas Devlieghere 324*97fc8eb4SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 325*97fc8eb4SJonas Devlieghere return result.Succeeded(); 326*97fc8eb4SJonas Devlieghere } 327*97fc8eb4SJonas Devlieghere 328*97fc8eb4SJonas Devlieghere private: 329*97fc8eb4SJonas Devlieghere CommandOptions m_options; 330*97fc8eb4SJonas Devlieghere }; 331*97fc8eb4SJonas Devlieghere 3329e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer( 3339e046f02SJonas Devlieghere CommandInterpreter &interpreter) 334973d66eeSJonas Devlieghere : CommandObjectMultiword( 335973d66eeSJonas Devlieghere interpreter, "reproducer", 336130ec068SJonas Devlieghere "Commands for manipulate the reproducer functionality.", 337130ec068SJonas Devlieghere "reproducer <subcommand> [<subcommand-options>]") { 3389e046f02SJonas Devlieghere LoadSubCommand( 3399e046f02SJonas Devlieghere "generate", 3409e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 34115eacd74SJonas Devlieghere LoadSubCommand("status", CommandObjectSP( 34215eacd74SJonas Devlieghere new CommandObjectReproducerStatus(interpreter))); 343*97fc8eb4SJonas Devlieghere LoadSubCommand("dump", 344*97fc8eb4SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerDump(interpreter))); 3459e046f02SJonas Devlieghere } 3469e046f02SJonas Devlieghere 3479e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default; 348