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