diff options
Diffstat (limited to 'lldb/source/Core/Log.cpp')
-rw-r--r-- | lldb/source/Core/Log.cpp | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/lldb/source/Core/Log.cpp b/lldb/source/Core/Log.cpp new file mode 100644 index 00000000000..fe2071683ca --- /dev/null +++ b/lldb/source/Core/Log.cpp @@ -0,0 +1,590 @@ +//===-- Log.cpp -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <mach/mach.h> +#include <pthread.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> + +// C++ Includes +#include <map> +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/TimeValue.h" +#include "lldb/Host/Mutex.h" + +using namespace lldb; +using namespace lldb_private; + +static Stream * +StreamForSTDOUTAccess (bool set, StreamSP &stream_sp) +{ + // Since we are in a shared library and we can't have global + // constructors, we need to control access to this static variable + // through an accessor function to get and set the value. + static StreamSP g_stream_sp; + + if (set) + g_stream_sp = stream_sp; + else + { + if (g_stream_sp) + stream_sp = g_stream_sp; + else + { + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + if (out_fh) + stream_sp.reset(new StreamFile(out_fh)); + else + stream_sp.reset(); + } + } + return stream_sp.get(); +} + +StreamSP +Log::GetStreamForSTDOUT () +{ + StreamSP stream_sp; + StreamForSTDOUTAccess (false, stream_sp); + return stream_sp; +} + +void +Log::SetStreamForSTDOUT (StreamSP &stream_sp) +{ + StreamForSTDOUTAccess (true, stream_sp); +} + +void +Log::STDOUT (const char *format, ...) +{ + StreamSP stream_sp; + if (StreamForSTDOUTAccess(false, stream_sp)) + { + va_list args; + va_start (args, format); + stream_sp->PrintfVarArg(format, args); + va_end (args); + } +} + +static Stream * +StreamForSTDERRAccess (bool set, StreamSP &stream_sp) +{ + // Since we are in a shared library and we can't have global + // constructors, we need to control access to this static variable + // through an accessor function to get and set the value. + static StreamSP g_stream_sp(new StreamFile(Debugger::GetSharedInstance().GetErrorFileHandle())); + + if (set) + g_stream_sp = stream_sp; + else + stream_sp = g_stream_sp; + return stream_sp.get(); +} + +StreamSP +Log::GetStreamForSTDERR () +{ + StreamSP stream_sp; + StreamForSTDERRAccess (false, stream_sp); + return stream_sp; +} + +void +Log::SetStreamForSTDERR (StreamSP &stream_sp) +{ + StreamForSTDERRAccess (true, stream_sp); +} + +void +Log::STDERR (const char *format, ...) +{ + StreamSP stream_sp; + if (StreamForSTDERRAccess(false, stream_sp)) + { + va_list args; + va_start (args, format); + stream_sp->PrintfVarArg(format, args); + va_end (args); + } +} + +Log::Log () : + m_stream_sp(), + m_options(0), + m_mask_bits(0) +{ +} + +Log::Log (StreamSP &stream_sp) : + m_stream_sp(stream_sp), + m_options(0), + m_mask_bits(0) +{ +} + +Log::~Log () +{ +} + +Flags & +Log::GetOptions() +{ + return m_options; +} + +const Flags & +Log::GetOptions() const +{ + return m_options; +} + +Flags & +Log::GetMask() +{ + return m_mask_bits; +} + +const Flags & +Log::GetMask() const +{ + return m_mask_bits; +} + + +//---------------------------------------------------------------------- +// All logging eventually boils down to this function call. If we have +// a callback registered, then we call the logging callback. If we have +// a valid file handle, we also log to the file. +//---------------------------------------------------------------------- +void +Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args) +{ + if (m_stream_sp) + { + static uint32_t g_sequence_id = 0; + StreamString header; + static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive); + + Mutex::Locker locker; + + uint32_t log_options = m_options.GetAllFlagBits(); + + // Lock the threaded logging mutex if we are doing thread safe logging + if (log_options & LLDB_LOG_OPTION_THREADSAFE) + locker.Reset(g_LogThreadedMutex.GetMutex()); + + // Add a sequence ID if requested + if (log_options & LLDB_LOG_OPTION_PREPEND_SEQUENCE) + header.Printf ("%u ", ++g_sequence_id); + + // Timestamp if requested + if (log_options & LLDB_LOG_OPTION_PREPEND_TIMESTAMP) + { + struct timeval tv = TimeValue::Now().GetAsTimeVal(); + header.Printf ("%9llu.%6.6llu ", tv.tv_sec, tv.tv_usec); + } + + // Add the process and thread if requested + if (log_options & LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD) + header.Printf ("[%4.4x/%4.4x]: ", getpid(), mach_thread_self()); + + // Add the process and thread if requested + if (log_options & LLDB_LOG_OPTION_PREPEND_THREAD_NAME) + { + const char *thread_name_str = Host::GetThreadName (getpid(), mach_thread_self()); + if (thread_name_str) + header.Printf ("%s ", thread_name_str); + } + + header.PrintfVarArg (format, args); + m_stream_sp->Printf("%s\n", header.GetData()); + } +} + + +void +Log::PutCString (const char *cstr) +{ + Printf ("%s", cstr); +} + + +//---------------------------------------------------------------------- +// Simple variable argument logging with flags. +//---------------------------------------------------------------------- +void +Log::Printf(const char *format, ...) +{ + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (0, format, args); + va_end (args); +} + +void +Log::VAPrintf (const char *format, va_list args) +{ + PrintfWithFlagsVarArg (0, format, args); +} + + +//---------------------------------------------------------------------- +// Simple variable argument logging with flags. +//---------------------------------------------------------------------- +void +Log::PrintfWithFlags (uint32_t flags, const char *format, ...) +{ + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (flags, format, args); + va_end (args); +} + +//---------------------------------------------------------------------- +// Print debug strings if and only if the global debug option is set to +// a non-zero value. +//---------------------------------------------------------------------- +void +Log::Debug (const char *format, ...) +{ + if (GetOptions().IsSet(LLDB_LOG_OPTION_DEBUG)) + { + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG, format, args); + va_end (args); + } +} + + +//---------------------------------------------------------------------- +// Print debug strings if and only if the global debug option is set to +// a non-zero value. +//---------------------------------------------------------------------- +void +Log::DebugVerbose (const char *format, ...) +{ + if (GetOptions().IsSet(LLDB_LOG_OPTION_DEBUG) && GetOptions().IsSet(LLDB_LOG_OPTION_VERBOSE)) + { + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG | LLDB_LOG_FLAG_VERBOSE, format, args); + va_end (args); + } +} + + +//---------------------------------------------------------------------- +// Log only if all of the bits are set +//---------------------------------------------------------------------- +void +Log::LogIf (uint32_t bits, const char *format, ...) +{ + if ((bits & m_options.GetAllFlagBits()) == bits) + { + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (0, format, args); + va_end (args); + } +} + + +//---------------------------------------------------------------------- +// Printing of errors that are not fatal. +//---------------------------------------------------------------------- +void +Log::Error (const char *format, ...) +{ + char *arg_msg = NULL; + va_list args; + va_start (args, format); + ::vasprintf (&arg_msg, format, args); + va_end (args); + + if (arg_msg != NULL) + { + PrintfWithFlags (LLDB_LOG_FLAG_ERROR, "error: %s", arg_msg); + free (arg_msg); + } +} + +//---------------------------------------------------------------------- +// Printing of errors that ARE fatal. Exit with ERR exit code +// immediately. +//---------------------------------------------------------------------- +void +Log::FatalError (int err, const char *format, ...) +{ + char *arg_msg = NULL; + va_list args; + va_start (args, format); + ::vasprintf (&arg_msg, format, args); + va_end (args); + + if (arg_msg != NULL) + { + PrintfWithFlags (LLDB_LOG_FLAG_ERROR | LLDB_LOG_FLAG_FATAL, "error: %s", arg_msg); + ::free (arg_msg); + } + ::exit (err); +} + + +//---------------------------------------------------------------------- +// Printing of warnings that are not fatal only if verbose mode is +// enabled. +//---------------------------------------------------------------------- +void +Log::Verbose (const char *format, ...) +{ + if (m_options.IsSet(LLDB_LOG_OPTION_VERBOSE)) + { + va_list args; + va_start (args, format); + PrintfWithFlagsVarArg (LLDB_LOG_FLAG_VERBOSE, format, args); + va_end (args); + } +} + +//---------------------------------------------------------------------- +// Printing of warnings that are not fatal only if verbose mode is +// enabled. +//---------------------------------------------------------------------- +void +Log::WarningVerbose (const char *format, ...) +{ + if (m_options.IsSet(LLDB_LOG_OPTION_VERBOSE)) + { + char *arg_msg = NULL; + va_list args; + va_start (args, format); + ::vasprintf (&arg_msg, format, args); + va_end (args); + + if (arg_msg != NULL) + { + PrintfWithFlags (LLDB_LOG_FLAG_WARNING | LLDB_LOG_FLAG_VERBOSE, "warning: %s", arg_msg); + free (arg_msg); + } + } +} +//---------------------------------------------------------------------- +// Printing of warnings that are not fatal. +//---------------------------------------------------------------------- +void +Log::Warning (const char *format, ...) +{ + char *arg_msg = NULL; + va_list args; + va_start (args, format); + ::vasprintf (&arg_msg, format, args); + va_end (args); + + if (arg_msg != NULL) + { + PrintfWithFlags (LLDB_LOG_FLAG_WARNING, "warning: %s", arg_msg); + free (arg_msg); + } +} + +typedef std::map <std::string, 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 () +{ + static CallbackMap g_callback_map; + return g_callback_map; +} + +static LogChannelMap & +GetChannelMap () +{ + static LogChannelMap g_channel_map; + return g_channel_map; +} + +void +Log::RegisterLogChannel (const char *channel, const Log::Callbacks &log_callbacks) +{ + GetCallbackMap().insert(std::make_pair(channel, log_callbacks)); +} + +bool +Log::UnregisterLogChannel (const char *channel) +{ + return GetCallbackMap().erase(channel) != 0; +} + +bool +Log::GetLogChannelCallbacks (const char *channel, Log::Callbacks &log_callbacks) +{ + CallbackMap &callback_map = GetCallbackMap (); + CallbackMapIter pos = callback_map.find(channel); + if (pos != callback_map.end()) + { + log_callbacks = pos->second; + return true; + } + ::bzero (&log_callbacks, sizeof(log_callbacks)); + return false; +} + +void +Log::EnableAllLogChannels +( + StreamSP &log_stream_sp, + uint32_t log_options, + Args &args, + Stream *feedback_strm +) +{ + CallbackMap &callback_map = GetCallbackMap (); + CallbackMapIter pos, end = callback_map.end(); + + for (pos = callback_map.begin(); pos != end; ++pos) + pos->second.enable (log_stream_sp, log_options, args, 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, args); + } + +} + +void +Log::DisableAllLogChannels () +{ + CallbackMap &callback_map = GetCallbackMap (); + CallbackMapIter pos, end = callback_map.end(); + + for (pos = callback_map.begin(); pos != end; ++pos) + pos->second.disable (); + + 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 (); +} + +void +Log::ListAllLogChannels (Stream *strm) +{ + CallbackMap &callback_map = GetCallbackMap (); + LogChannelMap &channel_map = GetChannelMap (); + + if (callback_map.empty() && channel_map.empty()) + { + strm->PutCString ("No logging channels are currently registered.\n"); + return; + } + + CallbackMapIter pos, end = callback_map.end(); + 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)) != NULL; ++idx) + { + LogChannelSP log_channel_sp(LogChannel::FindPlugin (name)); + if (log_channel_sp) + log_channel_sp->ListCategories (strm); + } +} + +bool +Log::GetVerbose() const +{ + if (m_stream_sp) + return m_stream_sp->GetVerbose(); + return false; +} + +//------------------------------------------------------------------ +// Returns true if the debug flag bit is set in this stream. +//------------------------------------------------------------------ +bool +Log::GetDebug() const +{ + if (m_stream_sp) + return m_stream_sp->GetDebug(); + return false; +} + + +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()) + { + LogChannelCreateInstance create_callback = PluginManager::GetLogChannelCreateCallbackForPluginName (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_sp () +{ +} + +LogChannel::~LogChannel () +{ +} + +const char * +LogChannel::GetPluginSuffix () +{ + return ".log-channel"; +} + + |