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