brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.2 KiB · 5e212e0 Raw
425 lines · cpp
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-exception6//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/CommandOptionArgumentTable.h"20#include "lldb/Interpreter/CommandReturnObject.h"21#include "lldb/Interpreter/OptionArgParser.h"22#include "lldb/Interpreter/OptionGroupFormat.h"23#include "lldb/Interpreter/OptionValueBoolean.h"24#include "lldb/Interpreter/OptionValueLanguage.h"25#include "lldb/Interpreter/OptionValueString.h"26#include "lldb/Interpreter/Options.h"27#include "lldb/Target/Process.h"28#include "lldb/Target/Trace.h"29 30using namespace lldb;31using namespace lldb_private;32using namespace llvm;33 34// CommandObjectTraceSave35#define LLDB_OPTIONS_trace_save36#include "CommandOptions.inc"37 38#pragma mark CommandObjectTraceSave39 40class CommandObjectTraceSave : public CommandObjectParsed {41public:42  class CommandOptions : public Options {43  public:44    CommandOptions() { OptionParsingStarting(nullptr); }45 46    Status SetOptionValue(uint32_t option_idx, llvm::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 'c': {53        m_compact = 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_compact = false;64    };65 66    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {67      return llvm::ArrayRef(g_trace_save_options);68    };69 70    bool m_compact;71  };72 73  Options *GetOptions() override { return &m_options; }74 75  CommandObjectTraceSave(CommandInterpreter &interpreter)76      : CommandObjectParsed(77            interpreter, "trace save",78            "Save the trace of the current target in the specified directory, "79            "which will be created if needed. "80            "This directory will contain a trace bundle, with all the "81            "necessary files the reconstruct the trace session even on a "82            "different computer. "83            "Part of this bundle is the bundle description file with the name "84            "trace.json. This file can be used by the \"trace load\" command "85            "to load this trace in LLDB."86            "Note: if the current target contains information of multiple "87            "processes or targets, they all will be included in the bundle.",88            "trace save [<cmd-options>] <bundle_directory>",89            eCommandRequiresProcess | eCommandTryTargetAPILock |90                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |91                eCommandProcessMustBeTraced) {92    AddSimpleArgumentList(eArgTypeDirectoryName);93  }94 95  void96  HandleArgumentCompletion(CompletionRequest &request,97                           OptionElementVector &opt_element_vector) override {98    lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(99        GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);100  }101 102  ~CommandObjectTraceSave() override = default;103 104protected:105  void DoExecute(Args &command, CommandReturnObject &result) override {106    if (command.size() != 1) {107      result.AppendError("a single path to a directory where the trace bundle "108                         "will be created is required");109      return;110    }111 112    FileSpec bundle_dir(command[0].ref());113    FileSystem::Instance().Resolve(bundle_dir);114 115    ProcessSP process_sp = m_exe_ctx.GetProcessSP();116 117    TraceSP trace_sp = process_sp->GetTarget().GetTrace();118 119    if (llvm::Expected<FileSpec> desc_file =120            trace_sp->SaveToDisk(bundle_dir, m_options.m_compact)) {121      result.AppendMessageWithFormatv(122          "Trace bundle description file written to: {0}", *desc_file);123      result.SetStatus(eReturnStatusSuccessFinishResult);124    } else {125      result.AppendError(toString(desc_file.takeError()));126    }127  }128 129  CommandOptions m_options;130};131 132// CommandObjectTraceLoad133#define LLDB_OPTIONS_trace_load134#include "CommandOptions.inc"135 136#pragma mark CommandObjectTraceLoad137 138class CommandObjectTraceLoad : public CommandObjectParsed {139public:140  class CommandOptions : public Options {141  public:142    CommandOptions() { OptionParsingStarting(nullptr); }143 144    ~CommandOptions() override = default;145 146    Status SetOptionValue(uint32_t option_idx, 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    ArrayRef<OptionDefinition> GetDefinitions() override {167      return ArrayRef(g_trace_load_options);168    }169 170    bool m_verbose; // Enable verbose logging for debugging purposes.171  };172 173  CommandObjectTraceLoad(CommandInterpreter &interpreter)174      : CommandObjectParsed(175            interpreter, "trace load",176            "Load a post-mortem processor trace session from a trace bundle.",177            "trace load <trace_description_file>") {178    AddSimpleArgumentList(eArgTypeFilename);179  }180 181  void182  HandleArgumentCompletion(CompletionRequest &request,183                           OptionElementVector &opt_element_vector) override {184    lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(185        GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);186  }187 188  ~CommandObjectTraceLoad() override = default;189 190  Options *GetOptions() override { return &m_options; }191 192protected:193  void DoExecute(Args &command, CommandReturnObject &result) override {194    if (command.size() != 1) {195      result.AppendError("a single path to a JSON file containing a the "196                         "description of the trace bundle is required");197      return;198    }199 200    const FileSpec trace_description_file(command[0].ref());201 202    llvm::Expected<lldb::TraceSP> trace_or_err =203        Trace::LoadPostMortemTraceFromFile(GetDebugger(),204                                           trace_description_file);205 206    if (!trace_or_err) {207      result.AppendErrorWithFormat(208          "%s\n", llvm::toString(trace_or_err.takeError()).c_str());209      return;210    }211 212    if (m_options.m_verbose) {213      result.AppendMessageWithFormatv("loading trace with plugin {0}\n",214                                      trace_or_err.get()->GetPluginName());215    }216 217    result.SetStatus(eReturnStatusSuccessFinishResult);218  }219 220  CommandOptions m_options;221};222 223// CommandObjectTraceDump224#define LLDB_OPTIONS_trace_dump225#include "CommandOptions.inc"226 227#pragma mark CommandObjectTraceDump228 229class CommandObjectTraceDump : public CommandObjectParsed {230public:231  class CommandOptions : public Options {232  public:233    CommandOptions() { OptionParsingStarting(nullptr); }234 235    ~CommandOptions() override = default;236 237    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,238                          ExecutionContext *execution_context) override {239      Status error;240      const int short_option = m_getopt_table[option_idx].val;241 242      switch (short_option) {243      case 'v': {244        m_verbose = true;245        break;246      }247      default:248        llvm_unreachable("Unimplemented option");249      }250      return error;251    }252 253    void OptionParsingStarting(ExecutionContext *execution_context) override {254      m_verbose = false;255    }256 257    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {258      return llvm::ArrayRef(g_trace_dump_options);259    }260 261    bool m_verbose; // Enable verbose logging for debugging purposes.262  };263 264  CommandObjectTraceDump(CommandInterpreter &interpreter)265      : CommandObjectParsed(interpreter, "trace dump",266                            "Dump the loaded processor trace data.",267                            "trace dump") {}268 269  ~CommandObjectTraceDump() override = default;270 271  Options *GetOptions() override { return &m_options; }272 273protected:274  void DoExecute(Args &command, CommandReturnObject &result) override {275    Status error;276    // TODO: fill in the dumping code here!277    if (error.Success()) {278      result.SetStatus(eReturnStatusSuccessFinishResult);279    } else {280      result.AppendErrorWithFormat("%s\n", error.AsCString());281    }282  }283 284  CommandOptions m_options;285};286 287// CommandObjectTraceSchema288#define LLDB_OPTIONS_trace_schema289#include "CommandOptions.inc"290 291#pragma mark CommandObjectTraceSchema292 293class CommandObjectTraceSchema : public CommandObjectParsed {294public:295  class CommandOptions : public Options {296  public:297    CommandOptions() { OptionParsingStarting(nullptr); }298 299    ~CommandOptions() override = default;300 301    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,302                          ExecutionContext *execution_context) override {303      Status error;304      const int short_option = m_getopt_table[option_idx].val;305 306      switch (short_option) {307      case 'v': {308        m_verbose = true;309        break;310      }311      default:312        llvm_unreachable("Unimplemented option");313      }314      return error;315    }316 317    void OptionParsingStarting(ExecutionContext *execution_context) override {318      m_verbose = false;319    }320 321    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {322      return llvm::ArrayRef(g_trace_schema_options);323    }324 325    bool m_verbose; // Enable verbose logging for debugging purposes.326  };327 328  CommandObjectTraceSchema(CommandInterpreter &interpreter)329      : CommandObjectParsed(interpreter, "trace schema",330                            "Show the schema of the given trace plugin.",331                            "trace schema <plug-in>. Use the plug-in name "332                            "\"all\" to see all schemas.\n") {333    AddSimpleArgumentList(eArgTypeNone);334  }335 336  ~CommandObjectTraceSchema() override = default;337 338  Options *GetOptions() override { return &m_options; }339 340protected:341  void DoExecute(Args &command, CommandReturnObject &result) override {342    Status error;343    if (command.empty()) {344      result.AppendError(345          "trace schema cannot be invoked without a plug-in as argument");346      return;347    }348 349    StringRef plugin_name(command[0].c_str());350    if (plugin_name == "all") {351      size_t index = 0;352      while (true) {353        StringRef schema = PluginManager::GetTraceSchema(index++);354        if (schema.empty())355          break;356 357        result.AppendMessage(schema);358      }359    } else {360      if (Expected<StringRef> schemaOrErr =361              Trace::FindPluginSchema(plugin_name))362        result.AppendMessage(*schemaOrErr);363      else364        error = Status::FromError(schemaOrErr.takeError());365    }366 367    if (error.Success()) {368      result.SetStatus(eReturnStatusSuccessFinishResult);369    } else {370      result.AppendErrorWithFormat("%s\n", error.AsCString());371    }372  }373 374  CommandOptions m_options;375};376 377// CommandObjectTrace378 379CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)380    : CommandObjectMultiword(interpreter, "trace",381                             "Commands for loading and using processor "382                             "trace information.",383                             "trace [<sub-command-options>]") {384  LoadSubCommand("load",385                 CommandObjectSP(new CommandObjectTraceLoad(interpreter)));386  LoadSubCommand("dump",387                 CommandObjectSP(new CommandObjectTraceDump(interpreter)));388  LoadSubCommand("save",389                 CommandObjectSP(new CommandObjectTraceSave(interpreter)));390  LoadSubCommand("schema",391                 CommandObjectSP(new CommandObjectTraceSchema(interpreter)));392}393 394CommandObjectTrace::~CommandObjectTrace() = default;395 396Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {397  ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();398 399  if (!process_sp)400    return createStringError(inconvertibleErrorCode(),401                             "Process not available.");402  if (m_live_debug_session_only && !process_sp->IsLiveDebugSession())403    return createStringError(inconvertibleErrorCode(),404                             "Process must be alive.");405 406  if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate())407    return GetDelegateCommand(**trace_sp);408  else409    return createStringError(inconvertibleErrorCode(),410                             "Tracing is not supported. %s",411                             toString(trace_sp.takeError()).c_str());412}413 414CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() {415  if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {416    m_delegate_sp = *delegate;417    m_delegate_error.clear();418    return m_delegate_sp.get();419  } else {420    m_delegate_sp.reset();421    m_delegate_error = toString(delegate.takeError());422    return nullptr;423  }424}425