aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Commands/CommandObjectLog.cpp
diff options
context:
space:
mode:
authorJonas Devlieghere <jonas@devlieghere.com>2022-06-27 10:00:05 -0700
committerJonas Devlieghere <jonas@devlieghere.com>2022-06-27 10:02:34 -0700
commit9bdb7e573427ac3785cb10829da57ee18ef65ce3 (patch)
treee7d0c4cd3f5ffa0cb8a6c9cb530ac330f63f8c7b /lldb/source/Commands/CommandObjectLog.cpp
parentbecbbb7e3c8141b3346211faf9359f629cbf4e4d (diff)
downloadllvm-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.cpp113
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)));
}