Revert "Refactor log channel registration mechanism"

The change breaks on Windows and NetBSD bots. Revert while I
investigate.

llvm-svn: 295201
This commit is contained in:
Pavel Labath 2017-02-15 17:13:19 +00:00
parent 94c8d4976c
commit f0713996b2
11 changed files with 490 additions and 329 deletions

View File

@ -44,53 +44,6 @@ namespace lldb_private {
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 *> log_ptr;
public:
const llvm::ArrayRef<Category> categories;
const uint32_t default_flags;
constexpr Channel(llvm::ArrayRef<Log::Category> 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<llvm::raw_ostream> &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.
//------------------------------------------------------------------
@ -110,9 +63,6 @@ public:
//------------------------------------------------------------------
// 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);
@ -123,13 +73,13 @@ public:
static bool
EnableLogChannel(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
uint32_t log_options, llvm::StringRef channel,
uint32_t log_options, const char *channel,
const char **categories, Stream &error_stream);
static bool DisableLogChannel(llvm::StringRef channel,
const char **categories, Stream &error_stream);
static bool ListChannelCategories(llvm::StringRef channel, Stream &stream);
static void
EnableAllLogChannels(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
uint32_t log_options, const char **categories,
Stream *feedback_strm);
static void DisableAllLogChannels(Stream *feedback_strm);
@ -139,6 +89,12 @@ public:
static void Terminate();
//------------------------------------------------------------------
// Auto completion
//------------------------------------------------------------------
static void AutoCompleteChannelName(const char *channel_name,
StringList &matches);
//------------------------------------------------------------------
// Member functions
//------------------------------------------------------------------
@ -206,6 +162,34 @@ private:
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<llvm::raw_ostream> &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<Log> m_log_ap;
private:
DISALLOW_COPY_AND_ASSIGN(LogChannel);
};
} // namespace lldb_private
#define LLDB_LOG(log, ...) \

View File

@ -209,6 +209,22 @@ public:
static ObjectFileGetModuleSpecifications
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
//------------------------------------------------------------------

View File

@ -127,6 +127,7 @@ class MemoryRegionInfo;
class LineTable;
class Listener;
class Log;
class LogChannel;
class Mangled;
class Materializer;
class MemoryHistory;
@ -361,6 +362,7 @@ typedef std::unique_ptr<lldb_private::SystemRuntime> SystemRuntimeUP;
typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
typedef std::weak_ptr<lldb_private::Listener> ListenerWP;
typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
typedef std::shared_ptr<lldb_private::MemoryHistory> MemoryHistorySP;
typedef std::shared_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoSP;
typedef std::unique_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoUP;

View File

@ -45,6 +45,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)(
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,

View File

@ -227,15 +227,25 @@ protected:
return false;
}
Log::Callbacks log_callbacks;
const std::string channel = args[0].ref;
args.Shift(); // Shift off the channel
if (channel == "all") {
Log::DisableAllLogChannels(&result.GetErrorStream());
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
log_callbacks.disable(args.GetConstArgumentVector(),
&result.GetErrorStream());
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else if (channel == "all") {
Log::DisableAllLogChannels(&result.GetErrorStream());
} else {
if (Log::DisableLogChannel(channel, args.GetConstArgumentVector(),
result.GetErrorStream()))
LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.data()));
if (log_channel_sp) {
log_channel_sp->Disable(args.GetConstArgumentVector(),
&result.GetErrorStream());
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else
result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
channel.data());
}
return result.Succeeded();
}
@ -274,12 +284,26 @@ protected:
Log::ListAllLogChannels(&result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
bool success = true;
for (const auto &entry : args.entries())
success = success && Log::ListChannelCategories(
entry.ref, result.GetOutputStream());
if (success)
result.SetStatus(eReturnStatusSuccessFinishResult);
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());
}
}
}
return result.Succeeded();
}

View File

