diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2022-06-27 10:00:05 -0700 |
---|---|---|
committer | Jonas Devlieghere <jonas@devlieghere.com> | 2022-06-27 10:02:34 -0700 |
commit | 9bdb7e573427ac3785cb10829da57ee18ef65ce3 (patch) | |
tree | e7d0c4cd3f5ffa0cb8a6c9cb530ac330f63f8c7b /lldb/source/Commands/CommandObjectLog.cpp | |
parent | becbbb7e3c8141b3346211faf9359f629cbf4e4d (diff) | |
download | llvm-9bdb7e573427ac3785cb10829da57ee18ef65ce3.zip llvm-9bdb7e573427ac3785cb10829da57ee18ef65ce3.tar.gz llvm-9bdb7e573427ac3785cb10829da57ee18ef65ce3.tar.bz2 |
[lldb] Add a log dump command
Add a log dump command to dump logs to a file. This only works for
channels that have a log handler associated that supports dumping. For
now that's limited to the circular log handler, but more could be added
in the future.
Differential revision: https://reviews.llvm.org/D128557
Diffstat (limited to 'lldb/source/Commands/CommandObjectLog.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectLog.cpp | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp index 349af26..684cb35 100644 --- a/lldb/source/Commands/CommandObjectLog.cpp +++ b/lldb/source/Commands/CommandObjectLog.cpp @@ -56,6 +56,9 @@ static constexpr OptionEnumValues LogHandlerType() { #define LLDB_OPTIONS_log_enable #include "CommandOptions.inc" +#define LLDB_OPTIONS_log_dump +#include "CommandOptions.inc" + /// Common completion logic for log enable/disable. static void CompleteEnableDisable(CompletionRequest &request) { size_t arg_index = request.GetCursorIndex(); @@ -345,6 +348,114 @@ protected: return result.Succeeded(); } }; +class CommandObjectLogDump : public CommandObjectParsed { +public: + CommandObjectLogDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "log dump", + "dump circular buffer logs", nullptr) { + CommandArgumentEntry arg1; + CommandArgumentData channel_arg; + + // Define the first (and only) variant of this arg. + channel_arg.arg_type = eArgTypeLogChannel; + channel_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(channel_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + } + + ~CommandObjectLogDump() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() = default; + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + log_file.SetFile(option_arg, FileSpec::Style::native); + FileSystem::Instance().Resolve(log_file); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + log_file.Clear(); + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_log_dump_options); + } + + FileSpec log_file; + }; + + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CompleteEnableDisable(request); + } + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + if (args.empty()) { + result.AppendErrorWithFormat( + "%s takes a log channel and one or more log types.\n", + m_cmd_name.c_str()); + return false; + } + + std::unique_ptr<llvm::raw_ostream> stream_up; + if (m_options.log_file) { + const File::OpenOptions flags = File::eOpenOptionWriteOnly | + File::eOpenOptionCanCreate | + File::eOpenOptionTruncate; + llvm::Expected<FileUP> file = FileSystem::Instance().Open( + m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false); + if (!file) { + result.AppendErrorWithFormat("Unable to open log file '%s': %s", + m_options.log_file.GetCString(), + llvm::toString(file.takeError()).c_str()); + return false; + } + stream_up = std::make_unique<llvm::raw_fd_ostream>( + (*file)->GetDescriptor(), /*shouldClose=*/true); + } else { + stream_up = std::make_unique<llvm::raw_fd_ostream>( + GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false); + } + + const std::string channel = std::string(args[0].ref()); + std::string error; + llvm::raw_string_ostream error_stream(error); + if (Log::DumpLogChannel(channel, *stream_up, error_stream)) { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } else { + result.SetStatus(eReturnStatusFailed); + result.GetErrorStream() << error_stream.str(); + } + + return result.Succeeded(); + } + + CommandOptions m_options; +}; class CommandObjectLogTimerEnable : public CommandObjectParsed { public: @@ -554,6 +665,8 @@ CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) CommandObjectSP(new CommandObjectLogDisable(interpreter))); LoadSubCommand("list", CommandObjectSP(new CommandObjectLogList(interpreter))); + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectLogDump(interpreter))); LoadSubCommand("timers", CommandObjectSP(new CommandObjectLogTimer(interpreter))); } |