aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-04 19:20:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-08 19:02:26 +0000
commit81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch)
tree311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp
parent5fff09660e06a66bed6482da9c70df328e16bbb6 (diff)
parent145449b1e420787bb99721a429341fa6be3adfb6 (diff)
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp184
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)));
}