@ -18,10 +18,8 @@
#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"
@ -38,76 +36,6 @@
using namespace lldb;
using namespace lldb_private;
namespace {
struct ChannelAndLog {
Log log;
Log::Channel &channel;
ChannelAndLog(Log::Channel &channel) : channel(channel) {}
};
typedef llvm::StringMap<ChannelAndLog> ChannelMap;
}
static llvm::ManagedStatic<ChannelMap> 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<llvm::raw_ostream> &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<llvm::raw_ostream> &stream_sp)
@ -224,6 +152,9 @@ void Log::Warning(const char *format, ...) {
typedef std::map<ConstString, Log::Callbacks> CallbackMap;
typedef CallbackMap::iterator CallbackMapIter;
typedef std::map<ConstString, LogChannelSP> LogChannelMap;
typedef LogChannelMap::iterator LogChannelMapIter;
// Surround our callback map with a singleton function so we don't have any
// global initializers.
static CallbackMap &GetCallbackMap() {
@ -231,17 +162,9 @@ static CallbackMap &GetCallbackMap() {
return g_callback_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);
static LogChannelMap &GetChannelMap() {
static LogChannelMap g_channel_map;
return g_channel_map;
}
void Log::RegisterLogChannel(const ConstString &channel,
@ -267,7 +190,7 @@ bool Log::GetLogChannelCallbacks(const ConstString &channel,
bool Log::EnableLogChannel(
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
uint32_t log_options, llvm::StringRef channel, const char **categories,
uint32_t log_options, const char *channel, const char **categories,
Stream &error_stream) {
Log::Callbacks log_callbacks;
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
@ -275,52 +198,52 @@ bool Log::EnableLogChannel(
return true;
}
auto iter = g_channel_map->find(channel);
if (iter == g_channel_map->end()) {
error_stream.Format("Invalid log channel '{0}'.\n", channel);
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);
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;
}
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;
}
void Log::EnableAllLogChannels(
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
uint32_t log_options, const char **categories, Stream *feedback_strm) {
CallbackMap &callback_map = GetCallbackMap();
CallbackMapIter pos, end = callback_map.end();
auto iter = g_channel_map->find(channel);
if (iter == g_channel_map->end()) {
error_stream.Format("Invalid log channel '{0}'.\n", channel);
return false;
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);
}
uint32_t flags = categories && categories[0]
? GetFlags(error_stream, *iter, categories)
: UINT32_MAX;
iter->second.channel.Disable(flags);
return true;
}
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;
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);
}
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) {
@ -331,8 +254,11 @@ void Log::DisableAllLogChannels(Stream *feedback_strm) {
for (pos = callback_map.begin(); pos != end; ++pos)
pos->second.disable(categories, feedback_strm);
for (auto &entry : *g_channel_map)
entry.second.channel.Disable(UINT32_MAX);
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);
}
void Log::Initialize() {
@ -344,8 +270,9 @@ void Log::Terminate() { DisableAllLogChannels(nullptr); }
void Log::ListAllLogChannels(Stream *strm) {
CallbackMap &callback_map = GetCallbackMap();
LogChannelMap &channel_map = GetChannelMap();
if (callback_map.empty() && g_channel_map->empty()) {
if (callback_map.empty() && channel_map.empty()) {
strm->PutCString("No logging channels are currently registered.\n");
return;
}
@ -354,9 +281,17 @@ void Log::ListAllLogChannels(Stream *strm) {
for (pos = callback_map.begin(); pos != end; ++pos)
pos->second.list_categories(strm);
for (const auto &channel : *g_channel_map)
ListCategories(*strm, channel);
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);
}
}
bool Log::GetVerbose() const { return m_options.Test(LLDB_LOG_OPTION_VERBOSE); }
void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
@ -423,3 +358,33 @@ void Log::Format(llvm::StringRef file, llvm::StringRef function,
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;

View File

@ -1167,6 +1167,93 @@ PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(
return nullptr;
}
#pragma mark LogChannel
struct LogInstance {
LogInstance() : name(), description(), create_callback(nullptr) {}
ConstString name;
std::string description;
LogChannelCreateInstance create_callback;
};
typedef std::vector<LogInstance> 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<std::recursive_mutex> gard(GetLogMutex());
GetLogInstances().push_back(instance);
}
return false;
}
bool PluginManager::UnregisterPlugin(LogChannelCreateInstance create_callback) {
if (create_callback) {
std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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 {

View File

@ -9,28 +9,192 @@
#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;
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},
};
// when the one and only logging channel is enabled, then this will be non NULL.
static LogChannelDWARF *g_log_channel = NULL;
Log::Channel LogChannelDWARF::g_channel(g_categories, DWARF_LOG_DEFAULT);
LogChannelDWARF::LogChannelDWARF() : LogChannel() {}
LogChannelDWARF::~LogChannelDWARF() {}
void LogChannelDWARF::Initialize() {
Log::Register("dwarf", g_channel);
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(),
LogChannelDWARF::CreateInstance);
}
void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); }
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();
}
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<llvm::raw_ostream> &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);
}
}
}

View File

@ -27,17 +27,48 @@
#define DWARF_LOG_ALL (UINT32_MAX)
#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
namespace lldb_private {
class LogChannelDWARF {
static Log::Channel g_channel;
class LogChannelDWARF : public lldb_private::LogChannel {
public:
LogChannelDWARF();
~LogChannelDWARF() override;
static void Initialize();
static void Terminate();
static Log *GetLogIfAll(uint32_t mask) { return g_channel.GetLogIfAll(mask); }
static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); }
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<llvm::raw_ostream> &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, ...);
};
}
#endif // SymbolFileDWARF_LogChannelDWARF_h_

View File

@ -223,7 +223,7 @@ void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
void SymbolFileDWARF::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
LogChannelDWARF::Terminate();
LogChannelDWARF::Initialize();
}
lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() {

View File

@ -12,30 +12,10 @@
#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;
@ -77,96 +57,3 @@ TEST(LogTest, log_options) {
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<llvm::raw_string_ostream> 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<llvm::raw_string_ostream> 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<llvm::raw_string_ostream> 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());
}