1 //===-- CommandObjectTrace.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectTrace.h" 10 11 #include "llvm/Support/JSON.h" 12 #include "llvm/Support/MemoryBuffer.h" 13 14 #include "lldb/Core/Debugger.h" 15 #include "lldb/Host/OptionParser.h" 16 #include "lldb/Interpreter/CommandInterpreter.h" 17 #include "lldb/Interpreter/CommandObject.h" 18 #include "lldb/Interpreter/CommandReturnObject.h" 19 #include "lldb/Interpreter/OptionArgParser.h" 20 #include "lldb/Interpreter/OptionGroupFormat.h" 21 #include "lldb/Interpreter/OptionValueBoolean.h" 22 #include "lldb/Interpreter/OptionValueLanguage.h" 23 #include "lldb/Interpreter/OptionValueString.h" 24 #include "lldb/Interpreter/Options.h" 25 #include "lldb/Target/Trace.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 using namespace llvm; 30 31 // CommandObjectTraceLoad 32 #define LLDB_OPTIONS_trace_load 33 #include "CommandOptions.inc" 34 35 #pragma mark CommandObjectTraceLoad 36 37 class CommandObjectTraceLoad : public CommandObjectParsed { 38 public: 39 class CommandOptions : public Options { 40 public: 41 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 42 43 ~CommandOptions() override = default; 44 45 Status SetOptionValue(uint32_t option_idx, StringRef option_arg, 46 ExecutionContext *execution_context) override { 47 Status error; 48 const int short_option = m_getopt_table[option_idx].val; 49 50 switch (short_option) { 51 case 'v': { 52 m_verbose = true; 53 break; 54 } 55 default: 56 llvm_unreachable("Unimplemented option"); 57 } 58 return error; 59 } 60 61 void OptionParsingStarting(ExecutionContext *execution_context) override { 62 m_verbose = false; 63 } 64 65 ArrayRef<OptionDefinition> GetDefinitions() override { 66 return makeArrayRef(g_trace_load_options); 67 } 68 69 bool m_verbose; // Enable verbose logging for debugging purposes. 70 }; 71 72 CommandObjectTraceLoad(CommandInterpreter &interpreter) 73 : CommandObjectParsed(interpreter, "trace load", 74 "Load processor trace data from a JSON file.", 75 "trace load"), 76 m_options() {} 77 78 ~CommandObjectTraceLoad() override = default; 79 80 Options *GetOptions() override { return &m_options; } 81 82 protected: 83 bool DoExecute(Args &command, CommandReturnObject &result) override { 84 if (command.size() != 1) { 85 result.AppendError("a single path to a JSON file containing trace " 86 "information is required"); 87 result.SetStatus(eReturnStatusFailed); 88 return false; 89 } 90 91 auto end_with_failure = [&result](llvm::Error err) -> bool { 92 result.AppendErrorWithFormat("%s\n", 93 llvm::toString(std::move(err)).c_str()); 94 result.SetStatus(eReturnStatusFailed); 95 return false; 96 }; 97 98 FileSpec json_file(command[0].ref()); 99 100 auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath()); 101 if (!buffer_or_error) { 102 return end_with_failure(llvm::createStringError( 103 std::errc::invalid_argument, "could not open input file: %s - %s.", 104 json_file.GetPath().c_str(), 105 buffer_or_error.getError().message().c_str())); 106 } 107 108 llvm::Expected<json::Value> settings = 109 json::parse(buffer_or_error.get()->getBuffer().str()); 110 if (!settings) 111 return end_with_failure(settings.takeError()); 112 113 if (Expected<lldb::TraceSP> traceOrErr = Trace::FindPlugin( 114 GetDebugger(), *settings, json_file.GetDirectory().AsCString())) { 115 lldb::TraceSP trace_sp = traceOrErr.get(); 116 if (m_options.m_verbose) 117 result.AppendMessageWithFormat("loading trace with plugin %s\n", 118 trace_sp->GetPluginName().AsCString()); 119 } else 120 return end_with_failure(traceOrErr.takeError()); 121 122 result.SetStatus(eReturnStatusSuccessFinishResult); 123 return true; 124 } 125 126 CommandOptions m_options; 127 }; 128 129 // CommandObjectTraceDump 130 #define LLDB_OPTIONS_trace_dump 131 #include "CommandOptions.inc" 132 133 #pragma mark CommandObjectTraceDump 134 135 class CommandObjectTraceDump : public CommandObjectParsed { 136 public: 137 class CommandOptions : public Options { 138 public: 139 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 140 141 ~CommandOptions() override = default; 142 143 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 144 ExecutionContext *execution_context) override { 145 Status error; 146 const int short_option = m_getopt_table[option_idx].val; 147 148 switch (short_option) { 149 case 'v': { 150 m_verbose = true; 151 break; 152 } 153 default: 154 llvm_unreachable("Unimplemented option"); 155 } 156 return error; 157 } 158 159 void OptionParsingStarting(ExecutionContext *execution_context) override { 160 m_verbose = false; 161 } 162 163 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 164 return llvm::makeArrayRef(g_trace_dump_options); 165 } 166 167 bool m_verbose; // Enable verbose logging for debugging purposes. 168 }; 169 170 CommandObjectTraceDump(CommandInterpreter &interpreter) 171 : CommandObjectParsed(interpreter, "trace dump", 172 "Dump the loaded processor trace data.", 173 "trace dump"), 174 m_options() {} 175 176 ~CommandObjectTraceDump() override = default; 177 178 Options *GetOptions() override { return &m_options; } 179 180 protected: 181 bool DoExecute(Args &command, CommandReturnObject &result) override { 182 Status error; 183 // TODO: fill in the dumping code here! 184 if (error.Success()) { 185 result.SetStatus(eReturnStatusSuccessFinishResult); 186 } else { 187 result.AppendErrorWithFormat("%s\n", error.AsCString()); 188 result.SetStatus(eReturnStatusFailed); 189 } 190 return result.Succeeded(); 191 } 192 193 CommandOptions m_options; 194 }; 195 196 // CommandObjectTraceSchema 197 #define LLDB_OPTIONS_trace_schema 198 #include "CommandOptions.inc" 199 200 #pragma mark CommandObjectTraceSchema 201 202 class CommandObjectTraceSchema : public CommandObjectParsed { 203 public: 204 class CommandOptions : public Options { 205 public: 206 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 207 208 ~CommandOptions() override = default; 209 210 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 211 ExecutionContext *execution_context) override { 212 Status error; 213 const int short_option = m_getopt_table[option_idx].val; 214 215 switch (short_option) { 216 case 'v': { 217 m_verbose = true; 218 break; 219 } 220 default: 221 llvm_unreachable("Unimplemented option"); 222 } 223 return error; 224 } 225 226 void OptionParsingStarting(ExecutionContext *execution_context) override { 227 m_verbose = false; 228 } 229 230 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 231 return llvm::makeArrayRef(g_trace_schema_options); 232 } 233 234 bool m_verbose; // Enable verbose logging for debugging purposes. 235 }; 236 237 CommandObjectTraceSchema(CommandInterpreter &interpreter) 238 : CommandObjectParsed(interpreter, "trace schema", 239 "Show the schema of the given trace plugin.", 240 "trace schema <plug-in>"), 241 m_options() {} 242 243 ~CommandObjectTraceSchema() override = default; 244 245 Options *GetOptions() override { return &m_options; } 246 247 protected: 248 bool DoExecute(Args &command, CommandReturnObject &result) override { 249 Status error; 250 if (command.empty()) { 251 result.SetError( 252 "trace schema cannot be invoked without a plug-in as argument"); 253 return false; 254 } 255 256 StringRef plugin_name(command[0].c_str()); 257 258 if (Expected<lldb::TraceSP> traceOrErr = Trace::FindPlugin(plugin_name)) { 259 lldb::TraceSP trace_sp = traceOrErr.get(); 260 result.AppendMessage(trace_sp->GetSchema()); 261 } else { 262 error.SetErrorString(llvm::toString(traceOrErr.takeError())); 263 } 264 265 if (error.Success()) { 266 result.SetStatus(eReturnStatusSuccessFinishResult); 267 } else { 268 result.AppendErrorWithFormat("%s\n", error.AsCString()); 269 result.SetStatus(eReturnStatusFailed); 270 } 271 return result.Succeeded(); 272 } 273 274 CommandOptions m_options; 275 }; 276 277 // CommandObjectTrace 278 279 CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter) 280 : CommandObjectMultiword(interpreter, "trace", 281 "Commands for loading and using processor " 282 "trace information.", 283 "trace [<sub-command-options>]") { 284 LoadSubCommand("load", 285 CommandObjectSP(new CommandObjectTraceLoad(interpreter))); 286 LoadSubCommand("dump", 287 CommandObjectSP(new CommandObjectTraceDump(interpreter))); 288 LoadSubCommand("schema", 289 CommandObjectSP(new CommandObjectTraceSchema(interpreter))); 290 } 291 292 CommandObjectTrace::~CommandObjectTrace() = default; 293