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