Index: include/lldb/Core/Log.h =================================================================== --- include/lldb/Core/Log.h +++ include/lldb/Core/Log.h @@ -44,6 +44,53 @@ class Log final { public: + // Description of a log channel category. + struct Category { + llvm::StringLiteral name; + llvm::StringLiteral description; + uint32_t flag; + }; + + // This class describes a log channel. It also encapsulates the behavior + // necessary to enable a log channel in an atomic manner. + class Channel { + std::atomic log_ptr; + + public: + const llvm::ArrayRef categories; + const uint32_t default_flags; + + constexpr Channel(llvm::ArrayRef categories, + uint32_t default_flags) + : log_ptr(nullptr), categories(categories), + default_flags(default_flags) {} + + // This function is safe to call at any time + // FIXME: Not true yet, mask access is not atomic + Log *GetLogIfAll(uint32_t mask) { + Log *log = log_ptr.load(std::memory_order_acquire); + if (log && log->GetMask().AllSet(mask)) + return log; + return nullptr; + } + + // This function is safe to call at any time + // FIXME: Not true yet, mask access is not atomic + Log *GetLogIfAny(uint32_t mask) { + Log *log = log_ptr.load(std::memory_order_acquire); + if (log && log->GetMask().AnySet(mask)) + return log; + return nullptr; + } + + // Calls to Enable and disable need to be serialized externally. + void Enable(Log &log, const std::shared_ptr &stream_sp, + uint32_t flags); + + // Calls to Enable and disable need to be serialized externally. + void Disable(uint32_t flags); + }; + //------------------------------------------------------------------ // Callback definitions for abstracted plug-in log access. //------------------------------------------------------------------ @@ -63,6 +110,9 @@ //------------------------------------------------------------------ // Static accessors for logging channels //------------------------------------------------------------------ + static void Register(llvm::StringRef name, Channel &channel); + static void Unregister(llvm::StringRef name); + static void RegisterLogChannel(const ConstString &channel, const Log::Callbacks &log_callbacks); @@ -73,13 +123,13 @@ static bool EnableLogChannel(const std::shared_ptr &log_stream_sp, - uint32_t log_options, const char *channel, + uint32_t log_options, llvm::StringRef channel, const char **categories, Stream &error_stream); - static void - EnableAllLogChannels(const std::shared_ptr &log_stream_sp, - uint32_t log_options, const char **categories, - Stream *feedback_strm); + static bool DisableLogChannel(llvm::StringRef channel, + const char **categories, Stream &error_stream); + + static bool ListChannelCategories(llvm::StringRef channel, Stream &stream); static void DisableAllLogChannels(Stream *feedback_strm); @@ -90,12 +140,6 @@ static void Terminate(); //------------------------------------------------------------------ - // Auto completion - //------------------------------------------------------------------ - static void AutoCompleteChannelName(const char *channel_name, - StringList &matches); - - //------------------------------------------------------------------ // Member functions //------------------------------------------------------------------ Log(); @@ -162,34 +206,6 @@ const llvm::formatv_object_base &payload); }; -class LogChannel : public PluginInterface { -public: - LogChannel(); - - ~LogChannel() override; - - static lldb::LogChannelSP FindPlugin(const char *plugin_name); - - // categories is an array of chars that ends with a NULL element. - virtual void Disable(const char **categories, Stream *feedback_strm) = 0; - - virtual bool - Enable(const std::shared_ptr &log_stream_sp, - uint32_t log_options, - Stream *feedback_strm, // Feedback stream for argument errors etc - const char **categories) = 0; // The categories to enable within this - // logging stream, if empty, enable - // default set - - virtual void ListCategories(Stream *strm) = 0; - -protected: - std::unique_ptr m_log_ap; - -private: - DISALLOW_COPY_AND_ASSIGN(LogChannel); -}; - } // namespace lldb_private #define LLDB_LOG(log, ...) \ Index: include/lldb/Core/PluginManager.h =================================================================== --- include/lldb/Core/PluginManager.h +++ include/lldb/Core/PluginManager.h @@ -210,22 +210,6 @@ GetObjectContainerGetModuleSpecificationsCallbackAtIndex(uint32_t idx); //------------------------------------------------------------------ - // LogChannel - //------------------------------------------------------------------ - static bool RegisterPlugin(const ConstString &name, const char *description, - LogChannelCreateInstance create_callback); - - static bool UnregisterPlugin(LogChannelCreateInstance create_callback); - - static LogChannelCreateInstance - GetLogChannelCreateCallbackAtIndex(uint32_t idx); - - static LogChannelCreateInstance - GetLogChannelCreateCallbackForPluginName(const ConstString &name); - - static const char *GetLogChannelCreateNameAtIndex(uint32_t idx); - - //------------------------------------------------------------------ // Platform //------------------------------------------------------------------ static bool Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -127,7 +127,6 @@ class LineTable; class Listener; class Log; -class LogChannel; class Mangled; class Materializer; class MemoryHistory; @@ -362,7 +361,6 @@ typedef std::shared_ptr LineTableSP; typedef std::shared_ptr ListenerSP; typedef std::weak_ptr ListenerWP; -typedef std::shared_ptr LogChannelSP; typedef std::shared_ptr MemoryHistorySP; typedef std::shared_ptr MemoryRegionInfoSP; typedef std::unique_ptr MemoryRegionInfoUP; Index: include/lldb/lldb-private-interfaces.h =================================================================== --- include/lldb/lldb-private-interfaces.h +++ include/lldb/lldb-private-interfaces.h @@ -45,7 +45,6 @@ const lldb::ProcessSP &process_sp, lldb::addr_t offset); typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp, const FileSpec &outfile, Error &error); -typedef LogChannel *(*LogChannelCreateInstance)(); typedef EmulateInstruction *(*EmulateInstructionCreateInstance)( const ArchSpec &arch, InstructionType inst_type); typedef OperatingSystem *(*OperatingSystemCreateInstance)(Process *process, Index: source/Commands/CommandObjectLog.cpp =================================================================== --- source/Commands/CommandObjectLog.cpp +++ source/Commands/CommandObjectLog.cpp @@ -227,25 +227,15 @@ return false; } - Log::Callbacks log_callbacks; - const std::string channel = args[0].ref; args.Shift(); // Shift off the channel - if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) { - log_callbacks.disable(args.GetConstArgumentVector(), - &result.GetErrorStream()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - } else if (channel == "all") { + if (channel == "all") { Log::DisableAllLogChannels(&result.GetErrorStream()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { - LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.data())); - if (log_channel_sp) { - log_channel_sp->Disable(args.GetConstArgumentVector(), - &result.GetErrorStream()); + if (Log::DisableLogChannel(channel, args.GetConstArgumentVector(), + result.GetErrorStream())) result.SetStatus(eReturnStatusSuccessFinishNoResult); - } else - result.AppendErrorWithFormat("Invalid log channel '%s'.\n", - channel.data()); } return result.Succeeded(); } @@ -284,26 +274,12 @@ Log::ListAllLogChannels(&result.GetOutputStream()); result.SetStatus(eReturnStatusSuccessFinishResult); } else { - for (auto &entry : args.entries()) { - Log::Callbacks log_callbacks; - - if (Log::GetLogChannelCallbacks(ConstString(entry.ref), - log_callbacks)) { - log_callbacks.list_categories(&result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else if (entry.ref == "all") { - Log::ListAllLogChannels(&result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - LogChannelSP log_channel_sp(LogChannel::FindPlugin(entry.c_str())); - if (log_channel_sp) { - log_channel_sp->ListCategories(&result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - } else - result.AppendErrorWithFormat("Invalid log channel '%s'.\n", - entry.c_str()); - } - } + bool success = true; + for (const auto &entry : args.entries()) + success = success && Log::ListChannelCategories( + entry.ref, result.GetOutputStream()); + if (success) + result.SetStatus(eReturnStatusSuccessFinishResult); } return result.Succeeded(); } Index: source/Core/Log.cpp =================================================================== --- source/Core/Log.cpp +++ source/Core/Log.cpp @@ -18,8 +18,10 @@ #include "lldb/Utility/StreamString.h" // Other libraries and framework includes +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Chrono.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" @@ -36,6 +38,76 @@ using namespace lldb; using namespace lldb_private; +namespace { + struct ChannelAndLog { + Log log; + Log::Channel &channel; + + ChannelAndLog(Log::Channel &channel) : channel(channel) {} + }; + typedef llvm::StringMap ChannelMap; +} + +static llvm::ManagedStatic g_channel_map; + +static void ListCategories(Stream &stream, const ChannelMap::value_type &entry) { + stream.Format("Logging categories for '{0}':\n", entry.first()); + stream.Format(" all - all available logging categories\n"); + stream.Format(" default - default set of logging categories\n"); + for (const auto &category : entry.second.channel.categories) + stream.Format(" {0} - {1}\n", category.name, category.description); +} + +static uint32_t GetFlags(Stream &stream, const ChannelMap::value_type &entry, + const char **categories) { + bool list_categories = false; + uint32_t flags = 0; + for (size_t i = 0; categories[i]; ++i) { + if (llvm::StringRef("all").equals_lower(categories[i])) { + flags |= UINT32_MAX; + continue; + } + if (llvm::StringRef("default").equals_lower(categories[i])) { + flags |= entry.second.channel.default_flags; + continue; + } + auto cat = llvm::find_if(entry.second.channel.categories, + [&](const Log::Category &c) { + return c.name.equals_lower(categories[i]); + }); + if (cat != entry.second.channel.categories.end()) { + flags |= cat->flag; + continue; + } + stream.Format("error: unrecognized log category '{0}'\n", categories[i]); + list_categories = true; + } + if (list_categories) + ListCategories(stream, entry); + return flags; +} + +void Log::Channel::Enable(Log &log, + const std::shared_ptr &stream_sp, + uint32_t flags) { + log.GetMask().Set(flags); + if (log.GetMask().Get()) { + log.SetStream(stream_sp); + log_ptr.store(&log, std::memory_order_release); + } +} + +void Log::Channel::Disable(uint32_t flags) { + Log *log = log_ptr.load(std::memory_order_acquire); + if (!log) + return; + log->GetMask().Clear(flags); + if (!log->GetMask().Get()) { + log->SetStream(nullptr); + log_ptr.store(nullptr, std::memory_order_release); + } +} + Log::Log() : m_stream_sp(), m_options(0), m_mask_bits(0) {} Log::Log(const std::shared_ptr &stream_sp) @@ -152,9 +224,6 @@ typedef std::map CallbackMap; typedef CallbackMap::iterator CallbackMapIter; -typedef std::map LogChannelMap; -typedef LogChannelMap::iterator LogChannelMapIter; - // Surround our callback map with a singleton function so we don't have any // global initializers. static CallbackMap &GetCallbackMap() { @@ -162,9 +231,17 @@ return g_callback_map; } -static LogChannelMap &GetChannelMap() { - static LogChannelMap g_channel_map; - return g_channel_map; +void Log::Register(llvm::StringRef name, Channel &channel) { + auto iter = g_channel_map->try_emplace(name, channel); + assert(iter.second == true); + (void)iter; +} + +void Log::Unregister(llvm::StringRef name) { + auto iter = g_channel_map->find(name); + assert(iter != g_channel_map->end()); + iter->second.channel.Disable(UINT32_MAX); + g_channel_map->erase(iter); } void Log::RegisterLogChannel(const ConstString &channel, @@ -190,7 +267,7 @@ bool Log::EnableLogChannel( const std::shared_ptr &log_stream_sp, - uint32_t log_options, const char *channel, const char **categories, + uint32_t log_options, llvm::StringRef channel, const char **categories, Stream &error_stream) { Log::Callbacks log_callbacks; if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) { @@ -198,52 +275,52 @@ return true; } - LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel)); - if (log_channel_sp) { - if (log_channel_sp->Enable(log_stream_sp, log_options, &error_stream, - categories)) { - return true; - } else { - error_stream.Printf("Invalid log channel '%s'.\n", channel); - return false; - } - } else { - error_stream.Printf("Invalid log channel '%s'.\n", channel); + auto iter = g_channel_map->find(channel); + if (iter == g_channel_map->end()) { + error_stream.Format("Invalid log channel '{0}'.\n", channel); return false; } + uint32_t flags = categories && categories[0] + ? GetFlags(error_stream, *iter, categories) + : iter->second.channel.default_flags; + iter->second.channel.Enable(iter->second.log, log_stream_sp, flags); + return true; } -void Log::EnableAllLogChannels( - const std::shared_ptr &log_stream_sp, - uint32_t log_options, const char **categories, Stream *feedback_strm) { - CallbackMap &callback_map = GetCallbackMap(); - CallbackMapIter pos, end = callback_map.end(); +bool Log::DisableLogChannel(llvm::StringRef channel, const char **categories, + Stream &error_stream) { + Log::Callbacks log_callbacks; + if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) { + log_callbacks.disable(categories, &error_stream); + return true; + } - for (pos = callback_map.begin(); pos != end; ++pos) - pos->second.enable(log_stream_sp, log_options, categories, feedback_strm); - - LogChannelMap &channel_map = GetChannelMap(); - LogChannelMapIter channel_pos, channel_end = channel_map.end(); - for (channel_pos = channel_map.begin(); channel_pos != channel_end; - ++channel_pos) { - channel_pos->second->Enable(log_stream_sp, log_options, feedback_strm, - categories); + auto iter = g_channel_map->find(channel); + if (iter == g_channel_map->end()) { + error_stream.Format("Invalid log channel '{0}'.\n", channel); + return false; } + uint32_t flags = categories && categories[0] + ? GetFlags(error_stream, *iter, categories) + : UINT32_MAX; + iter->second.channel.Disable(flags); + return true; } -void Log::AutoCompleteChannelName(const char *channel_name, - StringList &matches) { - LogChannelMap &map = GetChannelMap(); - LogChannelMapIter pos, end = map.end(); - for (pos = map.begin(); pos != end; ++pos) { - const char *pos_channel_name = pos->first.GetCString(); - if (channel_name && channel_name[0]) { - if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) { - matches.AppendString(pos_channel_name); - } - } else - matches.AppendString(pos_channel_name); +bool Log::ListChannelCategories(llvm::StringRef channel, Stream &stream) { + Log::Callbacks log_callbacks; + if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) { + log_callbacks.list_categories(&stream); + return true; + } + + auto ch = g_channel_map->find(channel); + if (ch == g_channel_map->end()) { + stream.Format("Invalid log channel '{0}'.\n", channel); + return false; } + ListCategories(stream, *ch); + return true; } void Log::DisableAllLogChannels(Stream *feedback_strm) { @@ -254,11 +331,8 @@ for (pos = callback_map.begin(); pos != end; ++pos) pos->second.disable(categories, feedback_strm); - LogChannelMap &channel_map = GetChannelMap(); - LogChannelMapIter channel_pos, channel_end = channel_map.end(); - for (channel_pos = channel_map.begin(); channel_pos != channel_end; - ++channel_pos) - channel_pos->second->Disable(categories, feedback_strm); + for (auto &entry : *g_channel_map) + entry.second.channel.Disable(UINT32_MAX); } void Log::Initialize() { @@ -270,9 +344,8 @@ void Log::ListAllLogChannels(Stream *strm) { CallbackMap &callback_map = GetCallbackMap(); - LogChannelMap &channel_map = GetChannelMap(); - if (callback_map.empty() && channel_map.empty()) { + if (callback_map.empty() && g_channel_map->empty()) { strm->PutCString("No logging channels are currently registered.\n"); return; } @@ -281,17 +354,9 @@ for (pos = callback_map.begin(); pos != end; ++pos) pos->second.list_categories(strm); - uint32_t idx = 0; - const char *name; - for (idx = 0; - (name = PluginManager::GetLogChannelCreateNameAtIndex(idx)) != nullptr; - ++idx) { - LogChannelSP log_channel_sp(LogChannel::FindPlugin(name)); - if (log_channel_sp) - log_channel_sp->ListCategories(strm); - } + for (const auto &channel : *g_channel_map) + ListCategories(*strm, channel); } - bool Log::GetVerbose() const { return m_options.Test(LLDB_LOG_OPTION_VERBOSE); } void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file, @@ -358,33 +423,3 @@ message << payload << "\n"; WriteMessage(message.str()); } - -LogChannelSP LogChannel::FindPlugin(const char *plugin_name) { - LogChannelSP log_channel_sp; - LogChannelMap &channel_map = GetChannelMap(); - ConstString log_channel_name(plugin_name); - LogChannelMapIter pos = channel_map.find(log_channel_name); - if (pos == channel_map.end()) { - ConstString const_plugin_name(plugin_name); - LogChannelCreateInstance create_callback = - PluginManager::GetLogChannelCreateCallbackForPluginName( - const_plugin_name); - if (create_callback) { - log_channel_sp.reset(create_callback()); - if (log_channel_sp) { - // Cache the one and only loaded instance of each log channel - // plug-in after it has been loaded once. - channel_map[log_channel_name] = log_channel_sp; - } - } - } else { - // We have already loaded an instance of this log channel class, - // so just return the cached instance. - log_channel_sp = pos->second; - } - return log_channel_sp; -} - -LogChannel::LogChannel() : m_log_ap() {} - -LogChannel::~LogChannel() = default; Index: source/Core/PluginManager.cpp =================================================================== --- source/Core/PluginManager.cpp +++ source/Core/PluginManager.cpp @@ -1167,93 +1167,6 @@ return nullptr; } -#pragma mark LogChannel - -struct LogInstance { - LogInstance() : name(), description(), create_callback(nullptr) {} - - ConstString name; - std::string description; - LogChannelCreateInstance create_callback; -}; - -typedef std::vector LogInstances; - -static std::recursive_mutex &GetLogMutex() { - static std::recursive_mutex g_instances_mutex; - return g_instances_mutex; -} - -static LogInstances &GetLogInstances() { - static LogInstances g_instances; - return g_instances; -} - -bool PluginManager::RegisterPlugin(const ConstString &name, - const char *description, - LogChannelCreateInstance create_callback) { - if (create_callback) { - LogInstance instance; - assert((bool)name); - instance.name = name; - if (description && description[0]) - instance.description = description; - instance.create_callback = create_callback; - std::lock_guard gard(GetLogMutex()); - GetLogInstances().push_back(instance); - } - return false; -} - -bool PluginManager::UnregisterPlugin(LogChannelCreateInstance create_callback) { - if (create_callback) { - std::lock_guard gard(GetLogMutex()); - LogInstances &instances = GetLogInstances(); - - LogInstances::iterator pos, end = instances.end(); - for (pos = instances.begin(); pos != end; ++pos) { - if (pos->create_callback == create_callback) { - instances.erase(pos); - return true; - } - } - } - return false; -} - -const char *PluginManager::GetLogChannelCreateNameAtIndex(uint32_t idx) { - std::lock_guard gard(GetLogMutex()); - LogInstances &instances = GetLogInstances(); - if (idx < instances.size()) - return instances[idx].name.GetCString(); - return nullptr; -} - -LogChannelCreateInstance -PluginManager::GetLogChannelCreateCallbackAtIndex(uint32_t idx) { - std::lock_guard gard(GetLogMutex()); - LogInstances &instances = GetLogInstances(); - if (idx < instances.size()) - return instances[idx].create_callback; - return nullptr; -} - -LogChannelCreateInstance -PluginManager::GetLogChannelCreateCallbackForPluginName( - const ConstString &name) { - if (name) { - std::lock_guard gard(GetLogMutex()); - LogInstances &instances = GetLogInstances(); - - LogInstances::iterator pos, end = instances.end(); - for (pos = instances.begin(); pos != end; ++pos) { - if (name == pos->name) - return pos->create_callback; - } - } - return nullptr; -} - #pragma mark Platform struct PlatformInstance { Index: source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h +++ source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -27,48 +27,17 @@ #define DWARF_LOG_ALL (UINT32_MAX) #define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO) -class LogChannelDWARF : public lldb_private::LogChannel { -public: - LogChannelDWARF(); - - ~LogChannelDWARF() override; +namespace lldb_private { +class LogChannelDWARF { + static Log::Channel g_channel; +public: static void Initialize(); - static void Terminate(); - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - static lldb_private::LogChannel *CreateInstance(); - - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - void Disable(const char **categories, - lldb_private::Stream *feedback_strm) override; - - void Delete(); - - bool Enable(const std::shared_ptr &log_stream_sp, - uint32_t log_options, - lldb_private::Stream - *feedback_strm, // Feedback stream for argument errors etc - const char **categories) override; // The categories to enable - // within this logging stream, - // if empty, enable default set - - void ListCategories(lldb_private::Stream *strm) override; - - static lldb_private::Log *GetLog(); - - static lldb_private::Log *GetLogIfAll(uint32_t mask); - - static lldb_private::Log *GetLogIfAny(uint32_t mask); - - static void LogIf(uint32_t mask, const char *format, ...); + static Log *GetLogIfAll(uint32_t mask) { return g_channel.GetLogIfAll(mask); } + static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); } }; +} #endif // SymbolFileDWARF_LogChannelDWARF_h_ Index: source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -9,192 +9,28 @@ #include "LogChannelDWARF.h" -#include "SymbolFileDWARF.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Interpreter/Args.h" - using namespace lldb; using namespace lldb_private; -// when the one and only logging channel is enabled, then this will be non NULL. -static LogChannelDWARF *g_log_channel = NULL; - -LogChannelDWARF::LogChannelDWARF() : LogChannel() {} - -LogChannelDWARF::~LogChannelDWARF() {} +static constexpr Log::Category g_categories[] = { + {"aranges", "log the parsing of .debug_aranges", DWARF_LOG_DEBUG_ARANGES}, + {"comp", "log insertions of object files into DWARF debug maps", + DWARF_LOG_TYPE_COMPLETION}, + {"info", "log the parsing of .debug_info", DWARF_LOG_DEBUG_INFO}, + {"line", "log the parsing of .debug_line", DWARF_LOG_DEBUG_LINE}, + {"lookups", "log any lookups that happen by name, regex, or address", + DWARF_LOG_LOOKUPS}, + {"map", "log struct/unions/class type completions", DWARF_LOG_DEBUG_MAP}, + {"pubnames", "log the parsing of .debug_pubnames", + DWARF_LOG_DEBUG_PUBNAMES}, + {"pubtypes", "log the parsing of .debug_pubtypes", + DWARF_LOG_DEBUG_PUBTYPES}, +}; + +Log::Channel LogChannelDWARF::g_channel(g_categories, DWARF_LOG_DEFAULT); void LogChannelDWARF::Initialize() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - LogChannelDWARF::CreateInstance); -} - -void LogChannelDWARF::Terminate() { - PluginManager::UnregisterPlugin(LogChannelDWARF::CreateInstance); -} - -LogChannel *LogChannelDWARF::CreateInstance() { return new LogChannelDWARF(); } - -lldb_private::ConstString LogChannelDWARF::GetPluginNameStatic() { - return SymbolFileDWARF::GetPluginNameStatic(); -} - -const char *LogChannelDWARF::GetPluginDescriptionStatic() { - return "DWARF log channel for debugging plug-in issues."; -} - -lldb_private::ConstString LogChannelDWARF::GetPluginName() { - return GetPluginNameStatic(); + Log::Register("dwarf", g_channel); } -uint32_t LogChannelDWARF::GetPluginVersion() { return 1; } - -void LogChannelDWARF::Delete() { g_log_channel = NULL; } - -void LogChannelDWARF::Disable(const char **categories, Stream *feedback_strm) { - if (m_log_ap.get() == NULL) - return; - - uint32_t flag_bits = m_log_ap->GetMask().Get(); - for (size_t i = 0; categories[i] != NULL; ++i) { - const char *arg = categories[i]; - - if (::strcasecmp(arg, "all") == 0) - flag_bits &= ~DWARF_LOG_ALL; - else if (::strcasecmp(arg, "info") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_INFO; - else if (::strcasecmp(arg, "line") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_LINE; - else if (::strcasecmp(arg, "pubnames") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_PUBNAMES; - else if (::strcasecmp(arg, "pubtypes") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_PUBTYPES; - else if (::strcasecmp(arg, "aranges") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_ARANGES; - else if (::strcasecmp(arg, "lookups") == 0) - flag_bits &= ~DWARF_LOG_LOOKUPS; - else if (::strcasecmp(arg, "map") == 0) - flag_bits &= ~DWARF_LOG_DEBUG_MAP; - else if (::strcasecmp(arg, "default") == 0) - flag_bits &= ~DWARF_LOG_DEFAULT; - else if (::strncasecmp(arg, "comp", 4) == 0) - flag_bits &= ~DWARF_LOG_TYPE_COMPLETION; - else { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - ListCategories(feedback_strm); - } - } - - if (flag_bits == 0) - Delete(); - else - m_log_ap->GetMask().Reset(flag_bits); - - return; -} - -bool LogChannelDWARF::Enable( - const std::shared_ptr &log_stream_sp, - uint32_t log_options, - Stream *feedback_strm, // Feedback stream for argument errors etc - const char **categories // The categories to enable within this logging - // stream, if empty, enable default set - ) { - Delete(); - - if (m_log_ap) - m_log_ap->SetStream(log_stream_sp); - else - m_log_ap.reset(new Log(log_stream_sp)); - - g_log_channel = this; - uint32_t flag_bits = 0; - bool got_unknown_category = false; - for (size_t i = 0; categories[i] != NULL; ++i) { - const char *arg = categories[i]; - - if (::strcasecmp(arg, "all") == 0) - flag_bits |= DWARF_LOG_ALL; - else if (::strcasecmp(arg, "info") == 0) - flag_bits |= DWARF_LOG_DEBUG_INFO; - else if (::strcasecmp(arg, "line") == 0) - flag_bits |= DWARF_LOG_DEBUG_LINE; - else if (::strcasecmp(arg, "pubnames") == 0) - flag_bits |= DWARF_LOG_DEBUG_PUBNAMES; - else if (::strcasecmp(arg, "pubtypes") == 0) - flag_bits |= DWARF_LOG_DEBUG_PUBTYPES; - else if (::strcasecmp(arg, "aranges") == 0) - flag_bits |= DWARF_LOG_DEBUG_ARANGES; - else if (::strcasecmp(arg, "lookups") == 0) - flag_bits |= DWARF_LOG_LOOKUPS; - else if (::strcasecmp(arg, "map") == 0) - flag_bits |= DWARF_LOG_DEBUG_MAP; - else if (::strcasecmp(arg, "default") == 0) - flag_bits |= DWARF_LOG_DEFAULT; - else if (::strncasecmp(arg, "comp", 4) == 0) - flag_bits |= DWARF_LOG_TYPE_COMPLETION; - else { - feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); - if (got_unknown_category == false) { - got_unknown_category = true; - ListCategories(feedback_strm); - } - } - } - if (flag_bits == 0) - flag_bits = DWARF_LOG_DEFAULT; - m_log_ap->GetMask().Reset(flag_bits); - m_log_ap->GetOptions().Reset(log_options); - return m_log_ap.get() != NULL; -} - -void LogChannelDWARF::ListCategories(Stream *strm) { - strm->Printf( - "Logging categories for '%s':\n" - " all - turn on all available logging categories\n" - " info - log the parsing of .debug_info\n" - " line - log the parsing of .debug_line\n" - " pubnames - log the parsing of .debug_pubnames\n" - " pubtypes - log the parsing of .debug_pubtypes\n" - " aranges - log the parsing of .debug_aranges\n" - " lookups - log any lookups that happen by name, regex, or address\n" - " completion - log struct/unions/class type completions\n" - " map - log insertions of object files into DWARF debug maps\n", - SymbolFileDWARF::GetPluginNameStatic().GetCString()); -} - -Log *LogChannelDWARF::GetLog() { - if (g_log_channel) - return g_log_channel->m_log_ap.get(); - - return NULL; -} - -Log *LogChannelDWARF::GetLogIfAll(uint32_t mask) { - if (g_log_channel && g_log_channel->m_log_ap.get()) { - if (g_log_channel->m_log_ap->GetMask().AllSet(mask)) - return g_log_channel->m_log_ap.get(); - } - return NULL; -} - -Log *LogChannelDWARF::GetLogIfAny(uint32_t mask) { - if (g_log_channel && g_log_channel->m_log_ap.get()) { - if (g_log_channel->m_log_ap->GetMask().AnySet(mask)) - return g_log_channel->m_log_ap.get(); - } - return NULL; -} - -void LogChannelDWARF::LogIf(uint32_t mask, const char *format, ...) { - if (g_log_channel) { - Log *log = g_log_channel->m_log_ap.get(); - if (log && log->GetMask().AnySet(mask)) { - va_list args; - va_start(args, format); - log->VAPrintf(format, args); - va_end(args); - } - } -} +void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); } Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -223,7 +223,7 @@ void SymbolFileDWARF::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); - LogChannelDWARF::Initialize(); + LogChannelDWARF::Terminate(); } lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() { Index: unittests/Core/LogTest.cpp =================================================================== --- unittests/Core/LogTest.cpp +++ unittests/Core/LogTest.cpp @@ -12,10 +12,30 @@ #include "lldb/Core/Log.h" #include "lldb/Host/Host.h" #include "lldb/Utility/StreamString.h" +#include "llvm/Support/ManagedStatic.h" using namespace lldb; using namespace lldb_private; +enum { FOO = 1, BAR = 2 }; +static constexpr Log::Category test_categories[] = { + {"foo", "log foo", FOO}, {"bar", "log bar", BAR}, +}; +static constexpr uint32_t default_flags = FOO; + +static Log::Channel test_channel(test_categories, default_flags); + +struct LogChannelTest : public ::testing::Test { + static void SetUpTestCase() { + Log::Register("chan", test_channel); + } + + static void TearDownTestCase() { + Log::Unregister("chan"); + llvm::llvm_shutdown(); + } +}; + static std::string GetLogString(uint32_t log_options, const char *format, int arg) { std::string stream_string; @@ -57,3 +77,96 @@ GetLogString(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD, "Hello World {0}", 47)); } + +TEST(LogTest, Register) { + llvm::llvm_shutdown_obj obj; + Log::Register("chan", test_channel); + Log::Unregister("chan"); + Log::Register("chan", test_channel); + Log::Unregister("chan"); +} + +TEST(LogTest, Unregister) { + llvm::llvm_shutdown_obj obj; + Log::Register("chan", test_channel); + EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO)); + const char *cat1[] = {"foo", nullptr}; + std::string message; + std::shared_ptr stream_sp( + new llvm::raw_string_ostream(message)); + StreamString err; + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat1, err)); + EXPECT_NE(nullptr, test_channel.GetLogIfAny(FOO)); + Log::Unregister("chan"); + EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO)); +} + +TEST_F(LogChannelTest, Enable) { + EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO)); + std::string message; + std::shared_ptr stream_sp( + new llvm::raw_string_ostream(message)); + StreamString err; + EXPECT_FALSE(Log::EnableLogChannel(stream_sp, 0, "chanchan", nullptr, err)); + EXPECT_EQ("Invalid log channel 'chanchan'.\n", err.GetString()); + err.Clear(); + + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", nullptr, err)); + EXPECT_EQ("", err.GetString()); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO)); + EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); + + const char *cat2[] = {"bar", nullptr}; + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat2, err)); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR)); + + const char *cat3[] = {"baz", nullptr}; + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat3, err)); + EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'")) + << "err: " << err.GetString().str(); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR)); +} + +TEST_F(LogChannelTest, Disable) { + EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO)); + const char *cat12[] = {"foo", "bar", nullptr}; + std::string message; + std::shared_ptr stream_sp( + new llvm::raw_string_ostream(message)); + StreamString err; + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat12, err)); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR)); + + const char *cat2[] = {"bar", nullptr}; + EXPECT_TRUE(Log::DisableLogChannel("chan", cat2, err)); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO)); + EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); + + const char *cat3[] = {"baz", nullptr}; + EXPECT_TRUE(Log::DisableLogChannel("chan", cat3, err)); + EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'")) + << "err: " << err.GetString().str(); + EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO)); + EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); + err.Clear(); + + EXPECT_TRUE(Log::DisableLogChannel("chan", nullptr, err)); + EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO | BAR)); +} + +TEST_F(LogChannelTest, List) { + StreamString str; + EXPECT_TRUE(Log::ListChannelCategories("chan", str)); + std::string expected = + R"(Logging categories for 'chan': + all - all available logging categories + default - default set of logging categories + foo - log foo + bar - log bar +)"; + EXPECT_EQ(expected, str.GetString().str()); + str.Clear(); + + EXPECT_FALSE(Log::ListChannelCategories("chanchan", str)); + EXPECT_EQ("Invalid log channel 'chanchan'.\n", str.GetString().str()); +}