1 //===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CommandObjectReproducer.h" 11 12 #include "lldb/Utility/Reproducer.h" 13 14 #include "lldb/Interpreter/CommandInterpreter.h" 15 #include "lldb/Interpreter/CommandReturnObject.h" 16 #include "lldb/Interpreter/OptionArgParser.h" 17 #include "lldb/Interpreter/OptionGroupBoolean.h" 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 static void AppendErrorToResult(llvm::Error e, CommandReturnObject &result) { 23 std::string error_str = llvm::toString(std::move(e)); 24 result.AppendErrorWithFormat("%s", error_str.c_str()); 25 } 26 27 class CommandObjectReproducerCaptureEnable : public CommandObjectParsed { 28 public: 29 CommandObjectReproducerCaptureEnable(CommandInterpreter &interpreter) 30 : CommandObjectParsed(interpreter, "reproducer capture enable", 31 "Enable gathering information for reproducer", 32 nullptr) {} 33 34 ~CommandObjectReproducerCaptureEnable() override = default; 35 36 protected: 37 bool DoExecute(Args &command, CommandReturnObject &result) override { 38 if (!command.empty()) { 39 result.AppendErrorWithFormat("'%s' takes no arguments", 40 m_cmd_name.c_str()); 41 return false; 42 } 43 44 if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(true)) { 45 AppendErrorToResult(std::move(e), result); 46 return false; 47 } 48 49 result.SetStatus(eReturnStatusSuccessFinishNoResult); 50 return result.Succeeded(); 51 } 52 }; 53 54 class CommandObjectReproducerCaptureDisable : public CommandObjectParsed { 55 public: 56 CommandObjectReproducerCaptureDisable(CommandInterpreter &interpreter) 57 : CommandObjectParsed(interpreter, "reproducer capture enable", 58 "Disable gathering information for reproducer", 59 nullptr) {} 60 61 ~CommandObjectReproducerCaptureDisable() override = default; 62 63 protected: 64 bool DoExecute(Args &command, CommandReturnObject &result) override { 65 if (!command.empty()) { 66 result.AppendErrorWithFormat("'%s' takes no arguments", 67 m_cmd_name.c_str()); 68 return false; 69 } 70 71 if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(false)) { 72 AppendErrorToResult(std::move(e), result); 73 return false; 74 } 75 76 result.SetStatus(eReturnStatusSuccessFinishNoResult); 77 return result.Succeeded(); 78 } 79 }; 80 81 class CommandObjectReproducerGenerate : public CommandObjectParsed { 82 public: 83 CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 84 : CommandObjectParsed(interpreter, "reproducer generate", 85 "Generate reproducer on disk.", nullptr) {} 86 87 ~CommandObjectReproducerGenerate() override = default; 88 89 protected: 90 bool DoExecute(Args &command, CommandReturnObject &result) override { 91 if (!command.empty()) { 92 result.AppendErrorWithFormat("'%s' takes no arguments", 93 m_cmd_name.c_str()); 94 return false; 95 } 96 97 auto &r = repro::Reproducer::Instance(); 98 if (auto generator = r.GetGenerator()) { 99 generator->Keep(); 100 } else { 101 result.AppendErrorWithFormat("Unable to get the reproducer generator"); 102 return false; 103 } 104 105 result.GetOutputStream() 106 << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 107 108 result.SetStatus(eReturnStatusSuccessFinishResult); 109 return result.Succeeded(); 110 } 111 }; 112 113 class CommandObjectReproducerReplay : public CommandObjectParsed { 114 public: 115 CommandObjectReproducerReplay(CommandInterpreter &interpreter) 116 : CommandObjectParsed(interpreter, "reproducer replay", 117 "Replay a reproducer.", nullptr) { 118 CommandArgumentEntry arg1; 119 CommandArgumentData path_arg; 120 121 // Define the first (and only) variant of this arg. 122 path_arg.arg_type = eArgTypePath; 123 path_arg.arg_repetition = eArgRepeatPlain; 124 125 // There is only one variant this argument could be; put it into the 126 // argument entry. 127 arg1.push_back(path_arg); 128 129 // Push the data for the first argument into the m_arguments vector. 130 m_arguments.push_back(arg1); 131 } 132 133 ~CommandObjectReproducerReplay() override = default; 134 135 protected: 136 bool DoExecute(Args &command, CommandReturnObject &result) override { 137 if (command.empty()) { 138 result.AppendErrorWithFormat( 139 "'%s' takes a single argument: the reproducer path", 140 m_cmd_name.c_str()); 141 return false; 142 } 143 144 auto &r = repro::Reproducer::Instance(); 145 146 if (auto e = r.SetReplayReproducer(true)) { 147 std::string error_str = llvm::toString(std::move(e)); 148 result.AppendErrorWithFormat("%s", error_str.c_str()); 149 return false; 150 } 151 152 if (auto loader = r.GetLoader()) { 153 const char *repro_path = command.GetArgumentAtIndex(0); 154 if (auto e = loader->LoadIndex(FileSpec(repro_path))) { 155 std::string error_str = llvm::toString(std::move(e)); 156 result.AppendErrorWithFormat("Unable to load reproducer: %s", 157 error_str.c_str()); 158 return false; 159 } 160 } else { 161 result.AppendErrorWithFormat("Unable to get the reproducer loader"); 162 return false; 163 } 164 165 result.SetStatus(eReturnStatusSuccessFinishNoResult); 166 return result.Succeeded(); 167 } 168 }; 169 170 class CommandObjectReproducerCapture : public CommandObjectMultiword { 171 private: 172 public: 173 CommandObjectReproducerCapture(CommandInterpreter &interpreter) 174 : CommandObjectMultiword( 175 interpreter, "reproducer capture", 176 "Manage gathering of information needed to generate a reproducer.", 177 NULL) { 178 LoadSubCommand( 179 "enable", 180 CommandObjectSP(new CommandObjectReproducerCaptureEnable(interpreter))); 181 LoadSubCommand("disable", 182 CommandObjectSP( 183 new CommandObjectReproducerCaptureDisable(interpreter))); 184 } 185 186 ~CommandObjectReproducerCapture() {} 187 }; 188 189 CommandObjectReproducer::CommandObjectReproducer( 190 CommandInterpreter &interpreter) 191 : CommandObjectMultiword(interpreter, "reproducer", 192 "Commands controlling LLDB reproducers.", 193 "log <subcommand> [<command-options>]") { 194 LoadSubCommand("capture", CommandObjectSP(new CommandObjectReproducerCapture( 195 interpreter))); 196 LoadSubCommand( 197 "generate", 198 CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 199 LoadSubCommand("replay", CommandObjectSP( 200 new CommandObjectReproducerReplay(interpreter))); 201 } 202 203 CommandObjectReproducer::~CommandObjectReproducer() = default; 204