blob: b62df3c1fe97ddc32d2c4524729b166eefc3f3af [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Log.cpp -------------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Pavel Labath774103c2016-11-02 12:18:42 +000010// Project includes
11#include "lldb/Core/Log.h"
12#include "lldb/Core/PluginManager.h"
13#include "lldb/Core/StreamFile.h"
14#include "lldb/Core/StreamString.h"
15#include "lldb/Host/Host.h"
16#include "lldb/Host/ThisThread.h"
17#include "lldb/Interpreter/Args.h"
18#include "lldb/Utility/NameMatches.h"
19
20// Other libraries and framework includes
21#include "llvm/ADT/SmallString.h"
22#include "llvm/Support/Chrono.h"
23#include "llvm/Support/Signals.h"
24#include "llvm/Support/raw_ostream.h"
25
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026// C Includes
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027// C++ Includes
Eugene Zelenkoa74f37a2016-03-10 23:57:12 +000028#include <cstdarg>
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +000029#include <cstdio>
Eugene Zelenkoa74f37a2016-03-10 23:57:12 +000030#include <cstdlib>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031#include <map>
Saleem Abdulrasool16ff8602016-05-18 01:59:10 +000032#include <mutex>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033#include <string>
34
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035using namespace lldb;
36using namespace lldb_private;
37
Kate Stoneb9c1b512016-09-06 20:57:50 +000038Log::Log() : m_stream_sp(), m_options(0), m_mask_bits(0) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000039
Kate Stoneb9c1b512016-09-06 20:57:50 +000040Log::Log(const StreamSP &stream_sp)
41 : m_stream_sp(stream_sp), m_options(0), m_mask_bits(0) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000042
Eugene Zelenkoa74f37a2016-03-10 23:57:12 +000043Log::~Log() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045Flags &Log::GetOptions() { return m_options; }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000046
Kate Stoneb9c1b512016-09-06 20:57:50 +000047const Flags &Log::GetOptions() const { return m_options; }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049Flags &Log::GetMask() { return m_mask_bits; }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000050
Kate Stoneb9c1b512016-09-06 20:57:50 +000051const Flags &Log::GetMask() const { return m_mask_bits; }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000052
Kate Stoneb9c1b512016-09-06 20:57:50 +000053void Log::PutCString(const char *cstr) { Printf("%s", cstr); }
Zachary Turnerc1564272016-11-16 21:15:24 +000054void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); }
Zachary Turnerc1592652015-04-29 22:55:28 +000055
56//----------------------------------------------------------------------
57// Simple variable argument logging with flags.
58//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000059void Log::Printf(const char *format, ...) {
60 va_list args;
61 va_start(args, format);
62 VAPrintf(format, args);
63 va_end(args);
Zachary Turnerc1592652015-04-29 22:55:28 +000064}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065
66//----------------------------------------------------------------------
67// All logging eventually boils down to this function call. If we have
68// a callback registered, then we call the logging callback. If we have
69// a valid file handle, we also log to the file.
70//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000071void Log::VAPrintf(const char *format, va_list args) {
72 // Make a copy of our stream shared pointer in case someone disables our
73 // log while we are logging and releases the stream
74 StreamSP stream_sp(m_stream_sp);
75 if (stream_sp) {
76 static uint32_t g_sequence_id = 0;
77 StreamString header;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000078
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 // Add a sequence ID if requested
80 if (m_options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE))
81 header.Printf("%u ", ++g_sequence_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 // Timestamp if requested
84 if (m_options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) {
Pavel Labath774103c2016-11-02 12:18:42 +000085 auto now = std::chrono::duration<double>(
86 std::chrono::system_clock::now().time_since_epoch());
87 header.Printf("%.9f ", now.count());
Chris Lattner30fdc8d2010-06-08 16:52:24 +000088 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000089
90 // Add the process and thread if requested
91 if (m_options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
92 header.Printf("[%4.4x/%4.4" PRIx64 "]: ", getpid(),
93 Host::GetCurrentThreadID());
94
95 // Add the thread name if requested
96 if (m_options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) {
97 llvm::SmallString<32> thread_name;
98 ThisThread::GetName(thread_name);
99 if (!thread_name.empty())
100 header.Printf("%s ", thread_name.c_str());
101 }
102
103 header.PrintfVarArg(format, args);
104 header.PutCString("\n");
105
106 if (m_options.Test(LLDB_LOG_OPTION_BACKTRACE)) {
107 std::string back_trace;
108 llvm::raw_string_ostream stream(back_trace);
109 llvm::sys::PrintStackTrace(stream);
110 stream.flush();
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000111 header.PutCString(back_trace);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 }
113
114 if (m_options.Test(LLDB_LOG_OPTION_THREADSAFE)) {
115 static std::recursive_mutex g_LogThreadedMutex;
116 std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex);
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000117 stream_sp->PutCString(header.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 stream_sp->Flush();
119 } else {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000120 stream_sp->PutCString(header.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 stream_sp->Flush();
122 }
123 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000124}
125
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000126//----------------------------------------------------------------------
127// Print debug strings if and only if the global debug option is set to
128// a non-zero value.
129//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130void Log::Debug(const char *format, ...) {
131 if (!GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
132 return;
Zachary Turnerc1592652015-04-29 22:55:28 +0000133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 va_list args;
135 va_start(args, format);
136 VAPrintf(format, args);
137 va_end(args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000138}
139
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000140//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000141// Log only if all of the bits are set
142//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143void Log::LogIf(uint32_t bits, const char *format, ...) {
144 if (!m_options.AllSet(bits))
145 return;
Zachary Turnerc1592652015-04-29 22:55:28 +0000146
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 va_list args;
148 va_start(args, format);
149 VAPrintf(format, args);
150 va_end(args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000151}
152
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153//----------------------------------------------------------------------
154// Printing of errors that are not fatal.
155//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156void Log::Error(const char *format, ...) {
157 va_list args;
158 va_start(args, format);
159 VAError(format, args);
160 va_end(args);
Zachary Turner610e5292015-05-07 21:39:33 +0000161}
162
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163void Log::VAError(const char *format, va_list args) {
164 char *arg_msg = nullptr;
165 ::vasprintf(&arg_msg, format, args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 if (arg_msg == nullptr)
168 return;
Zachary Turnerc1592652015-04-29 22:55:28 +0000169
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 Printf("error: %s", arg_msg);
171 free(arg_msg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000172}
173
174//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000175// Printing of warnings that are not fatal only if verbose mode is
176// enabled.
177//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178void Log::Verbose(const char *format, ...) {
179 if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
180 return;
Zachary Turnerc1592652015-04-29 22:55:28 +0000181
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182 va_list args;
183 va_start(args, format);
184 VAPrintf(format, args);
185 va_end(args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000186}
187
188//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189// Printing of warnings that are not fatal.
190//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191void Log::Warning(const char *format, ...) {
192 char *arg_msg = nullptr;
193 va_list args;
194 va_start(args, format);
195 ::vasprintf(&arg_msg, format, args);
196 va_end(args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000197
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198 if (arg_msg == nullptr)
199 return;
Zachary Turnerc1592652015-04-29 22:55:28 +0000200
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 Printf("warning: %s", arg_msg);
202 free(arg_msg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000203}
204
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205typedef std::map<ConstString, Log::Callbacks> CallbackMap;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000206typedef CallbackMap::iterator CallbackMapIter;
207
Kate Stoneb9c1b512016-09-06 20:57:50 +0000208typedef std::map<ConstString, LogChannelSP> LogChannelMap;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000209typedef LogChannelMap::iterator LogChannelMapIter;
210
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000211// Surround our callback map with a singleton function so we don't have any
212// global initializers.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213static CallbackMap &GetCallbackMap() {
214 static CallbackMap g_callback_map;
215 return g_callback_map;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000216}
217
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218static LogChannelMap &GetChannelMap() {
219 static LogChannelMap g_channel_map;
220 return g_channel_map;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000221}
222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223void Log::RegisterLogChannel(const ConstString &channel,
224 const Log::Callbacks &log_callbacks) {
225 GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000226}
227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228bool Log::UnregisterLogChannel(const ConstString &channel) {
229 return GetCallbackMap().erase(channel) != 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000230}
231
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232bool Log::GetLogChannelCallbacks(const ConstString &channel,
233 Log::Callbacks &log_callbacks) {
234 CallbackMap &callback_map = GetCallbackMap();
235 CallbackMapIter pos = callback_map.find(channel);
236 if (pos != callback_map.end()) {
237 log_callbacks = pos->second;
238 return true;
239 }
240 ::memset(&log_callbacks, 0, sizeof(log_callbacks));
241 return false;
242}
243
244bool Log::EnableLogChannel(lldb::StreamSP &log_stream_sp, uint32_t log_options,
245 const char *channel, const char **categories,
246 Stream &error_stream) {
247 Log::Callbacks log_callbacks;
248 if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
249 log_callbacks.enable(log_stream_sp, log_options, categories, &error_stream);
250 return true;
251 }
252
253 LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel));
254 if (log_channel_sp) {
255 if (log_channel_sp->Enable(log_stream_sp, log_options, &error_stream,
256 categories)) {
257 return true;
258 } else {
259 error_stream.Printf("Invalid log channel '%s'.\n", channel);
260 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000261 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262 } else {
263 error_stream.Printf("Invalid log channel '%s'.\n", channel);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000264 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000266}
267
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268void Log::EnableAllLogChannels(StreamSP &log_stream_sp, uint32_t log_options,
269 const char **categories, Stream *feedback_strm) {
270 CallbackMap &callback_map = GetCallbackMap();
271 CallbackMapIter pos, end = callback_map.end();
272
273 for (pos = callback_map.begin(); pos != end; ++pos)
274 pos->second.enable(log_stream_sp, log_options, categories, feedback_strm);
275
276 LogChannelMap &channel_map = GetChannelMap();
277 LogChannelMapIter channel_pos, channel_end = channel_map.end();
278 for (channel_pos = channel_map.begin(); channel_pos != channel_end;
279 ++channel_pos) {
280 channel_pos->second->Enable(log_stream_sp, log_options, feedback_strm,
281 categories);
282 }
283}
284
285void Log::AutoCompleteChannelName(const char *channel_name,
286 StringList &matches) {
287 LogChannelMap &map = GetChannelMap();
288 LogChannelMapIter pos, end = map.end();
289 for (pos = map.begin(); pos != end; ++pos) {
290 const char *pos_channel_name = pos->first.GetCString();
291 if (channel_name && channel_name[0]) {
292 if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) {
293 matches.AppendString(pos_channel_name);
294 }
295 } else
296 matches.AppendString(pos_channel_name);
297 }
298}
299
300void Log::DisableAllLogChannels(Stream *feedback_strm) {
301 CallbackMap &callback_map = GetCallbackMap();
302 CallbackMapIter pos, end = callback_map.end();
303 const char *categories[] = {"all", nullptr};
304
305 for (pos = callback_map.begin(); pos != end; ++pos)
306 pos->second.disable(categories, feedback_strm);
307
308 LogChannelMap &channel_map = GetChannelMap();
309 LogChannelMapIter channel_pos, channel_end = channel_map.end();
310 for (channel_pos = channel_map.begin(); channel_pos != channel_end;
311 ++channel_pos)
312 channel_pos->second->Disable(categories, feedback_strm);
313}
314
315void Log::Initialize() {
316 Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
317 Log::RegisterLogChannel(ConstString("lldb"), log_callbacks);
318}
319
320void Log::Terminate() { DisableAllLogChannels(nullptr); }
321
322void Log::ListAllLogChannels(Stream *strm) {
323 CallbackMap &callback_map = GetCallbackMap();
324 LogChannelMap &channel_map = GetChannelMap();
325
326 if (callback_map.empty() && channel_map.empty()) {
327 strm->PutCString("No logging channels are currently registered.\n");
328 return;
329 }
330
331 CallbackMapIter pos, end = callback_map.end();
332 for (pos = callback_map.begin(); pos != end; ++pos)
333 pos->second.list_categories(strm);
334
335 uint32_t idx = 0;
336 const char *name;
337 for (idx = 0;
338 (name = PluginManager::GetLogChannelCreateNameAtIndex(idx)) != nullptr;
339 ++idx) {
340 LogChannelSP log_channel_sp(LogChannel::FindPlugin(name));
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000341 if (log_channel_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000342 log_channel_sp->ListCategories(strm);
343 }
Tamas Berghammer9c9ecce2015-05-27 13:34:04 +0000344}
345
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346bool Log::GetVerbose() const {
347 // FIXME: This has to be centralized between the stream and the log...
348 if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
349 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000350
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 // Make a copy of our stream shared pointer in case someone disables our
352 // log while we are logging and releases the stream
353 StreamSP stream_sp(m_stream_sp);
354 if (stream_sp)
355 return stream_sp->GetVerbose();
356 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000357}
358
359//------------------------------------------------------------------
360// Returns true if the debug flag bit is set in this stream.
361//------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000362bool Log::GetDebug() const {
363 // Make a copy of our stream shared pointer in case someone disables our
364 // log while we are logging and releases the stream
365 StreamSP stream_sp(m_stream_sp);
366 if (stream_sp)
367 return stream_sp->GetDebug();
368 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000369}
370
Kate Stoneb9c1b512016-09-06 20:57:50 +0000371LogChannelSP LogChannel::FindPlugin(const char *plugin_name) {
372 LogChannelSP log_channel_sp;
373 LogChannelMap &channel_map = GetChannelMap();
374 ConstString log_channel_name(plugin_name);
375 LogChannelMapIter pos = channel_map.find(log_channel_name);
376 if (pos == channel_map.end()) {
377 ConstString const_plugin_name(plugin_name);
378 LogChannelCreateInstance create_callback =
379 PluginManager::GetLogChannelCreateCallbackForPluginName(
380 const_plugin_name);
381 if (create_callback) {
382 log_channel_sp.reset(create_callback());
383 if (log_channel_sp) {
384 // Cache the one and only loaded instance of each log channel
385 // plug-in after it has been loaded once.
386 channel_map[log_channel_name] = log_channel_sp;
387 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000388 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000389 } else {
390 // We have already loaded an instance of this log channel class,
391 // so just return the cached instance.
392 log_channel_sp = pos->second;
393 }
394 return log_channel_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000395}
396
Kate Stoneb9c1b512016-09-06 20:57:50 +0000397LogChannel::LogChannel() : m_log_ap() {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000398
Eugene Zelenkoa74f37a2016-03-10 23:57:12 +0000399LogChannel::~LogChannel() = default;