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: 4374c93956SWalter Erquinigo CommandOptions() : Options() { 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.", 7774c93956SWalter Erquinigo "trace load"), 7874c93956SWalter Erquinigo m_options() {} 7974c93956SWalter Erquinigo 8074c93956SWalter Erquinigo ~CommandObjectTraceLoad() override = default; 8174c93956SWalter Erquinigo 8274c93956SWalter Erquinigo Options *GetOptions() override { return &m_options; } 8374c93956SWalter Erquinigo 8474c93956SWalter Erquinigo protected: 8574c93956SWalter Erquinigo bool DoExecute(Args &command, CommandReturnObject &result) override { 8674c93956SWalter Erquinigo if (command.size() != 1) { 87ea1f4974SWalter Erquinigo result.AppendError( 88ea1f4974SWalter Erquinigo "a single path to a JSON file containing a trace session" 89ea1f4974SWalter Erquinigo "is required"); 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 return false; 9774c93956SWalter Erquinigo }; 9874c93956SWalter Erquinigo 9974c93956SWalter Erquinigo FileSpec json_file(command[0].ref()); 10074c93956SWalter Erquinigo 10174c93956SWalter Erquinigo auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath()); 10274c93956SWalter Erquinigo if (!buffer_or_error) { 10374c93956SWalter Erquinigo return end_with_failure(llvm::createStringError( 10474c93956SWalter Erquinigo std::errc::invalid_argument, "could not open input file: %s - %s.", 10574c93956SWalter Erquinigo json_file.GetPath().c_str(), 10674c93956SWalter Erquinigo buffer_or_error.getError().message().c_str())); 10774c93956SWalter Erquinigo } 10874c93956SWalter Erquinigo 109ea1f4974SWalter Erquinigo llvm::Expected<json::Value> session_file = 11074c93956SWalter Erquinigo json::parse(buffer_or_error.get()->getBuffer().str()); 111ea1f4974SWalter Erquinigo if (!session_file) 112ea1f4974SWalter Erquinigo return end_with_failure(session_file.takeError()); 11374c93956SWalter Erquinigo 114ea1f4974SWalter Erquinigo if (Expected<lldb::TraceSP> traceOrErr = 1150b697561SWalter Erquinigo Trace::FindPluginForPostMortemProcess( 1160b697561SWalter Erquinigo GetDebugger(), *session_file, 117ea1f4974SWalter Erquinigo json_file.GetDirectory().AsCString())) { 11874c93956SWalter Erquinigo lldb::TraceSP trace_sp = traceOrErr.get(); 119801067f4SStella 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 } 19274c93956SWalter Erquinigo return result.Succeeded(); 19374c93956SWalter Erquinigo } 19474c93956SWalter Erquinigo 19574c93956SWalter Erquinigo CommandOptions m_options; 19674c93956SWalter Erquinigo }; 19774c93956SWalter Erquinigo 19874c93956SWalter Erquinigo // CommandObjectTraceSchema 19974c93956SWalter Erquinigo #define LLDB_OPTIONS_trace_schema 20074c93956SWalter Erquinigo #include "CommandOptions.inc" 20174c93956SWalter Erquinigo 20274c93956SWalter Erquinigo #pragma mark CommandObjectTraceSchema 20374c93956SWalter Erquinigo 20474c93956SWalter Erquinigo class CommandObjectTraceSchema : public CommandObjectParsed { 20574c93956SWalter Erquinigo public: 20674c93956SWalter Erquinigo class CommandOptions : public Options { 20774c93956SWalter Erquinigo public: 20874c93956SWalter Erquinigo CommandOptions() : Options() { OptionParsingStarting(nullptr); } 20974c93956SWalter Erquinigo 21074c93956SWalter Erquinigo ~CommandOptions() override = default; 21174c93956SWalter Erquinigo 21274c93956SWalter Erquinigo Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 21374c93956SWalter Erquinigo ExecutionContext *execution_context) override { 21474c93956SWalter Erquinigo Status error; 21574c93956SWalter Erquinigo const int short_option = m_getopt_table[option_idx].val; 21674c93956SWalter Erquinigo 21774c93956SWalter Erquinigo switch (short_option) { 21874c93956SWalter Erquinigo case 'v': { 21974c93956SWalter Erquinigo m_verbose = true; 22074c93956SWalter Erquinigo break; 22174c93956SWalter Erquinigo } 22274c93956SWalter Erquinigo default: 22374c93956SWalter Erquinigo llvm_unreachable("Unimplemented option"); 22474c93956SWalter Erquinigo } 22574c93956SWalter Erquinigo return error; 22674c93956SWalter Erquinigo } 22774c93956SWalter Erquinigo 22874c93956SWalter Erquinigo void OptionParsingStarting(ExecutionContext *execution_context) override { 22974c93956SWalter Erquinigo m_verbose = false; 23074c93956SWalter Erquinigo } 23174c93956SWalter Erquinigo 23274c93956SWalter Erquinigo llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 23374c93956SWalter Erquinigo return llvm::makeArrayRef(g_trace_schema_options); 23474c93956SWalter Erquinigo } 23574c93956SWalter Erquinigo 23674c93956SWalter Erquinigo bool m_verbose; // Enable verbose logging for debugging purposes. 23774c93956SWalter Erquinigo }; 23874c93956SWalter Erquinigo 23974c93956SWalter Erquinigo CommandObjectTraceSchema(CommandInterpreter &interpreter) 24074c93956SWalter Erquinigo : CommandObjectParsed(interpreter, "trace schema", 24174c93956SWalter Erquinigo "Show the schema of the given trace plugin.", 242ea1f4974SWalter Erquinigo "trace schema <plug-in>. Use the plug-in name " 243ea1f4974SWalter Erquinigo "\"all\" to see all schemas.\n"), 24474c93956SWalter Erquinigo m_options() {} 24574c93956SWalter Erquinigo 24674c93956SWalter Erquinigo ~CommandObjectTraceSchema() override = default; 24774c93956SWalter Erquinigo 24874c93956SWalter Erquinigo Options *GetOptions() override { return &m_options; } 24974c93956SWalter Erquinigo 25074c93956SWalter Erquinigo protected: 25174c93956SWalter Erquinigo bool DoExecute(Args &command, CommandReturnObject &result) override { 25274c93956SWalter Erquinigo Status error; 25374c93956SWalter Erquinigo if (command.empty()) { 25474c93956SWalter Erquinigo result.SetError( 25574c93956SWalter Erquinigo "trace schema cannot be invoked without a plug-in as argument"); 25674c93956SWalter Erquinigo return false; 25774c93956SWalter Erquinigo } 25874c93956SWalter Erquinigo 25974c93956SWalter Erquinigo StringRef plugin_name(command[0].c_str()); 260ea1f4974SWalter Erquinigo if (plugin_name == "all") { 261ea1f4974SWalter Erquinigo size_t index = 0; 262ea1f4974SWalter Erquinigo while (true) { 263ea1f4974SWalter Erquinigo StringRef schema = PluginManager::GetTraceSchema(index++); 264ea1f4974SWalter Erquinigo if (schema.empty()) 265ea1f4974SWalter Erquinigo break; 26674c93956SWalter Erquinigo 267ea1f4974SWalter Erquinigo result.AppendMessage(schema); 268ea1f4974SWalter Erquinigo } 26974c93956SWalter Erquinigo } else { 270ea1f4974SWalter Erquinigo if (Expected<StringRef> schemaOrErr = 271ea1f4974SWalter Erquinigo Trace::FindPluginSchema(plugin_name)) 272ea1f4974SWalter Erquinigo result.AppendMessage(*schemaOrErr); 273ea1f4974SWalter Erquinigo else 274ea1f4974SWalter Erquinigo error = schemaOrErr.takeError(); 27574c93956SWalter Erquinigo } 27674c93956SWalter Erquinigo 27774c93956SWalter Erquinigo if (error.Success()) { 27874c93956SWalter Erquinigo result.SetStatus(eReturnStatusSuccessFinishResult); 27974c93956SWalter Erquinigo } else { 28074c93956SWalter Erquinigo result.AppendErrorWithFormat("%s\n", error.AsCString()); 28174c93956SWalter Erquinigo } 28274c93956SWalter Erquinigo return result.Succeeded(); 28374c93956SWalter Erquinigo } 28474c93956SWalter Erquinigo 28574c93956SWalter Erquinigo CommandOptions m_options; 28674c93956SWalter Erquinigo }; 28774c93956SWalter Erquinigo 28874c93956SWalter Erquinigo // CommandObjectTrace 28974c93956SWalter Erquinigo 29074c93956SWalter Erquinigo CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter) 29174c93956SWalter Erquinigo : CommandObjectMultiword(interpreter, "trace", 29274c93956SWalter Erquinigo "Commands for loading and using processor " 29374c93956SWalter Erquinigo "trace information.", 29474c93956SWalter Erquinigo "trace [<sub-command-options>]") { 29574c93956SWalter Erquinigo LoadSubCommand("load", 29674c93956SWalter Erquinigo CommandObjectSP(new CommandObjectTraceLoad(interpreter))); 29774c93956SWalter Erquinigo LoadSubCommand("dump", 29874c93956SWalter Erquinigo CommandObjectSP(new CommandObjectTraceDump(interpreter))); 29974c93956SWalter Erquinigo LoadSubCommand("schema", 30074c93956SWalter Erquinigo CommandObjectSP(new CommandObjectTraceSchema(interpreter))); 30174c93956SWalter Erquinigo } 30274c93956SWalter Erquinigo 30374c93956SWalter Erquinigo CommandObjectTrace::~CommandObjectTrace() = default; 3040b697561SWalter Erquinigo 3050b697561SWalter Erquinigo Expected<CommandObjectSP> CommandObjectTraceProxy::DoGetProxyCommandObject() { 3060b697561SWalter Erquinigo ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP(); 3070b697561SWalter Erquinigo 3080b697561SWalter Erquinigo if (!process_sp) 3090b697561SWalter Erquinigo return createStringError(inconvertibleErrorCode(), 3100b697561SWalter Erquinigo "Process not available."); 3110b697561SWalter Erquinigo if (m_live_debug_session_only && !process_sp->IsLiveDebugSession()) 3120b697561SWalter Erquinigo return createStringError(inconvertibleErrorCode(), 3130b697561SWalter Erquinigo "Process must be alive."); 3140b697561SWalter Erquinigo 315*bf9f21a2SWalter Erquinigo if (Expected<TraceSP> trace_sp = process_sp->GetTarget().GetTraceOrCreate()) 3160b697561SWalter Erquinigo return GetDelegateCommand(**trace_sp); 3170b697561SWalter Erquinigo else 3180b697561SWalter Erquinigo return createStringError(inconvertibleErrorCode(), 3190b697561SWalter Erquinigo "Tracing is not supported. %s", 3200b697561SWalter Erquinigo toString(trace_sp.takeError()).c_str()); 3210b697561SWalter Erquinigo } 3220b697561SWalter Erquinigo 3230b697561SWalter Erquinigo CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() { 3240b697561SWalter Erquinigo if (Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) { 3250b697561SWalter Erquinigo m_delegate_sp = *delegate; 3260b697561SWalter Erquinigo m_delegate_error.clear(); 3270b697561SWalter Erquinigo return m_delegate_sp.get(); 3280b697561SWalter Erquinigo } else { 3290b697561SWalter Erquinigo m_delegate_sp.reset(); 3300b697561SWalter Erquinigo m_delegate_error = toString(delegate.takeError()); 3310b697561SWalter Erquinigo return nullptr; 3320b697561SWalter Erquinigo } 3330b697561SWalter Erquinigo } 334