diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-04 19:20:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-08 19:02:26 +0000 |
commit | 81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch) | |
tree | 311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp | |
parent | 5fff09660e06a66bed6482da9c70df328e16bbb6 (diff) | |
parent | 145449b1e420787bb99721a429341fa6be3adfb6 (diff) |
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp | 184 |
1 files changed, 174 insertions, 10 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp index d432ab244805..684cb35da1cc 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp @@ -11,6 +11,8 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValueEnumeration.h" +#include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/FileSpec.h" @@ -21,7 +23,40 @@ using namespace lldb; using namespace lldb_private; -#define LLDB_OPTIONS_log +static constexpr OptionEnumValueElement g_log_handler_type[] = { + { + eLogHandlerDefault, + "default", + "Use the default (stream) log handler", + }, + { + eLogHandlerStream, + "stream", + "Write log messages to the debugger output stream or to a file if one " + "is specified. A buffer size (in bytes) can be specified with -b. If " + "no buffer size is specified the output is unbuffered.", + }, + { + eLogHandlerCircular, + "circular", + "Write log messages to a fixed size circular buffer. A buffer size " + "(number of messages) must be specified with -b.", + }, + { + eLogHandlerSystem, + "os", + "Write log messages to the operating system log.", + }, +}; + +static constexpr OptionEnumValues LogHandlerType() { + return OptionEnumValues(g_log_handler_type); +} + +#define LLDB_OPTIONS_log_enable +#include "CommandOptions.inc" + +#define LLDB_OPTIONS_log_dump #include "CommandOptions.inc" /// Common completion logic for log enable/disable. @@ -75,7 +110,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() {} + CommandOptions() = default; ~CommandOptions() override = default; @@ -89,8 +124,17 @@ public: log_file.SetFile(option_arg, FileSpec::Style::native); FileSystem::Instance().Resolve(log_file); break; - case 't': - log_options |= LLDB_LOG_OPTION_THREADSAFE; + case 'h': + handler = (LogHandlerKind)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, 0, error); + if (!error.Success()) + error.SetErrorStringWithFormat( + "unrecognized value for log handler '%s'", + option_arg.str().c_str()); + break; + case 'b': + error = + buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign); break; case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; @@ -125,16 +169,18 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { log_file.Clear(); + buffer_size.Clear(); + handler = eLogHandlerStream; log_options = 0; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { - return llvm::makeArrayRef(g_log_options); + return llvm::makeArrayRef(g_log_enable_options); } - // Instance variables to hold the values for command options. - FileSpec log_file; + OptionValueUInt64 buffer_size; + LogHandlerKind handler = eLogHandlerStream; uint32_t log_options = 0; }; @@ -153,6 +199,13 @@ protected: return false; } + if (m_options.handler == eLogHandlerCircular && + m_options.buffer_size.GetCurrentValue() == 0) { + result.AppendError( + "the circular buffer handler requires a non-zero buffer size.\n"); + return false; + } + // Store into a std::string since we're about to shift the channel off. const std::string channel = std::string(args[0].ref()); args.Shift(); // Shift off the channel @@ -164,9 +217,10 @@ protected: std::string error; llvm::raw_string_ostream error_stream(error); - bool success = - GetDebugger().EnableLog(channel, args.GetArgumentArrayRef(), log_file, - m_options.log_options, error_stream); + bool success = GetDebugger().EnableLog( + channel, args.GetArgumentArrayRef(), log_file, m_options.log_options, + m_options.buffer_size.GetCurrentValue(), m_options.handler, + error_stream); result.GetErrorStream() << error_stream.str(); if (success) @@ -294,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: @@ -503,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))); } |