1af732203SDimitry Andric //===-- CommandObjectTrace.cpp --------------------------------------------===//
2af732203SDimitry Andric //
3af732203SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af732203SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5af732203SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af732203SDimitry Andric //
7af732203SDimitry Andric //===----------------------------------------------------------------------===//
8af732203SDimitry Andric
9af732203SDimitry Andric #include "CommandObjectTrace.h"
10af732203SDimitry Andric
11af732203SDimitry Andric #include "llvm/Support/JSON.h"
12af732203SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
13af732203SDimitry Andric
14af732203SDimitry Andric #include "lldb/Core/Debugger.h"
15af732203SDimitry Andric #include "lldb/Core/PluginManager.h"
16af732203SDimitry Andric #include "lldb/Host/OptionParser.h"
17af732203SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
18af732203SDimitry Andric #include "lldb/Interpreter/CommandObject.h"
19af732203SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
20af732203SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
21af732203SDimitry Andric #include "lldb/Interpreter/OptionGroupFormat.h"
22af732203SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
23af732203SDimitry Andric #include "lldb/Interpreter/OptionValueLanguage.h"
24af732203SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
25af732203SDimitry Andric #include "lldb/Interpreter/Options.h"
26*5f7ddb14SDimitry Andric #include "lldb/Target/Process.h"
27af732203SDimitry Andric #include "lldb/Target/Trace.h"
28af732203SDimitry Andric
29af732203SDimitry Andric using namespace lldb;
30af732203SDimitry Andric using namespace lldb_private;
31af732203SDimitry Andric using namespace llvm;
32af732203SDimitry Andric
33af732203SDimitry Andric // CommandObjectTraceLoad
34af732203SDimitry Andric #define LLDB_OPTIONS_trace_load
35af732203SDimitry Andric #include "CommandOptions.inc"
36af732203SDimitry Andric
37af732203SDimitry Andric #pragma mark CommandObjectTraceLoad
38af732203SDimitry Andric
39af732203SDimitry Andric class CommandObjectTraceLoad : public CommandObjectParsed {
40af732203SDimitry Andric public:
41af732203SDimitry Andric class CommandOptions : public Options {
42af732203SDimitry Andric public:
CommandOptions()43af732203SDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); }
44af732203SDimitry Andric
45af732203SDimitry Andric ~CommandOptions() override = default;
46af732203SDimitry Andric
SetOptionValue(uint32_t option_idx,StringRef option_arg,ExecutionContext * execution_context)47af732203SDimitry Andric Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
48af732203SDimitry Andric ExecutionContext *execution_context) override {
49af732203SDimitry Andric Status error;
50af732203SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
51af732203SDimitry Andric
52af732203SDimitry Andric switch (short_option) {
53af732203SDimitry Andric case 'v': {
54af732203SDimitry Andric m_verbose = true;
55af732203SDimitry Andric break;
56af732203SDimitry Andric }
57af732203SDimitry Andric default:
58af732203SDimitry Andric llvm_unreachable("Unimplemented option");
59af732203SDimitry Andric }
60af732203SDimitry Andric return error;
61af732203SDimitry Andric }
62af732203SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)63af732203SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
64af732203SDimitry Andric m_verbose = false;
65af732203SDimitry Andric }
66af732203SDimitry Andric
GetDefinitions()67af732203SDimitry Andric ArrayRef<OptionDefinition> GetDefinitions() override {
68af732203SDimitry Andric return makeArrayRef(g_trace_load_options);
69af732203SDimitry Andric }
70af732203SDimitry Andric
71af732203SDimitry Andric bool m_verbose; // Enable verbose logging for debugging purposes.
72af732203SDimitry Andric };
73af732203SDimitry Andric
CommandObjectTraceLoad(CommandInterpreter & interpreter)74af732203SDimitry Andric CommandObjectTraceLoad(CommandInterpreter &interpreter)
75af732203SDimitry Andric : CommandObjectParsed(interpreter, "trace load",
76af732203SDimitry Andric "Load a processor trace session from a JSON file.",
77af732203SDimitry Andric "trace load"),
78af732203SDimitry Andric m_options() {}
79af732203SDimitry Andric
80af732203SDimitry Andric ~CommandObjectTraceLoad() override = default;
81af732203SDimitry Andric
GetOptions()82af732203SDimitry Andric Options *GetOptions() override { return &m_options; }
83af732203SDimitry Andric
84af732203SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)85af732203SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
86af732203SDimitry Andric if (command.size() != 1) {
87af732203SDimitry Andric result.AppendError(
88af732203SDimitry Andric "a single path to a JSON file containing a trace session"
89af732203SDimitry Andric "is required");
90af732203SDimitry Andric return false;
91af732203SDimitry Andric }
92af732203SDimitry Andric
93af732203SDimitry Andric auto end_with_failure = [&result](llvm::Error err) -> bool {
94af732203SDimitry Andric result.AppendErrorWithFormat("%s\n",
95af732203SDimitry Andric llvm::toString(std::move(err)).c_str());
96af732203SDimitry Andric return false;
97af732203SDimitry Andric };
98af732203SDimitry Andric
99af732203SDimitry Andric FileSpec json_file(command[0].ref());
100af732203SDimitry Andric
101af732203SDimitry Andric auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
102af732203SDimitry Andric if (!buffer_or_error) {
103af732203SDimitry Andric return end_with_failure(llvm::createStringError(
104af732203SDimitry Andric std::errc::invalid_argument, "could not open input file: %s - %s.",
105af732203SDimitry Andric json_file.GetPath().c_str(),
106af732203SDimitry Andric buffer_or_error.getError().message().c_str()));
107af732203SDimitry Andric }
108af732203SDimitry Andric
109af732203SDimitry Andric llvm::Expected<json::Value> session_file =
110af732203SDimitry Andric json::parse(buffer_or_error.get()->getBuffer().str());
111af732203SDimitry Andric if (!session_file)
112af732203SDimitry Andric return end_with_failure(session_file.takeError());
113af732203SDimitry Andric
114af732203SDimitry Andric if (Expected<lldb::TraceSP> traceOrErr =
115*5f7ddb14SDimitry Andric Trace::FindPluginForPostMortemProcess(
116*5f7ddb14SDimitry Andric GetDebugger(), *session_file,
117af732203SDimitry Andric json_file.GetDirectory().AsCString())) {
118af732203SDimitry Andric lldb::TraceSP trace_sp = traceOrErr.get();
119*5f7ddb14SDimitry Andric if (m_options.m_verbose && trace_sp)
120af732203SDimitry Andric result.AppendMessageWithFormat("loading trace with plugin %s\n",
121af732203SDimitry Andric trace_sp->GetPluginName().AsCString());
122af732203SDimitry Andric } else
123af732203SDimitry Andric return end_with_failure(traceOrErr.takeError());
124af732203SDimitry Andric
125af732203SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
126af732203SDimitry Andric return true;
127af732203SDimitry Andric }
128af732203SDimitry Andric
129af732203SDimitry Andric CommandOptions m_options;
130af732203SDimitry Andric };
131af732203SDimitry Andric
132af732203SDimitry Andric // CommandObjectTraceDump
133af732203SDimitry Andric #define LLDB_OPTIONS_trace_dump
134af732203SDimitry Andric #include "CommandOptions.inc"
135af732203SDimitry Andric
136af732203SDimitry Andric #pragma mark CommandObjectTraceDump
137af732203SDimitry Andric
138af732203SDimitry Andric class CommandObjectTraceDump : public CommandObjectParsed {
139af732203SDimitry Andric public:
140af732203SDimitry Andric class CommandOptions : public Options {
141af732203SDimitry Andric public:
CommandOptions()142af732203SDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); }
143af732203SDimitry Andric
144af732203SDimitry Andric ~CommandOptions() override = default;
145af732203SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)146af732203SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
147af732203SDimitry Andric ExecutionContext *execution_context) override {
148af732203SDimitry Andric Status error;
149af732203SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
150af732203SDimitry Andric
151af732203SDimitry Andric switch (short_option) {
152af732203SDimitry Andric case 'v': {
153af732203SDimitry Andric m_verbose = true;
154af732203SDimitry Andric break;
155af732203SDimitry Andric }
156af732203SDimitry Andric default:
157af732203SDimitry Andric llvm_unreachable("Unimplemented option");
158af732203SDimitry Andric }
159af732203SDimitry Andric return error;
160af732203SDimitry Andric }
161af732203SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)162af732203SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
163af732203SDimitry Andric m_verbose = false;
164af732203SDimitry Andric }
165af732203SDimitry Andric
GetDefinitions()166af732203SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
167af732203SDimitry Andric return llvm::makeArrayRef(g_trace_dump_options);
168af732203SDimitry Andric }
169af732203SDimitry Andric
170af732203SDimitry Andric bool m_verbose; // Enable verbose logging for debugging purposes.
171af732203SDimitry Andric };
172af732203SDimitry Andric
CommandObjectTraceDump(CommandInterpreter & interpreter)173af732203SDimitry Andric CommandObjectTraceDump(CommandInterpreter &interpreter)
174af732203SDimitry Andric : CommandObjectParsed(interpreter, "trace dump",
175af732203SDimitry Andric "Dump the loaded processor trace data.",
176af732203SDimitry Andric "trace dump"),
177af732203SDimitry Andric m_options() {}
178af732203SDimitry Andric
179af732203SDimitry Andric ~CommandObjectTraceDump() override = default;
180af732203SDimitry Andric
GetOptions()181af732203SDimitry Andric Options *GetOptions() override { return &m_options; }
182af732203SDimitry Andric
183af732203SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)184af732203SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
185af732203SDimitry Andric Status error;
186af732203SDimitry Andric // TODO: fill in the dumping code here!
187af732203SDimitry Andric if (error.Success()) {
188af732203SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
189af732203SDimitry Andric } else {
190af732203SDimitry Andric result.AppendErrorWithFormat("%s\n", error.AsCString());
191af732203SDimitry Andric }
192af732203SDimitry Andric return result.Succeeded();
193af732203SDimitry Andric }
194af732203SDimitry Andric
195af732203SDimitry Andric CommandOptions m_options;
196af732203SDimitry Andric };
197af732203SDimitry Andric
198af732203SDimitry Andric // CommandObjectTraceSchema
199af732203SDimitry Andric #define LLDB_OPTIONS_trace_schema
200af732203SDimitry Andric #include "CommandOptions.inc"
201af732203SDimitry Andric
202af732203SDimitry Andric #pragma mark CommandObjectTraceSchema
203af732203SDimitry Andric
204af732203SDimitry Andric class CommandObjectTraceSchema : public CommandObjectParsed {
205af732203SDimitry Andric public:
206af732203SDimitry Andric class CommandOptions : public Options {
207af732203SDimitry Andric public:
CommandOptions()208af732203SDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); }
209af732203SDimitry Andric
210af732203SDimitry Andric ~CommandOptions() override = default;
211af732203SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)212af732203SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
213af732203SDimitry Andric ExecutionContext *execution_context) override {
214af732203SDimitry Andric Status error;
215af732203SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
216af732203SDimitry Andric
217af732203SDimitry Andric switch (short_option) {
218af732203SDimitry Andric case 'v': {
219af732203SDimitry Andric m_verbose = true;
220af732203SDimitry Andric break;
221af732203SDimitry Andric }
222af732203SDimitry Andric default:
223af732203SDimitry Andric llvm_unreachable("Unimplemented option");
224af732203SDimitry Andric }
225af732203SDimitry Andric return error;
226af732203SDimitry Andric }
227af732203SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)228af732203SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
229af732203SDimitry Andric m_verbose = false;
230af732203SDimitry Andric }
231af732203SDimitry Andric
GetDefinitions()232af732203SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
233af732203SDimitry Andric return llvm::makeArrayRef(g_trace_schema_options);
234af732203SDimitry Andric }
235af732203SDimitry Andric
236af732203SDimitry Andric bool m_verbose; // Enable verbose logging for debugging purposes.
237af732203SDimitry Andric };
238af732203SDimitry Andric
CommandObjectTraceSchema(CommandInterpreter & interpreter)239af732203SDimitry Andric CommandObjectTraceSchema(CommandInterpreter &interpreter)
240af732203SDimitry Andric : CommandObjectParsed(interpreter, "trace schema",
241af732203SDimitry Andric "Show the schema of the given trace plugin.",
242af732203SDimitry Andric "trace schema <plug-in>. Use the plug-in name "
243af732203SDimitry Andric "\"all\" to see all schemas.\n"),
244af732203SDimitry Andric m_options() {}
245af732203SDimitry Andric
246af732203SDimitry Andric ~CommandObjectTraceSchema() override = default;
247af732203SDimitry Andric
GetOptions()248af732203SDimitry Andric Options *GetOptions() override { return &m_options; }
249af732203SDimitry Andric
250af732203SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)251af732203SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
252af732203SDimitry Andric Status error;
253af732203SDimitry Andric if (command.empty()) {
254*5f7ddb14SDimitry Andric result.AppendError(
255af732203SDimitry Andric "trace schema cannot be invoked without a plug-in as argument");
256af732203SDimitry Andric return false;
257af732203SDimitry Andric }
258af732203SDimitry Andric
259af732203SDimitry Andric StringRef plugin_name(command[0].c_str());
260af732203SDimitry Andric if (plugin_name == "all") {
261af732203SDimitry Andric size_t index = 0;
262af732203SDimitry Andric while (true) {
263af732203SDimitry Andric StringRef schema = PluginManager::GetTraceSchema(index++);
264af732203SDimitry Andric if (schema.empty())
265af732203SDimitry Andric break;
266af732203SDimitry Andric
267af732203SDimitry Andric result.AppendMessage(schema);
268af732203SDimitry Andric }
269af732203SDimitry Andric } else {
270af732203SDimitry Andric if (Expected<StringRef> schemaOrErr =
271af732203SDimitry Andric Trace::FindPluginSchema(plugin_name))
272af732203SDimitry Andric result.AppendMessage(*schemaOrErr);
273af732203SDimitry Andric else
274af732203SDimitry Andric error = schemaOrErr.takeError();
275af732203SDimitry Andric }
276af732203SDimitry Andric
277af732203SDimitry Andric if (error.Success()) {
278af732203SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
279af732203SDimitry Andric } else {
280af732203SDimitry Andric result.AppendErrorWithFormat("%s\n", error.AsCString());
281af732203SDimitry Andric }
282af732203SDimitry Andric return result.Succeeded();
283af732203SDimitry Andric }
284af732203SDimitry Andric
285af732203SDimitry Andric CommandOptions m_options;
286af732203SDimitry Andric };
287af732203SDimitry Andric
288af732203SDimitry Andric // CommandObjectTrace
289af732203SDimitry Andric
CommandObjectTrace(CommandInterpreter & interpreter)290af732203SDimitry Andric CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
291af732203SDimitry Andric : CommandObjectMultiword(interpreter, "trace",
292af732203SDimitry Andric "Commands for loading and using processor "
293af732203SDimitry Andric "trace information.",
294af732203SDimitry Andric "trace [<sub-command-options>]") {
295af732203SDimitry Andric LoadSubCommand("load",
296af732203SDimitry Andric CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
297af732203SDimitry Andric LoadSubCommand("dump",
298af732203SDimitry Andric CommandObjectSP(new CommandObjectTraceDump(interpreter)));
299af732203SDimitry Andric LoadSubCommand("schema",
300af732203SDimitry Andric CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
301af732203SDimitry Andric }
302af732203SDimitry Andric
303af732203SDimitry Andric CommandObjectTrace::~CommandObjectTrace() = default;
304*5f7ddb14SDimitry Andric
DoGetProxyCommandObject()305*5f7ddb14SDimitry Andric Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() {
306*5f7ddb14SDimitry Andric ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP();
307*5f7ddb14SDimitry Andric
308*5f7ddb14SDimitry Andric if (!process_sp)
309*5f7ddb14SDimitry Andric return createStringError(inconvertibleErrorCode(),
310*5f7ddb14SDimitry Andric "Process not available.");
311*5f7ddb14SDimitry Andric if (m_live_debug_session_only && !process_sp->IsLiveDebugSession())
312*5f7ddb14SDimitry Andric return createStringError(inconvertibleErrorCode(),
313*5f7ddb14SDimitry Andric "Process must be alive.");
314*5f7ddb14SDimitry Andric
315*5f7ddb14SDimitry Andric if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate())
316*5f7ddb14SDimitry Andric return GetDelegateCommand(**trace_sp);
317*5f7ddb14SDimitry Andric else
318*5f7ddb14SDimitry Andric return createStringError(inconvertibleErrorCode(),
319*5f7ddb14SDimitry Andric "Tracing is not supported. %s",
320*5f7ddb14SDimitry Andric toString(trace_sp.takeError()).c_str());
321*5f7ddb14SDimitry Andric }
322*5f7ddb14SDimitry Andric
GetProxyCommandObject()323*5f7ddb14SDimitry Andric CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() {
324*5f7ddb14SDimitry Andric if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) {
325*5f7ddb14SDimitry Andric m_delegate_sp = *delegate;
326*5f7ddb14SDimitry Andric m_delegate_error.clear();
327*5f7ddb14SDimitry Andric return m_delegate_sp.get();
328*5f7ddb14SDimitry Andric } else {
329*5f7ddb14SDimitry Andric m_delegate_sp.reset();
330*5f7ddb14SDimitry Andric m_delegate_error = toString(delegate.takeError());
331*5f7ddb14SDimitry Andric return nullptr;
332*5f7ddb14SDimitry Andric }
333*5f7ddb14SDimitry Andric }
334