Index: lldb/include/lldb/Utility/Diagnostics.h =================================================================== --- lldb/include/lldb/Utility/Diagnostics.h +++ lldb/include/lldb/Utility/Diagnostics.h @@ -11,6 +11,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSet.h" @@ -22,6 +23,21 @@ namespace lldb_private { +enum class DiagnosticsLog : Log::MaskType { + LLDB = Log::ChannelFlag<0>, + LLVM_MARK_AS_BITMASK_ENUM(LLDB) +}; + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class LogChannelDiagnostics { +public: + static void Initialize(); + static void Terminate(); +}; + +template <> Log::Channel &LogChannelFor(); + /// Diagnostics are a collection of files to help investigate bugs and /// troubleshoot issues. Any part of the debugger can register itself with the /// help of a callback to emit one or more files into the diagnostic directory. @@ -47,6 +63,10 @@ private: static llvm::Optional &InstanceImpl(); + llvm::Error DumpAlwaysOnLog(const FileSpec &dir) const; + + std::shared_ptr m_always_on_log_handler; + llvm::SmallVector m_callbacks; std::mutex m_callbacks_mutex; }; Index: lldb/include/lldb/Utility/Log.h =================================================================== --- lldb/include/lldb/Utility/Log.h +++ lldb/include/lldb/Utility/Log.h @@ -150,12 +150,13 @@ public: const llvm::ArrayRef categories; const MaskType default_flags; + const bool internal = false; template constexpr Channel(llvm::ArrayRef categories, - Cat default_flags) + Cat default_flags, bool internal = false) : log_ptr(nullptr), categories(categories), - default_flags(MaskType(default_flags)) { + default_flags(MaskType(default_flags)), internal(internal) { static_assert( std::is_same>::value); } @@ -341,6 +342,14 @@ log_private->Format(__FILE__, __func__, __VA_ARGS__); \ } while (0) +#define LLDB_MULTI_LOG(log1, log2, ...) \ + do { \ + if (::lldb_private::Log *log_private = (log1)) \ + log_private->Format(__FILE__, __func__, __VA_ARGS__); \ + if (::lldb_private::Log *log_private = (log2)) \ + log_private->Format(__FILE__, __func__, __VA_ARGS__); \ + } while (0) + #define LLDB_LOGF(log, ...) \ do { \ ::lldb_private::Log *log_private = (log); \ @@ -348,6 +357,14 @@ log_private->Printf(__VA_ARGS__); \ } while (0) +#define LLDB_MULTI_LOGF(log1, log2, ...) \ + do { \ + if (::lldb_private::Log *log_private = (log1)) \ + log_private->Printf(__VA_ARGS__); \ + if (::lldb_private::Log *log_private = (log2)) \ + log_private->Printf(__VA_ARGS__); \ + } while (0) + #define LLDB_LOGV(log, ...) \ do { \ ::lldb_private::Log *log_private = (log); \ Index: lldb/source/Utility/Diagnostics.cpp =================================================================== --- lldb/source/Utility/Diagnostics.cpp +++ lldb/source/Utility/Diagnostics.cpp @@ -17,7 +17,27 @@ using namespace lldb; using namespace llvm; +static constexpr size_t g_num_log_messages = 100; + +static constexpr Log::Category g_categories[] = { + {{"lldb"}, {"diagnostics log for lldb"}, DiagnosticsLog::LLDB}, +}; + +static Log::Channel g_channel(g_categories, DiagnosticsLog::LLDB, + /*internal=*/true); + +template <> Log::Channel &lldb_private::LogChannelFor() { + return g_channel; +} + +void LogChannelDiagnostics::Initialize() { + Log::Register("diagnostics", g_channel); +} + +void LogChannelDiagnostics::Terminate() { Log::Unregister("diagnostics"); } + void Diagnostics::Initialize() { + LogChannelDiagnostics::Initialize(); lldbassert(!InstanceImpl() && "Already initialized."); InstanceImpl().emplace(); } @@ -25,6 +45,7 @@ void Diagnostics::Terminate() { lldbassert(InstanceImpl() && "Already terminated."); InstanceImpl().reset(); + LogChannelDiagnostics::Terminate(); } Optional &Diagnostics::InstanceImpl() { @@ -34,9 +55,18 @@ Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); } -Diagnostics::Diagnostics() {} +Diagnostics::Diagnostics() + : m_always_on_log_handler( + std::make_shared(g_num_log_messages)) { + const uint32_t log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME; + Log::EnableLogChannel(m_always_on_log_handler, log_options, "diagnostics", + {"all"}, llvm::nulls()); + AddCallback([&](const FileSpec &dir) { return DumpAlwaysOnLog(dir); }); +} -Diagnostics::~Diagnostics() {} +Diagnostics::~Diagnostics() { + Log::DisableLogChannel("diagnostics", {"all"}, llvm::nulls()); +} void Diagnostics::AddCallback(Callback callback) { std::lock_guard guard(m_callbacks_mutex); @@ -66,9 +96,22 @@ } Error Diagnostics::Create(const FileSpec &dir) { + LLDB_LOG(GetLog(DiagnosticsLog::LLDB), "Dumping {0} diagnostics to '{1}'", + m_callbacks.size(), dir.GetPath()); + for (Callback c : m_callbacks) { if (Error err = c(dir)) return err; } return Error::success(); } + +llvm::Error Diagnostics::DumpAlwaysOnLog(const FileSpec &dir) const { + FileSpec log_file = dir.CopyByAppendingPathComponent("always-on.log"); + std::error_code ec; + llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None); + if (ec) + return errorCodeToError(ec); + m_always_on_log_handler->Dump(stream); + return Error::success(); +} Index: lldb/source/Utility/Log.cpp =================================================================== --- lldb/source/Utility/Log.cpp +++ lldb/source/Utility/Log.cpp @@ -283,8 +283,10 @@ std::vector Log::ListChannels() { std::vector result; - for (const auto &channel : *g_channel_map) - result.push_back(channel.first()); + for (const auto &entry : *g_channel_map) { + if (!entry.second.m_channel.internal) + result.push_back(entry.first()); + } return result; } @@ -294,8 +296,10 @@ return; } - for (const auto &channel : *g_channel_map) - ListCategories(stream, channel); + for (const auto &entry : *g_channel_map) { + if (!entry.second.m_channel.internal) + ListCategories(stream, entry); + } } bool Log::GetVerbose() const { Index: lldb/test/Shell/Diagnostics/TestLogChannel.test =================================================================== --- /dev/null +++ lldb/test/Shell/Diagnostics/TestLogChannel.test @@ -0,0 +1,2 @@ +# RUN: %lldb -o 'log list' 2>&1 | FileCheck %s +# CHECK-NOT: Logging categories for 'diagnostics'