174c93956SWalter Erquinigo //===-- CommandObjectTrace.cpp --------------------------------------------===//
274c93956SWalter Erquinigo //
374c93956SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
474c93956SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
574c93956SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674c93956SWalter Erquinigo //
774c93956SWalter Erquinigo //===----------------------------------------------------------------------===//
874c93956SWalter Erquinigo 
974c93956SWalter Erquinigo #include "CommandObjectTrace.h"
1074c93956SWalter Erquinigo 
1174c93956SWalter Erquinigo #include "llvm/Support/JSON.h"
1274c93956SWalter Erquinigo #include "llvm/Support/MemoryBuffer.h"
1374c93956SWalter Erquinigo 
1474c93956SWalter Erquinigo #include "lldb/Core/Debugger.h"
15ea1f4974SWalter Erquinigo #include "lldb/Core/PluginManager.h"
1674c93956SWalter Erquinigo #include "lldb/Host/OptionParser.h"
1774c93956SWalter Erquinigo #include "lldb/Interpreter/CommandInterpreter.h"
1874c93956SWalter Erquinigo #include "lldb/Interpreter/CommandObject.h"
1974c93956SWalter Erquinigo #include "lldb/Interpreter/CommandReturnObject.h"
2074c93956SWalter Erquinigo #include "lldb/Interpreter/OptionArgParser.h"
2174c93956SWalter Erquinigo #include "lldb/Interpreter/OptionGroupFormat.h"
2274c93956SWalter Erquinigo #include "lldb/Interpreter/OptionValueBoolean.h"
2374c93956SWalter Erquinigo #include "lldb/Interpreter/OptionValueLanguage.h"
2474c93956SWalter Erquinigo #include "lldb/Interpreter/OptionValueString.h"
2574c93956SWalter Erquinigo #include "lldb/Interpreter/Options.h"
260b697561SWalter Erquinigo #include "lldb/Target/Process.h"
2774c93956SWalter Erquinigo #include "lldb/Target/Trace.h"
2874c93956SWalter Erquinigo 
2974c93956SWalter Erquinigo using namespace lldb;
3074c93956SWalter Erquinigo using namespace lldb_private;
3174c93956SWalter Erquinigo using namespace llvm;
3274c93956SWalter Erquinigo 
3374c93956SWalter Erquinigo // CommandObjectTraceLoad
3474c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_load
3574c93956SWalter Erquinigo #include "CommandOptions.inc"
3674c93956SWalter Erquinigo 
3774c93956SWalter Erquinigo #pragma mark CommandObjectTraceLoad
3874c93956SWalter Erquinigo 
3974c93956SWalter Erquinigo class CommandObjectTraceLoad : public CommandObjectParsed {
4074c93956SWalter Erquinigo public:
4174c93956SWalter Erquinigo   class CommandOptions : public Options {
4274c93956SWalter Erquinigo   public:
43abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
4474c93956SWalter Erquinigo 
4574c93956SWalter Erquinigo     ~CommandOptions() override = default;
4674c93956SWalter Erquinigo 
4774c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
4874c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
4974c93956SWalter Erquinigo       Status error;
5074c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
5174c93956SWalter Erquinigo 
5274c93956SWalter Erquinigo       switch (short_option) {
5374c93956SWalter Erquinigo       case 'v': {
5474c93956SWalter Erquinigo         m_verbose = true;
5574c93956SWalter Erquinigo         break;
5674c93956SWalter Erquinigo       }
5774c93956SWalter Erquinigo       default:
5874c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
5974c93956SWalter Erquinigo       }
6074c93956SWalter Erquinigo       return error;
6174c93956SWalter Erquinigo     }
6274c93956SWalter Erquinigo 
6374c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
6474c93956SWalter Erquinigo       m_verbose = false;
6574c93956SWalter Erquinigo     }
6674c93956SWalter Erquinigo 
6774c93956SWalter Erquinigo     ArrayRef<OptionDefinition> GetDefinitions() override {
6874c93956SWalter Erquinigo       return makeArrayRef(g_trace_load_options);
6974c93956SWalter Erquinigo     }
7074c93956SWalter Erquinigo 
7174c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
7274c93956SWalter Erquinigo   };
7374c93956SWalter Erquinigo 
7474c93956SWalter Erquinigo   CommandObjectTraceLoad(CommandInterpreter &interpreter)
75*b8dcd0baSWalter Erquinigo       : CommandObjectParsed(
76*b8dcd0baSWalter Erquinigo             interpreter, "trace load",
77*b8dcd0baSWalter Erquinigo             "Load a post-mortem processor trace session from a trace bundle.",
78abb0ed44SKazu Hirata             "trace load") {}
7974c93956SWalter Erquinigo 
8074c93956SWalter Erquinigo   ~CommandObjectTraceLoad() override = default;
8174c93956SWalter Erquinigo 
8274c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
8374c93956SWalter Erquinigo 
8474c93956SWalter Erquinigo protected:
8574c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
8674c93956SWalter Erquinigo     if (command.size() != 1) {
87*b8dcd0baSWalter Erquinigo       result.AppendError("a single path to a JSON file containing a the "
88*b8dcd0baSWalter Erquinigo                          "description of the trace bundle is required");
8974c93956SWalter Erquinigo       return false;
9074c93956SWalter Erquinigo     }
9174c93956SWalter Erquinigo 
9250f93679SJakob Johnson     const FileSpec trace_description_file(command[0].ref());
9350f93679SJakob Johnson 
9450f93679SJakob Johnson     llvm::Expected<lldb::TraceSP> trace_or_err =
9550f93679SJakob Johnson         Trace::LoadPostMortemTraceFromFile(GetDebugger(),
9650f93679SJakob Johnson                                            trace_description_file);
9750f93679SJakob Johnson 
9850f93679SJakob Johnson     if (!trace_or_err) {
9950f93679SJakob Johnson       result.AppendErrorWithFormat(
10050f93679SJakob Johnson           "%s\n", llvm::toString(trace_or_err.takeError()).c_str());
10174c93956SWalter Erquinigo       return false;
10274c93956SWalter Erquinigo     }
10374c93956SWalter Erquinigo 
10450f93679SJakob Johnson     if (m_options.m_verbose) {
105a3939e15SPavel Labath       result.AppendMessageWithFormatv("loading trace with plugin {0}\n",
10650f93679SJakob Johnson                                       trace_or_err.get()->GetPluginName());
10750f93679SJakob Johnson     }
10874c93956SWalter Erquinigo 
10974c93956SWalter Erquinigo     result.SetStatus(eReturnStatusSuccessFinishResult);
11074c93956SWalter Erquinigo     return true;
11174c93956SWalter Erquinigo   }
11274c93956SWalter Erquinigo 
11374c93956SWalter Erquinigo   CommandOptions m_options;
11474c93956SWalter Erquinigo };
11574c93956SWalter Erquinigo 
11674c93956SWalter Erquinigo // CommandObjectTraceDump
11774c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_dump
11874c93956SWalter Erquinigo #include "CommandOptions.inc"
11974c93956SWalter Erquinigo 
12074c93956SWalter Erquinigo #pragma mark CommandObjectTraceDump
12174c93956SWalter Erquinigo 
12274c93956SWalter Erquinigo class CommandObjectTraceDump : public CommandObjectParsed {
12374c93956SWalter Erquinigo public:
12474c93956SWalter Erquinigo   class CommandOptions : public Options {
12574c93956SWalter Erquinigo   public:
126abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
12774c93956SWalter Erquinigo 
12874c93956SWalter Erquinigo     ~CommandOptions() override = default;
12974c93956SWalter Erquinigo 
13074c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
13174c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
13274c93956SWalter Erquinigo       Status error;
13374c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
13474c93956SWalter Erquinigo 
13574c93956SWalter Erquinigo       switch (short_option) {
13674c93956SWalter Erquinigo       case 'v': {
13774c93956SWalter Erquinigo         m_verbose = true;
13874c93956SWalter Erquinigo         break;
13974c93956SWalter Erquinigo       }
14074c93956SWalter Erquinigo       default:
14174c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
14274c93956SWalter Erquinigo       }
14374c93956SWalter Erquinigo       return error;
14474c93956SWalter Erquinigo     }
14574c93956SWalter Erquinigo 
14674c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
14774c93956SWalter Erquinigo       m_verbose = false;
14874c93956SWalter Erquinigo     }
14974c93956SWalter Erquinigo 
15074c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
15174c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_dump_options);
15274c93956SWalter Erquinigo     }
15374c93956SWalter Erquinigo 
15474c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
15574c93956SWalter Erquinigo   };
15674c93956SWalter Erquinigo 
15774c93956SWalter Erquinigo   CommandObjectTraceDump(CommandInterpreter &interpreter)
15874c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace dump",
15974c93956SWalter Erquinigo                             "Dump the loaded processor trace data.",
160abb0ed44SKazu Hirata                             "trace dump") {}
16174c93956SWalter Erquinigo 
16274c93956SWalter Erquinigo   ~CommandObjectTraceDump() override = default;
16374c93956SWalter Erquinigo 
16474c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
16574c93956SWalter Erquinigo 
16674c93956SWalter Erquinigo protected:
16774c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
16874c93956SWalter Erquinigo     Status error;
16974c93956SWalter Erquinigo     // TODO: fill in the dumping code here!
17074c93956SWalter Erquinigo     if (error.Success()) {
17174c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
17274c93956SWalter Erquinigo     } else {
17374c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
17474c93956SWalter Erquinigo     }
17574c93956SWalter Erquinigo     return result.Succeeded();
17674c93956SWalter Erquinigo   }
17774c93956SWalter Erquinigo 
17874c93956SWalter Erquinigo   CommandOptions m_options;
17974c93956SWalter Erquinigo };
18074c93956SWalter Erquinigo 
18174c93956SWalter Erquinigo // CommandObjectTraceSchema
18274c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_schema
18374c93956SWalter Erquinigo #include "CommandOptions.inc"
18474c93956SWalter Erquinigo 
18574c93956SWalter Erquinigo #pragma mark CommandObjectTraceSchema
18674c93956SWalter Erquinigo 
18774c93956SWalter Erquinigo class CommandObjectTraceSchema : public CommandObjectParsed {
18874c93956SWalter Erquinigo public:
18974c93956SWalter Erquinigo   class CommandOptions : public Options {
19074c93956SWalter Erquinigo   public:
191abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
19274c93956SWalter Erquinigo 
19374c93956SWalter Erquinigo     ~CommandOptions() override = default;
19474c93956SWalter Erquinigo 
19574c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
19674c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
19774c93956SWalter Erquinigo       Status error;
19874c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
19974c93956SWalter Erquinigo 
20074c93956SWalter Erquinigo       switch (short_option) {
20174c93956SWalter Erquinigo       case 'v': {
20274c93956SWalter Erquinigo         m_verbose = true;
20374c93956SWalter Erquinigo         break;
20474c93956SWalter Erquinigo       }
20574c93956SWalter Erquinigo       default:
20674c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
20774c93956SWalter Erquinigo       }
20874c93956SWalter Erquinigo       return error;
20974c93956SWalter Erquinigo     }
21074c93956SWalter Erquinigo 
21174c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
21274c93956SWalter Erquinigo       m_verbose = false;
21374c93956SWalter Erquinigo     }
21474c93956SWalter Erquinigo 
21574c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
21674c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_schema_options);
21774c93956SWalter Erquinigo     }
21874c93956SWalter Erquinigo 
21974c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
22074c93956SWalter Erquinigo   };
22174c93956SWalter Erquinigo 
22274c93956SWalter Erquinigo   CommandObjectTraceSchema(CommandInterpreter &interpreter)
22374c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace schema",
22474c93956SWalter Erquinigo                             "Show the schema of the given trace plugin.",
225ea1f4974SWalter Erquinigo                             "trace schema <plug-in>. Use the plug-in name "
226abb0ed44SKazu Hirata                             "\"all\" to see all schemas.\n") {}
22774c93956SWalter Erquinigo 
22874c93956SWalter Erquinigo   ~CommandObjectTraceSchema() override = default;
22974c93956SWalter Erquinigo 
23074c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
23174c93956SWalter Erquinigo 
23274c93956SWalter Erquinigo protected:
23374c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
23474c93956SWalter Erquinigo     Status error;
23574c93956SWalter Erquinigo     if (command.empty()) {
2361b1c8e4aSDavid Spickett       result.AppendError(
23774c93956SWalter Erquinigo           "trace schema cannot be invoked without a plug-in as argument");
23874c93956SWalter Erquinigo       return false;
23974c93956SWalter Erquinigo     }
24074c93956SWalter Erquinigo 
24174c93956SWalter Erquinigo     StringRef plugin_name(command[0].c_str());
242ea1f4974SWalter Erquinigo     if (plugin_name == "all") {
243ea1f4974SWalter Erquinigo       size_t index = 0;
244ea1f4974SWalter Erquinigo       while (true) {
245ea1f4974SWalter Erquinigo         StringRef schema = PluginManager::GetTraceSchema(index++);
246ea1f4974SWalter Erquinigo         if (schema.empty())
247ea1f4974SWalter Erquinigo           break;
24874c93956SWalter Erquinigo 
249ea1f4974SWalter Erquinigo         result.AppendMessage(schema);
250ea1f4974SWalter Erquinigo       }
25174c93956SWalter Erquinigo     } else {
252ea1f4974SWalter Erquinigo       if (Expected<StringRef> schemaOrErr =
253ea1f4974SWalter Erquinigo               Trace::FindPluginSchema(plugin_name))
254ea1f4974SWalter Erquinigo         result.AppendMessage(*schemaOrErr);
255ea1f4974SWalter Erquinigo       else
256ea1f4974SWalter Erquinigo         error = schemaOrErr.takeError();
25774c93956SWalter Erquinigo     }
25874c93956SWalter Erquinigo 
25974c93956SWalter Erquinigo     if (error.Success()) {
26074c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
26174c93956SWalter Erquinigo     } else {
26274c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
26374c93956SWalter Erquinigo     }
26474c93956SWalter Erquinigo     return result.Succeeded();
26574c93956SWalter Erquinigo   }
26674c93956SWalter Erquinigo 
26774c93956SWalter Erquinigo   CommandOptions m_options;
26874c93956SWalter Erquinigo };
26974c93956SWalter Erquinigo 
27074c93956SWalter Erquinigo // CommandObjectTrace
27174c93956SWalter Erquinigo 
27274c93956SWalter Erquinigo CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
27374c93956SWalter Erquinigo     : CommandObjectMultiword(interpreter, "trace",
27474c93956SWalter Erquinigo                              "Commands for loading and using processor "
27574c93956SWalter Erquinigo                              "trace information.",
27674c93956SWalter Erquinigo                              "trace [<sub-command-options>]") {
27774c93956SWalter Erquinigo   LoadSubCommand("load",
27874c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
27974c93956SWalter Erquinigo   LoadSubCommand("dump",
28074c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceDump(interpreter)));
28174c93956SWalter Erquinigo   LoadSubCommand("schema",
28274c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
28374c93956SWalter Erquinigo }
28474c93956SWalter Erquinigo 
28574c93956SWalter Erquinigo CommandObjectTrace::~CommandObjectTrace() = default;
2860b697561SWalter Erquinigo 
2870b697561SWalter Erquinigo Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
2880b697561SWalter Erquinigo   ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();
2890b697561SWalter Erquinigo 
2900b697561SWalter Erquinigo   if (!process_sp)
2910b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
2920b697561SWalter Erquinigo                              "Process not available.");
2930b697561SWalter Erquinigo   if (m_live_debug_session_only && !process_sp->IsLiveDebugSession())
2940b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
2950b697561SWalter Erquinigo                              "Process must be alive.");
2960b697561SWalter Erquinigo 
297bf9f21a2SWalter Erquinigo   if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
2980b697561SWalter Erquinigo     return GetDelegateCommand(**trace_sp);
2990b697561SWalter Erquinigo   else
3000b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
3010b697561SWalter Erquinigo                              "Tracing is not supported. %s",
3020b697561SWalter Erquinigo                              toString(trace_sp.takeError()).c_str());
3030b697561SWalter Erquinigo }
3040b697561SWalter Erquinigo 
3050b697561SWalter Erquinigo CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() {
3060b697561SWalter Erquinigo   if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {
3070b697561SWalter Erquinigo     m_delegate_sp = *delegate;
3080b697561SWalter Erquinigo     m_delegate_error.clear();
3090b697561SWalter Erquinigo     return m_delegate_sp.get();
3100b697561SWalter Erquinigo   } else {
3110b697561SWalter Erquinigo     m_delegate_sp.reset();
3120b697561SWalter Erquinigo     m_delegate_error = toString(delegate.takeError());
3130b697561SWalter Erquinigo     return nullptr;
3140b697561SWalter Erquinigo   }
3150b697561SWalter Erquinigo }
316