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"
2674c93956SWalter Erquinigo #include "lldb/Target/Trace.h"
2774c93956SWalter Erquinigo 
2874c93956SWalter Erquinigo using namespace lldb;
2974c93956SWalter Erquinigo using namespace lldb_private;
3074c93956SWalter Erquinigo using namespace llvm;
3174c93956SWalter Erquinigo 
3274c93956SWalter Erquinigo // CommandObjectTraceLoad
3374c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_load
3474c93956SWalter Erquinigo #include "CommandOptions.inc"
3574c93956SWalter Erquinigo 
3674c93956SWalter Erquinigo #pragma mark CommandObjectTraceLoad
3774c93956SWalter Erquinigo 
3874c93956SWalter Erquinigo class CommandObjectTraceLoad : public CommandObjectParsed {
3974c93956SWalter Erquinigo public:
4074c93956SWalter Erquinigo   class CommandOptions : public Options {
4174c93956SWalter Erquinigo   public:
4274c93956SWalter Erquinigo     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
4374c93956SWalter Erquinigo 
4474c93956SWalter Erquinigo     ~CommandOptions() override = default;
4574c93956SWalter Erquinigo 
4674c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
4774c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
4874c93956SWalter Erquinigo       Status error;
4974c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
5074c93956SWalter Erquinigo 
5174c93956SWalter Erquinigo       switch (short_option) {
5274c93956SWalter Erquinigo       case 'v': {
5374c93956SWalter Erquinigo         m_verbose = true;
5474c93956SWalter Erquinigo         break;
5574c93956SWalter Erquinigo       }
5674c93956SWalter Erquinigo       default:
5774c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
5874c93956SWalter Erquinigo       }
5974c93956SWalter Erquinigo       return error;
6074c93956SWalter Erquinigo     }
6174c93956SWalter Erquinigo 
6274c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
6374c93956SWalter Erquinigo       m_verbose = false;
6474c93956SWalter Erquinigo     }
6574c93956SWalter Erquinigo 
6674c93956SWalter Erquinigo     ArrayRef<OptionDefinition> GetDefinitions() override {
6774c93956SWalter Erquinigo       return makeArrayRef(g_trace_load_options);
6874c93956SWalter Erquinigo     }
6974c93956SWalter Erquinigo 
7074c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
7174c93956SWalter Erquinigo   };
7274c93956SWalter Erquinigo 
7374c93956SWalter Erquinigo   CommandObjectTraceLoad(CommandInterpreter &interpreter)
7474c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace load",
75ea1f4974SWalter Erquinigo                             "Load a processor trace session from a JSON file.",
7674c93956SWalter Erquinigo                             "trace load"),
7774c93956SWalter Erquinigo         m_options() {}
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       result.SetStatus(eReturnStatusFailed);
9074c93956SWalter Erquinigo       return false;
9174c93956SWalter Erquinigo     }
9274c93956SWalter Erquinigo 
9374c93956SWalter Erquinigo     auto end_with_failure = [&result](llvm::Error err) -> bool {
9474c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n",
9574c93956SWalter Erquinigo                                    llvm::toString(std::move(err)).c_str());
9674c93956SWalter Erquinigo       result.SetStatus(eReturnStatusFailed);
9774c93956SWalter Erquinigo       return false;
9874c93956SWalter Erquinigo     };
9974c93956SWalter Erquinigo 
10074c93956SWalter Erquinigo     FileSpec json_file(command[0].ref());
10174c93956SWalter Erquinigo 
10274c93956SWalter Erquinigo     auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
10374c93956SWalter Erquinigo     if (!buffer_or_error) {
10474c93956SWalter Erquinigo       return end_with_failure(llvm::createStringError(
10574c93956SWalter Erquinigo           std::errc::invalid_argument, "could not open input file: %s - %s.",
10674c93956SWalter Erquinigo           json_file.GetPath().c_str(),
10774c93956SWalter Erquinigo           buffer_or_error.getError().message().c_str()));
10874c93956SWalter Erquinigo     }
10974c93956SWalter Erquinigo 
110ea1f4974SWalter Erquinigo     llvm::Expected<json::Value> session_file =
11174c93956SWalter Erquinigo         json::parse(buffer_or_error.get()->getBuffer().str());
112ea1f4974SWalter Erquinigo     if (!session_file)
113ea1f4974SWalter Erquinigo       return end_with_failure(session_file.takeError());
11474c93956SWalter Erquinigo 
115ea1f4974SWalter Erquinigo     if (Expected<lldb::TraceSP> traceOrErr =
116ea1f4974SWalter Erquinigo             Trace::FindPlugin(GetDebugger(), *session_file,
117ea1f4974SWalter Erquinigo                               json_file.GetDirectory().AsCString())) {
11874c93956SWalter Erquinigo       lldb::TraceSP trace_sp = traceOrErr.get();
119*801067f4SStella Stamenova       if (m_options.m_verbose && trace_sp)
12074c93956SWalter Erquinigo         result.AppendMessageWithFormat("loading trace with plugin %s\n",
12174c93956SWalter Erquinigo                                        trace_sp->GetPluginName().AsCString());
12274c93956SWalter Erquinigo     } else
12374c93956SWalter Erquinigo       return end_with_failure(traceOrErr.takeError());
12474c93956SWalter Erquinigo 
12574c93956SWalter Erquinigo     result.SetStatus(eReturnStatusSuccessFinishResult);
12674c93956SWalter Erquinigo     return true;
12774c93956SWalter Erquinigo   }
12874c93956SWalter Erquinigo 
12974c93956SWalter Erquinigo   CommandOptions m_options;
13074c93956SWalter Erquinigo };
13174c93956SWalter Erquinigo 
13274c93956SWalter Erquinigo // CommandObjectTraceDump
13374c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_dump
13474c93956SWalter Erquinigo #include "CommandOptions.inc"
13574c93956SWalter Erquinigo 
13674c93956SWalter Erquinigo #pragma mark CommandObjectTraceDump
13774c93956SWalter Erquinigo 
13874c93956SWalter Erquinigo class CommandObjectTraceDump : public CommandObjectParsed {
13974c93956SWalter Erquinigo public:
14074c93956SWalter Erquinigo   class CommandOptions : public Options {
14174c93956SWalter Erquinigo   public:
14274c93956SWalter Erquinigo     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
14374c93956SWalter Erquinigo 
14474c93956SWalter Erquinigo     ~CommandOptions() override = default;
14574c93956SWalter Erquinigo 
14674c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
14774c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
14874c93956SWalter Erquinigo       Status error;
14974c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
15074c93956SWalter Erquinigo 
15174c93956SWalter Erquinigo       switch (short_option) {
15274c93956SWalter Erquinigo       case 'v': {
15374c93956SWalter Erquinigo         m_verbose = true;
15474c93956SWalter Erquinigo         break;
15574c93956SWalter Erquinigo       }
15674c93956SWalter Erquinigo       default:
15774c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
15874c93956SWalter Erquinigo       }
15974c93956SWalter Erquinigo       return error;
16074c93956SWalter Erquinigo     }
16174c93956SWalter Erquinigo 
16274c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
16374c93956SWalter Erquinigo       m_verbose = false;
16474c93956SWalter Erquinigo     }
16574c93956SWalter Erquinigo 
16674c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
16774c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_dump_options);
16874c93956SWalter Erquinigo     }
16974c93956SWalter Erquinigo 
17074c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
17174c93956SWalter Erquinigo   };
17274c93956SWalter Erquinigo 
17374c93956SWalter Erquinigo   CommandObjectTraceDump(CommandInterpreter &interpreter)
17474c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace dump",
17574c93956SWalter Erquinigo                             "Dump the loaded processor trace data.",
17674c93956SWalter Erquinigo                             "trace dump"),
17774c93956SWalter Erquinigo         m_options() {}
17874c93956SWalter Erquinigo 
17974c93956SWalter Erquinigo   ~CommandObjectTraceDump() override = default;
18074c93956SWalter Erquinigo 
18174c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
18274c93956SWalter Erquinigo 
18374c93956SWalter Erquinigo protected:
18474c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
18574c93956SWalter Erquinigo     Status error;
18674c93956SWalter Erquinigo     // TODO: fill in the dumping code here!
18774c93956SWalter Erquinigo     if (error.Success()) {
18874c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
18974c93956SWalter Erquinigo     } else {
19074c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
19174c93956SWalter Erquinigo       result.SetStatus(eReturnStatusFailed);
19274c93956SWalter Erquinigo     }
19374c93956SWalter Erquinigo     return result.Succeeded();
19474c93956SWalter Erquinigo   }
19574c93956SWalter Erquinigo 
19674c93956SWalter Erquinigo   CommandOptions m_options;
19774c93956SWalter Erquinigo };
19874c93956SWalter Erquinigo 
19974c93956SWalter Erquinigo // CommandObjectTraceSchema
20074c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_schema
20174c93956SWalter Erquinigo #include "CommandOptions.inc"
20274c93956SWalter Erquinigo 
20374c93956SWalter Erquinigo #pragma mark CommandObjectTraceSchema
20474c93956SWalter Erquinigo 
20574c93956SWalter Erquinigo class CommandObjectTraceSchema : public CommandObjectParsed {
20674c93956SWalter Erquinigo public:
20774c93956SWalter Erquinigo   class CommandOptions : public Options {
20874c93956SWalter Erquinigo   public:
20974c93956SWalter Erquinigo     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
21074c93956SWalter Erquinigo 
21174c93956SWalter Erquinigo     ~CommandOptions() override = default;
21274c93956SWalter Erquinigo 
21374c93956SWalter Erquinigo     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
21474c93956SWalter Erquinigo                           ExecutionContext *execution_context) override {
21574c93956SWalter Erquinigo       Status error;
21674c93956SWalter Erquinigo       const int short_option = m_getopt_table[option_idx].val;
21774c93956SWalter Erquinigo 
21874c93956SWalter Erquinigo       switch (short_option) {
21974c93956SWalter Erquinigo       case 'v': {
22074c93956SWalter Erquinigo         m_verbose = true;
22174c93956SWalter Erquinigo         break;
22274c93956SWalter Erquinigo       }
22374c93956SWalter Erquinigo       default:
22474c93956SWalter Erquinigo         llvm_unreachable("Unimplemented option");
22574c93956SWalter Erquinigo       }
22674c93956SWalter Erquinigo       return error;
22774c93956SWalter Erquinigo     }
22874c93956SWalter Erquinigo 
22974c93956SWalter Erquinigo     void OptionParsingStarting(ExecutionContext *execution_context) override {
23074c93956SWalter Erquinigo       m_verbose = false;
23174c93956SWalter Erquinigo     }
23274c93956SWalter Erquinigo 
23374c93956SWalter Erquinigo     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
23474c93956SWalter Erquinigo       return llvm::makeArrayRef(g_trace_schema_options);
23574c93956SWalter Erquinigo     }
23674c93956SWalter Erquinigo 
23774c93956SWalter Erquinigo     bool m_verbose; // Enable verbose logging for debugging purposes.
23874c93956SWalter Erquinigo   };
23974c93956SWalter Erquinigo 
24074c93956SWalter Erquinigo   CommandObjectTraceSchema(CommandInterpreter &interpreter)
24174c93956SWalter Erquinigo       : CommandObjectParsed(interpreter, "trace schema",
24274c93956SWalter Erquinigo                             "Show the schema of the given trace plugin.",
243ea1f4974SWalter Erquinigo                             "trace schema <plug-in>. Use the plug-in name "
244ea1f4974SWalter Erquinigo                             "\"all\" to see all schemas.\n"),
24574c93956SWalter Erquinigo         m_options() {}
24674c93956SWalter Erquinigo 
24774c93956SWalter Erquinigo   ~CommandObjectTraceSchema() override = default;
24874c93956SWalter Erquinigo 
24974c93956SWalter Erquinigo   Options *GetOptions() override { return &m_options; }
25074c93956SWalter Erquinigo 
25174c93956SWalter Erquinigo protected:
25274c93956SWalter Erquinigo   bool DoExecute(Args &command, CommandReturnObject &result) override {
25374c93956SWalter Erquinigo     Status error;
25474c93956SWalter Erquinigo     if (command.empty()) {
25574c93956SWalter Erquinigo       result.SetError(
25674c93956SWalter Erquinigo           "trace schema cannot be invoked without a plug-in as argument");
25774c93956SWalter Erquinigo       return false;
25874c93956SWalter Erquinigo     }
25974c93956SWalter Erquinigo 
26074c93956SWalter Erquinigo     StringRef plugin_name(command[0].c_str());
261ea1f4974SWalter Erquinigo     if (plugin_name == "all") {
262ea1f4974SWalter Erquinigo       size_t index = 0;
263ea1f4974SWalter Erquinigo       while (true) {
264ea1f4974SWalter Erquinigo         StringRef schema = PluginManager::GetTraceSchema(index++);
265ea1f4974SWalter Erquinigo         if (schema.empty())
266ea1f4974SWalter Erquinigo           break;
26774c93956SWalter Erquinigo 
268ea1f4974SWalter Erquinigo         result.AppendMessage(schema);
269ea1f4974SWalter Erquinigo       }
27074c93956SWalter Erquinigo     } else {
271ea1f4974SWalter Erquinigo       if (Expected<StringRef> schemaOrErr =
272ea1f4974SWalter Erquinigo               Trace::FindPluginSchema(plugin_name))
273ea1f4974SWalter Erquinigo         result.AppendMessage(*schemaOrErr);
274ea1f4974SWalter Erquinigo       else
275ea1f4974SWalter Erquinigo         error = schemaOrErr.takeError();
27674c93956SWalter Erquinigo     }
27774c93956SWalter Erquinigo 
27874c93956SWalter Erquinigo     if (error.Success()) {
27974c93956SWalter Erquinigo       result.SetStatus(eReturnStatusSuccessFinishResult);
28074c93956SWalter Erquinigo     } else {
28174c93956SWalter Erquinigo       result.AppendErrorWithFormat("%s\n", error.AsCString());
28274c93956SWalter Erquinigo       result.SetStatus(eReturnStatusFailed);
28374c93956SWalter Erquinigo     }
28474c93956SWalter Erquinigo     return result.Succeeded();
28574c93956SWalter Erquinigo   }
28674c93956SWalter Erquinigo 
28774c93956SWalter Erquinigo   CommandOptions m_options;
28874c93956SWalter Erquinigo };
28974c93956SWalter Erquinigo 
29074c93956SWalter Erquinigo // CommandObjectTrace
29174c93956SWalter Erquinigo 
29274c93956SWalter Erquinigo CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
29374c93956SWalter Erquinigo     : CommandObjectMultiword(interpreter, "trace",
29474c93956SWalter Erquinigo                              "Commands for loading and using processor "
29574c93956SWalter Erquinigo                              "trace information.",
29674c93956SWalter Erquinigo                              "trace [<sub-command-options>]") {
29774c93956SWalter Erquinigo   LoadSubCommand("load",
29874c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
29974c93956SWalter Erquinigo   LoadSubCommand("dump",
30074c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceDump(interpreter)));
30174c93956SWalter Erquinigo   LoadSubCommand("schema",
30274c93956SWalter Erquinigo                  CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
30374c93956SWalter Erquinigo }
30474c93956SWalter Erquinigo 
30574c93956SWalter Erquinigo CommandObjectTrace::~CommandObjectTrace() = default;
306