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:
43*abb0ed44SKazu 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)
7574c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace load",
76ea1f4974SWalter Erquinigo                             "Load a processor trace session from a JSON file.",
77*abb0ed44SKazu Hirata                             "trace load") {}
7874c93956SWalter Erquinigo 
7974c93956SWalter Erquinigo   ~CommandObjectTraceLoad() override = default;
8074c93956SWalter Erquinigo 
8174c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
8274c93956SWalter Erquinigo 
8374c93956SWalter Erquinigo protected:
8474c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
8574c93956SWalter Erquinigo     if (command.size() != 1) {
86ea1f4974SWalter Erquinigo       result.AppendError(
87ea1f4974SWalter Erquinigo           "a single path to a JSON file containing a trace session"
88ea1f4974SWalter Erquinigo           "is required");
8974c93956SWalter Erquinigo       return false;
9074c93956SWalter Erquinigo     }
9174c93956SWalter Erquinigo 
9274c93956SWalter Erquinigo     auto end_with_failure = [&result](llvm::Error err) -> bool {
9374c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n",
9474c93956SWalter Erquinigo                                    llvm::toString(std::move(err)).c_str());
9574c93956SWalter Erquinigo       return false;
9674c93956SWalter Erquinigo     };
9774c93956SWalter Erquinigo 
9874c93956SWalter Erquinigo     FileSpec json_file(command[0].ref());
9974c93956SWalter Erquinigo 
10074c93956SWalter Erquinigo     auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
10174c93956SWalter Erquinigo     if (!buffer_or_error) {
10274c93956SWalter Erquinigo       return end_with_failure(llvm::createStringError(
10374c93956SWalter Erquinigo           std::errc::invalid_argument, "could not open input file: %s - %s.",
10474c93956SWalter Erquinigo           json_file.GetPath().c_str(),
10574c93956SWalter Erquinigo           buffer_or_error.getError().message().c_str()));
10674c93956SWalter Erquinigo     }
10774c93956SWalter Erquinigo 
108ea1f4974SWalter Erquinigo     llvm::Expected<json::Value> session_file =
10974c93956SWalter Erquinigo         json::parse(buffer_or_error.get()->getBuffer().str());
110ea1f4974SWalter Erquinigo     if (!session_file)
111ea1f4974SWalter Erquinigo       return end_with_failure(session_file.takeError());
11274c93956SWalter Erquinigo 
113ea1f4974SWalter Erquinigo     if (Expected<lldb::TraceSP> traceOrErr =
1140b697561SWalter Erquinigo             Trace::FindPluginForPostMortemProcess(
1150b697561SWalter Erquinigo                 GetDebugger(), *session_file,
116ea1f4974SWalter Erquinigo                 json_file.GetDirectory().AsCString())) {
11774c93956SWalter Erquinigo       lldb::TraceSP trace_sp = traceOrErr.get();
118801067f4SStella Stamenova       if (m_options.m_verbose && trace_sp)
119a3939e15SPavel Labath         result.AppendMessageWithFormatv("loading trace with plugin {0}\n",
120a3939e15SPavel Labath                                         trace_sp->GetPluginName());
12174c93956SWalter Erquinigo     } else
12274c93956SWalter Erquinigo       return end_with_failure(traceOrErr.takeError());
12374c93956SWalter Erquinigo 
12474c93956SWalter Erquinigo     result.SetStatus(eReturnStatusSuccessFinishResult);
12574c93956SWalter Erquinigo     return true;
12674c93956SWalter Erquinigo   }
12774c93956SWalter Erquinigo 
12874c93956SWalter Erquinigo   CommandOptions m_options;
12974c93956SWalter Erquinigo };
13074c93956SWalter Erquinigo 
13174c93956SWalter Erquinigo // CommandObjectTraceDump
13274c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_dump
13374c93956SWalter Erquinigo #include "CommandOptions.inc"
13474c93956SWalter Erquinigo 
13574c93956SWalter Erquinigo #pragma mark CommandObjectTraceDump
13674c93956SWalter Erquinigo 
13774c93956SWalter Erquinigo class CommandObjectTraceDump : public CommandObjectParsed {
13874c93956SWalter Erquinigo public:
13974c93956SWalter Erquinigo   class CommandOptions : public Options {
14074c93956SWalter Erquinigo   public:
141*abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
14274c93956SWalter Erquinigo 
14374c93956SWalter Erquinigo     ~CommandOptions() override = default;
14474c93956SWalter Erquinigo 
14574c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
14674c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
14774c93956SWalter Erquinigo       Status error;
14874c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
14974c93956SWalter Erquinigo 
15074c93956SWalter Erquinigo       switch (short_option) {
15174c93956SWalter Erquinigo       case 'v': {
15274c93956SWalter Erquinigo         m_verbose = true;
15374c93956SWalter Erquinigo         break;
15474c93956SWalter Erquinigo       }
15574c93956SWalter Erquinigo       default:
15674c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
15774c93956SWalter Erquinigo       }
15874c93956SWalter Erquinigo       return error;
15974c93956SWalter Erquinigo     }
16074c93956SWalter Erquinigo 
16174c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
16274c93956SWalter Erquinigo       m_verbose = false;
16374c93956SWalter Erquinigo     }
16474c93956SWalter Erquinigo 
16574c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
16674c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_dump_options);
16774c93956SWalter Erquinigo     }
16874c93956SWalter Erquinigo 
16974c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
17074c93956SWalter Erquinigo   };
17174c93956SWalter Erquinigo 
17274c93956SWalter Erquinigo   CommandObjectTraceDump(CommandInterpreter &interpreter)
17374c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace dump",
17474c93956SWalter Erquinigo                             "Dump the loaded processor trace data.",
175*abb0ed44SKazu Hirata                             "trace dump") {}
17674c93956SWalter Erquinigo 
17774c93956SWalter Erquinigo   ~CommandObjectTraceDump() override = default;
17874c93956SWalter Erquinigo 
17974c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
18074c93956SWalter Erquinigo 
18174c93956SWalter Erquinigo protected:
18274c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
18374c93956SWalter Erquinigo     Status error;
18474c93956SWalter Erquinigo     // TODO: fill in the dumping code here!
18574c93956SWalter Erquinigo     if (error.Success()) {
18674c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
18774c93956SWalter Erquinigo     } else {
18874c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
18974c93956SWalter Erquinigo     }
19074c93956SWalter Erquinigo     return result.Succeeded();
19174c93956SWalter Erquinigo   }
19274c93956SWalter Erquinigo 
19374c93956SWalter Erquinigo   CommandOptions m_options;
19474c93956SWalter Erquinigo };
19574c93956SWalter Erquinigo 
19674c93956SWalter Erquinigo // CommandObjectTraceSchema
19774c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_schema
19874c93956SWalter Erquinigo #include "CommandOptions.inc"
19974c93956SWalter Erquinigo 
20074c93956SWalter Erquinigo #pragma mark CommandObjectTraceSchema
20174c93956SWalter Erquinigo 
20274c93956SWalter Erquinigo class CommandObjectTraceSchema : public CommandObjectParsed {
20374c93956SWalter Erquinigo public:
20474c93956SWalter Erquinigo   class CommandOptions : public Options {
20574c93956SWalter Erquinigo   public:
206*abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
20774c93956SWalter Erquinigo 
20874c93956SWalter Erquinigo     ~CommandOptions() override = default;
20974c93956SWalter Erquinigo 
21074c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
21174c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
21274c93956SWalter Erquinigo       Status error;
21374c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
21474c93956SWalter Erquinigo 
21574c93956SWalter Erquinigo       switch (short_option) {
21674c93956SWalter Erquinigo       case 'v': {
21774c93956SWalter Erquinigo         m_verbose = true;
21874c93956SWalter Erquinigo         break;
21974c93956SWalter Erquinigo       }
22074c93956SWalter Erquinigo       default:
22174c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
22274c93956SWalter Erquinigo       }
22374c93956SWalter Erquinigo       return error;
22474c93956SWalter Erquinigo     }
22574c93956SWalter Erquinigo 
22674c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
22774c93956SWalter Erquinigo       m_verbose = false;
22874c93956SWalter Erquinigo     }
22974c93956SWalter Erquinigo 
23074c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
23174c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_schema_options);
23274c93956SWalter Erquinigo     }
23374c93956SWalter Erquinigo 
23474c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
23574c93956SWalter Erquinigo   };
23674c93956SWalter Erquinigo 
23774c93956SWalter Erquinigo   CommandObjectTraceSchema(CommandInterpreter &interpreter)
23874c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace schema",
23974c93956SWalter Erquinigo                             "Show the schema of the given trace plugin.",
240ea1f4974SWalter Erquinigo                             "trace schema <plug-in>. Use the plug-in name "
241*abb0ed44SKazu Hirata                             "\"all\" to see all schemas.\n") {}
24274c93956SWalter Erquinigo 
24374c93956SWalter Erquinigo   ~CommandObjectTraceSchema() override = default;
24474c93956SWalter Erquinigo 
24574c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
24674c93956SWalter Erquinigo 
24774c93956SWalter Erquinigo protected:
24874c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
24974c93956SWalter Erquinigo     Status error;
25074c93956SWalter Erquinigo     if (command.empty()) {
2511b1c8e4aSDavid Spickett       result.AppendError(
25274c93956SWalter Erquinigo           "trace schema cannot be invoked without a plug-in as argument");
25374c93956SWalter Erquinigo       return false;
25474c93956SWalter Erquinigo     }
25574c93956SWalter Erquinigo 
25674c93956SWalter Erquinigo     StringRef plugin_name(command[0].c_str());
257ea1f4974SWalter Erquinigo     if (plugin_name == "all") {
258ea1f4974SWalter Erquinigo       size_t index = 0;
259ea1f4974SWalter Erquinigo       while (true) {
260ea1f4974SWalter Erquinigo         StringRef schema = PluginManager::GetTraceSchema(index++);
261ea1f4974SWalter Erquinigo         if (schema.empty())
262ea1f4974SWalter Erquinigo           break;
26374c93956SWalter Erquinigo 
264ea1f4974SWalter Erquinigo         result.AppendMessage(schema);
265ea1f4974SWalter Erquinigo       }
26674c93956SWalter Erquinigo     } else {
267ea1f4974SWalter Erquinigo       if (Expected<StringRef> schemaOrErr =
268ea1f4974SWalter Erquinigo               Trace::FindPluginSchema(plugin_name))
269ea1f4974SWalter Erquinigo         result.AppendMessage(*schemaOrErr);
270ea1f4974SWalter Erquinigo       else
271ea1f4974SWalter Erquinigo         error = schemaOrErr.takeError();
27274c93956SWalter Erquinigo     }
27374c93956SWalter Erquinigo 
27474c93956SWalter Erquinigo     if (error.Success()) {
27574c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
27674c93956SWalter Erquinigo     } else {
27774c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
27874c93956SWalter Erquinigo     }
27974c93956SWalter Erquinigo     return result.Succeeded();
28074c93956SWalter Erquinigo   }
28174c93956SWalter Erquinigo 
28274c93956SWalter Erquinigo   CommandOptions m_options;
28374c93956SWalter Erquinigo };
28474c93956SWalter Erquinigo 
28574c93956SWalter Erquinigo // CommandObjectTrace
28674c93956SWalter Erquinigo 
28774c93956SWalter Erquinigo CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
28874c93956SWalter Erquinigo     : CommandObjectMultiword(interpreter, "trace",
28974c93956SWalter Erquinigo                              "Commands for loading and using processor "
29074c93956SWalter Erquinigo                              "trace information.",
29174c93956SWalter Erquinigo                              "trace [<sub-command-options>]") {
29274c93956SWalter Erquinigo   LoadSubCommand("load",
29374c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
29474c93956SWalter Erquinigo   LoadSubCommand("dump",
29574c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceDump(interpreter)));
29674c93956SWalter Erquinigo   LoadSubCommand("schema",
29774c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
29874c93956SWalter Erquinigo }
29974c93956SWalter Erquinigo 
30074c93956SWalter Erquinigo CommandObjectTrace::~CommandObjectTrace() = default;
3010b697561SWalter Erquinigo 
3020b697561SWalter Erquinigo Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
3030b697561SWalter Erquinigo   ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();
3040b697561SWalter Erquinigo 
3050b697561SWalter Erquinigo   if (!process_sp)
3060b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
3070b697561SWalter Erquinigo                              "Process not available.");
3080b697561SWalter Erquinigo   if (m_live_debug_session_only && !process_sp->IsLiveDebugSession())
3090b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
3100b697561SWalter Erquinigo                              "Process must be alive.");
3110b697561SWalter Erquinigo 
312bf9f21a2SWalter Erquinigo   if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
3130b697561SWalter Erquinigo     return GetDelegateCommand(**trace_sp);
3140b697561SWalter Erquinigo   else
3150b697561SWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
3160b697561SWalter Erquinigo                              "Tracing is not supported. %s",
3170b697561SWalter Erquinigo                              toString(trace_sp.takeError()).c_str());
3180b697561SWalter Erquinigo }
3190b697561SWalter Erquinigo 
3200b697561SWalter Erquinigo CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() {
3210b697561SWalter Erquinigo   if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {
3220b697561SWalter Erquinigo     m_delegate_sp = *delegate;
3230b697561SWalter Erquinigo     m_delegate_error.clear();
3240b697561SWalter Erquinigo     return m_delegate_sp.get();
3250b697561SWalter Erquinigo   } else {
3260b697561SWalter Erquinigo     m_delegate_sp.reset();
3270b697561SWalter Erquinigo     m_delegate_error = toString(delegate.takeError());
3280b697561SWalter Erquinigo     return nullptr;
3290b697561SWalter Erquinigo   }
3300b697561SWalter Erquinigo }
331