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