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-exception
6 //
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/CommandReturnObject.h"
20 #include "lldb/Interpreter/OptionArgParser.h"
21 #include "lldb/Interpreter/OptionGroupFormat.h"
22 #include "lldb/Interpreter/OptionValueBoolean.h"
23 #include "lldb/Interpreter/OptionValueLanguage.h"
24 #include "lldb/Interpreter/OptionValueString.h"
25 #include "lldb/Interpreter/Options.h"
26 #include "lldb/Target/Trace.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace llvm;
31
32 // CommandObjectTraceLoad
33 #define LLDB_OPTIONS_trace_load
34 #include "CommandOptions.inc"
35
36 #pragma mark CommandObjectTraceLoad
37
38 class CommandObjectTraceLoad : public CommandObjectParsed {
39 public:
40 class CommandOptions : public Options {
41 public:
CommandOptions()42 CommandOptions() : Options() { OptionParsingStarting(nullptr); }
43
44 ~CommandOptions() override = default;
45
SetOptionValue(uint32_t option_idx,StringRef option_arg,ExecutionContext * execution_context)46 Status SetOptionValue(uint32_t option_idx, 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 'v': {
53 m_verbose = true;
54 break;
55 }
56 default:
57 llvm_unreachable("Unimplemented option");
58 }
59 return error;
60 }
61
OptionParsingStarting(ExecutionContext * execution_context)62 void OptionParsingStarting(ExecutionContext *execution_context) override {
63 m_verbose = false;
64 }
65
GetDefinitions()66 ArrayRef<OptionDefinition> GetDefinitions() override {
67 return makeArrayRef(g_trace_load_options);
68 }
69
70 bool m_verbose; // Enable verbose logging for debugging purposes.
71 };
72
CommandObjectTraceLoad(CommandInterpreter & interpreter)73 CommandObjectTraceLoad(CommandInterpreter &interpreter)
74 : CommandObjectParsed(interpreter, "trace load",
75 "Load a processor trace session from a JSON file.",
76 "trace load"),
77 m_options() {}
78
79 ~CommandObjectTraceLoad() override = default;
80
GetOptions()81 Options *GetOptions() override { return &m_options; }
82
83 protected:
DoExecute(Args & command,CommandReturnObject & result)84 bool DoExecute(Args &command, CommandReturnObject &result) override {
85 if (command.size() != 1) {
86 result.AppendError(
87 "a single path to a JSON file containing a trace session"
88 "is required");
89 result.SetStatus(eReturnStatusFailed);
90 return false;
91 }
92
93 auto end_with_failure = [&result](llvm::Error err) -> bool {
94 result.AppendErrorWithFormat("%s\n",
95 llvm::toString(std::move(err)).c_str());
96 result.SetStatus(eReturnStatusFailed);
97 return false;
98 };
99
100 FileSpec json_file(command[0].ref());
101
102 auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
103 if (!buffer_or_error) {
104 return end_with_failure(llvm::createStringError(
105 std::errc::invalid_argument, "could not open input file: %s - %s.",
106 json_file.GetPath().c_str(),
107 buffer_or_error.getError().message().c_str()));
108 }
109
110 llvm::Expected<json::Value> session_file =
111 json::parse(buffer_or_error.get()->getBuffer().str());
112 if (!session_file)
113 return end_with_failure(session_file.takeError());
114
115 if (Expected<lldb::TraceSP> traceOrErr =
116 Trace::FindPlugin(GetDebugger(), *session_file,
117 json_file.GetDirectory().AsCString())) {
118 lldb::TraceSP trace_sp = traceOrErr.get();
119 if (m_options.m_verbose)
120 result.AppendMessageWithFormat("loading trace with plugin %s\n",
121 trace_sp->GetPluginName().AsCString());
122 } else
123 return end_with_failure(traceOrErr.takeError());
124
125 result.SetStatus(eReturnStatusSuccessFinishResult);
126 return true;
127 }
128
129 CommandOptions m_options;
130 };
131
132 // CommandObjectTraceDump
133 #define LLDB_OPTIONS_trace_dump
134 #include "CommandOptions.inc"
135
136 #pragma mark CommandObjectTraceDump
137
138 class CommandObjectTraceDump : public CommandObjectParsed {
139 public:
140 class CommandOptions : public Options {
141 public:
CommandOptions()142 CommandOptions() : Options() { OptionParsingStarting(nullptr); }
143
144 ~CommandOptions() override = default;
145
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)146 Status SetOptionValue(uint32_t option_idx, llvm::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
OptionParsingStarting(ExecutionContext * execution_context)162 void OptionParsingStarting(ExecutionContext *execution_context) override {
163 m_verbose = false;
164 }
165
GetDefinitions()166 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
167 return llvm::makeArrayRef(g_trace_dump_options);
168 }
169
170 bool m_verbose; // Enable verbose logging for debugging purposes.
171 };
172
CommandObjectTraceDump(CommandInterpreter & interpreter)173 CommandObjectTraceDump(CommandInterpreter &interpreter)
174 : CommandObjectParsed(interpreter, "trace dump",
175 "Dump the loaded processor trace data.",
176 "trace dump"),
177 m_options() {}
178
179 ~CommandObjectTraceDump() override = default;
180
GetOptions()181 Options *GetOptions() override { return &m_options; }
182
183 protected:
DoExecute(Args & command,CommandReturnObject & result)184 bool DoExecute(Args &command, CommandReturnObject &result) override {
185 Status error;
186 // TODO: fill in the dumping code here!
187 if (error.Success()) {
188 result.SetStatus(eReturnStatusSuccessFinishResult);
189 } else {
190 result.AppendErrorWithFormat("%s\n", error.AsCString());
191 result.SetStatus(eReturnStatusFailed);
192 }
193 return result.Succeeded();
194 }
195
196 CommandOptions m_options;
197 };
198
199 // CommandObjectTraceSchema
200 #define LLDB_OPTIONS_trace_schema
201 #include "CommandOptions.inc"
202
203 #pragma mark CommandObjectTraceSchema
204
205 class CommandObjectTraceSchema : public CommandObjectParsed {
206 public:
207 class CommandOptions : public Options {
208 public:
CommandOptions()209 CommandOptions() : Options() { OptionParsingStarting(nullptr); }
210
211 ~CommandOptions() override = default;
212
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)213 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
214 ExecutionContext *execution_context) override {
215 Status error;
216 const int short_option = m_getopt_table[option_idx].val;
217
218 switch (short_option) {
219 case 'v': {
220 m_verbose = true;
221 break;
222 }
223 default:
224 llvm_unreachable("Unimplemented option");
225 }
226 return error;
227 }
228
OptionParsingStarting(ExecutionContext * execution_context)229 void OptionParsingStarting(ExecutionContext *execution_context) override {
230 m_verbose = false;
231 }
232
GetDefinitions()233 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
234 return llvm::makeArrayRef(g_trace_schema_options);
235 }
236
237 bool m_verbose; // Enable verbose logging for debugging purposes.
238 };
239
CommandObjectTraceSchema(CommandInterpreter & interpreter)240 CommandObjectTraceSchema(CommandInterpreter &interpreter)
241 : CommandObjectParsed(interpreter, "trace schema",
242 "Show the schema of the given trace plugin.",
243 "trace schema <plug-in>. Use the plug-in name "
244 "\"all\" to see all schemas.\n"),
245 m_options() {}
246
247 ~CommandObjectTraceSchema() override = default;
248
GetOptions()249 Options *GetOptions() override { return &m_options; }
250
251 protected:
DoExecute(Args & command,CommandReturnObject & result)252 bool DoExecute(Args &command, CommandReturnObject &result) override {
253 Status error;
254 if (command.empty()) {
255 result.SetError(
256 "trace schema cannot be invoked without a plug-in as argument");
257 return false;
258 }
259
260 StringRef plugin_name(command[0].c_str());
261 if (plugin_name == "all") {
262 size_t index = 0;
263 while (true) {
264 StringRef schema = PluginManager::GetTraceSchema(index++);
265 if (schema.empty())
266 break;
267
268 result.AppendMessage(schema);
269 }
270 } else {
271 if (Expected<StringRef> schemaOrErr =
272 Trace::FindPluginSchema(plugin_name))
273 result.AppendMessage(*schemaOrErr);
274 else
275 error = schemaOrErr.takeError();
276 }
277
278 if (error.Success()) {
279 result.SetStatus(eReturnStatusSuccessFinishResult);
280 } else {
281 result.AppendErrorWithFormat("%s\n", error.AsCString());
282 result.SetStatus(eReturnStatusFailed);
283 }
284 return result.Succeeded();
285 }
286
287 CommandOptions m_options;
288 };
289
290 // CommandObjectTrace
291
CommandObjectTrace(CommandInterpreter & interpreter)292 CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
293 : CommandObjectMultiword(interpreter, "trace",
294 "Commands for loading and using processor "
295 "trace information.",
296 "trace [<sub-command-options>]") {
297 LoadSubCommand("load",
298 CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
299 LoadSubCommand("dump",
300 CommandObjectSP(new CommandObjectTraceDump(interpreter)));
301 LoadSubCommand("schema",
302 CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
303 }
304
305 CommandObjectTrace::~CommandObjectTrace() = default;
306