diff --git a/lldb/include/lldb/Utility/Log.h b/lldb/include/lldb/Utility/Log.h --- a/lldb/include/lldb/Utility/Log.h +++ b/lldb/include/lldb/Utility/Log.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #define LLDB_LOG_OPTION_BACKTRACE (1U << 7) #define LLDB_LOG_OPTION_APPEND (1U << 8) #define LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION (1U << 9) +#define LLDB_LOG_OPTION_LOG_TO_FILE (1U << 10) // Logging Functions namespace lldb_private { @@ -238,6 +240,18 @@ return LogChannelFor().GetLog(Log::MaskType(mask)); } +/// Retrieve the Log object for a channel when any of its categories are +/// enabled. +/// +/// Returns a valid Log object if any of the categories for a channel are +/// enabled. Otherwise, returns nullptr. +template Log *GetChannelLogWhenAnyCategoryEnabled() { + static_assert( + std::is_same>::value, ""); + Log::MaskType any_category_flag = std::numeric_limits::max(); + return LogChannelFor().GetLog(any_category_flag); +} + } // namespace lldb_private /// The LLDB_LOG* macros defined below are the way to emit log messages. @@ -274,6 +288,15 @@ log_private->Printf(__VA_ARGS__); \ } while (0) +// Write a message to the log only if that log is sending its output to a file. +#define LLDB_LOGF_FILE_ONLY(log, ...) \ + do { \ + ::lldb_private::Log *log_private = (log); \ + if (log_private && \ + log_private->GetOptions().Test(LLDB_LOG_OPTION_LOG_TO_FILE)) \ + log_private->Printf(__VA_ARGS__); \ + } while (0) + #define LLDB_LOGV(log, ...) \ do { \ ::lldb_private::Log *log_private = (log); \ diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp --- a/lldb/source/Commands/CommandObjectLog.cpp +++ b/lldb/source/Commands/CommandObjectLog.cpp @@ -88,6 +88,7 @@ case 'f': log_file.SetFile(option_arg, FileSpec::Style::native); FileSystem::Instance().Resolve(log_file); + log_options |= LLDB_LOG_OPTION_LOG_TO_FILE; break; case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -1838,11 +1838,17 @@ std::string original_command_string(command_line); Log *log = GetLog(LLDBLog::Commands); + Log *lldb_log = GetChannelLogWhenAnyCategoryEnabled(); llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")", command_line); LLDB_LOGF(log, "Processing command: %s", command_line); LLDB_SCOPED_TIMERF("Processing command: %s.", command_line); + // If there is logging enabled for any category in the lldb channel that + // is being directed to a file, log every command. This functionality will + // make it easier for the user reading a log file after the fact to correlate + // the debugging output with the commands that may have caused it. + LLDB_LOGF_FILE_ONLY(lldb_log, "(lldb) %s\n", command_line); if (WasInterrupted()) { result.AppendError("interrupted");