LLDB  mainline
Log.cpp
Go to the documentation of this file.
1 //===-- Log.cpp -----------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Utility/Log.h"
10 #include "lldb/Utility/VASPrintf.h"
11 
12 #include "llvm/ADT/SmallString.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/ADT/iterator.h"
15 
16 #include "llvm/Support/Chrono.h"
17 #include "llvm/Support/ManagedStatic.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/Signals.h"
20 #include "llvm/Support/Threading.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 #include <chrono>
24 #include <cstdarg>
25 #include <mutex>
26 #include <utility>
27 
28 #include <cassert>
29 #if defined(_WIN32)
30 #include <process.h>
31 #else
32 #include <unistd.h>
33 #include <pthread.h>
34 #endif
35 
36 using namespace lldb_private;
37 
38 llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map;
39 
41  const Log::ChannelMap::value_type &entry,
42  llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
43  lambda("all", "all available logging categories");
44  lambda("default", "default set of logging categories");
45  for (const auto &category : entry.second.m_channel.categories)
46  lambda(category.name, category.description);
47 }
48 
49 void Log::ListCategories(llvm::raw_ostream &stream,
50  const ChannelMap::value_type &entry) {
51  stream << llvm::formatv("Logging categories for '{0}':\n", entry.first());
52  ForEachCategory(entry,
53  [&stream](llvm::StringRef name, llvm::StringRef description) {
54  stream << llvm::formatv(" {0} - {1}\n", name, description);
55  });
56 }
57 
58 uint32_t Log::GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &entry,
59  llvm::ArrayRef<const char *> categories) {
60  bool list_categories = false;
61  uint32_t flags = 0;
62  for (const char *category : categories) {
63  if (llvm::StringRef("all").equals_insensitive(category)) {
64  flags |= UINT32_MAX;
65  continue;
66  }
67  if (llvm::StringRef("default").equals_insensitive(category)) {
68  flags |= entry.second.m_channel.default_flags;
69  continue;
70  }
71  auto cat = llvm::find_if(entry.second.m_channel.categories,
72  [&](const Log::Category &c) {
73  return c.name.equals_insensitive(category);
74  });
75  if (cat != entry.second.m_channel.categories.end()) {
76  flags |= cat->flag;
77  continue;
78  }
79  stream << llvm::formatv("error: unrecognized log category '{0}'\n",
80  category);
81  list_categories = true;
82  }
83  if (list_categories)
84  ListCategories(stream, entry);
85  return flags;
86 }
87 
88 void Log::Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp,
89  uint32_t options, uint32_t flags) {
90  llvm::sys::ScopedWriter lock(m_mutex);
91 
92  uint32_t mask = m_mask.fetch_or(flags, std::memory_order_relaxed);
93  if (mask | flags) {
94  m_options.store(options, std::memory_order_relaxed);
95  m_stream_sp = stream_sp;
96  m_channel.log_ptr.store(this, std::memory_order_relaxed);
97  }
98 }
99 
100 void Log::Disable(uint32_t flags) {
101  llvm::sys::ScopedWriter lock(m_mutex);
102 
103  uint32_t mask = m_mask.fetch_and(~flags, std::memory_order_relaxed);
104  if (!(mask & ~flags)) {
105  m_stream_sp.reset();
106  m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
107  }
108 }
109 
110 const Flags Log::GetOptions() const {
111  return m_options.load(std::memory_order_relaxed);
112 }
113 
114 const Flags Log::GetMask() const {
115  return m_mask.load(std::memory_order_relaxed);
116 }
117 
118 void Log::PutCString(const char *cstr) { Printf("%s", cstr); }
119 void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); }
120 
121 // Simple variable argument logging with flags.
122 void Log::Printf(const char *format, ...) {
123  va_list args;
124  va_start(args, format);
125  VAPrintf(format, args);
126  va_end(args);
127 }
128 
129 // All logging eventually boils down to this function call. If we have a
130 // callback registered, then we call the logging callback. If we have a valid
131 // file handle, we also log to the file.
132 void Log::VAPrintf(const char *format, va_list args) {
133  llvm::SmallString<64> FinalMessage;
134  llvm::raw_svector_ostream Stream(FinalMessage);
135  WriteHeader(Stream, "", "");
136 
137  llvm::SmallString<64> Content;
138  lldb_private::VASprintf(Content, format, args);
139 
140  Stream << Content << "\n";
141 
142  WriteMessage(std::string(FinalMessage.str()));
143 }
144 
145 // Printing of errors that are not fatal.
146 void Log::Error(const char *format, ...) {
147  va_list args;
148  va_start(args, format);
149  VAError(format, args);
150  va_end(args);
151 }
152 
153 void Log::VAError(const char *format, va_list args) {
154  llvm::SmallString<64> Content;
155  VASprintf(Content, format, args);
156 
157  Printf("error: %s", Content.c_str());
158 }
159 
160 // Printing of warnings that are not fatal only if verbose mode is enabled.
161 void Log::Verbose(const char *format, ...) {
162  if (!GetVerbose())
163  return;
164 
165  va_list args;
166  va_start(args, format);
167  VAPrintf(format, args);
168  va_end(args);
169 }
170 
171 // Printing of warnings that are not fatal.
172 void Log::Warning(const char *format, ...) {
173  llvm::SmallString<64> Content;
174  va_list args;
175  va_start(args, format);
176  VASprintf(Content, format, args);
177  va_end(args);
178 
179  Printf("warning: %s", Content.c_str());
180 }
181 
183 #ifdef LLVM_ON_UNIX
184  pthread_atfork(nullptr, nullptr, &Log::DisableLoggingChild);
185 #endif
187 }
188 
189 void Log::Register(llvm::StringRef name, Channel &channel) {
190  auto iter = g_channel_map->try_emplace(name, channel);
191  assert(iter.second == true);
192  (void)iter;
193 }
194 
195 void Log::Unregister(llvm::StringRef name) {
196  auto iter = g_channel_map->find(name);
197  assert(iter != g_channel_map->end());
198  iter->second.Disable(UINT32_MAX);
199  g_channel_map->erase(iter);
200 }
201 
203  const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
204  uint32_t log_options, llvm::StringRef channel,
205  llvm::ArrayRef<const char *> categories, llvm::raw_ostream &error_stream) {
206  auto iter = g_channel_map->find(channel);
207  if (iter == g_channel_map->end()) {
208  error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
209  return false;
210  }
211  uint32_t flags = categories.empty()
212  ? iter->second.m_channel.default_flags
213  : GetFlags(error_stream, *iter, categories);
214  iter->second.Enable(log_stream_sp, log_options, flags);
215  return true;
216 }
217 
218 bool Log::DisableLogChannel(llvm::StringRef channel,
219  llvm::ArrayRef<const char *> categories,
220  llvm::raw_ostream &error_stream) {
221  auto iter = g_channel_map->find(channel);
222  if (iter == g_channel_map->end()) {
223  error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
224  return false;
225  }
226  uint32_t flags = categories.empty()
227  ? UINT32_MAX
228  : GetFlags(error_stream, *iter, categories);
229  iter->second.Disable(flags);
230  return true;
231 }
232 
233 bool Log::ListChannelCategories(llvm::StringRef channel,
234  llvm::raw_ostream &stream) {
235  auto ch = g_channel_map->find(channel);
236  if (ch == g_channel_map->end()) {
237  stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
238  return false;
239  }
240  ListCategories(stream, *ch);
241  return true;
242 }
243 
245  for (auto &entry : *g_channel_map)
246  entry.second.Disable(UINT32_MAX);
247 }
248 
250  llvm::StringRef channel,
251  llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> lambda) {
252  auto ch = g_channel_map->find(channel);
253  if (ch == g_channel_map->end())
254  return;
255 
256  ForEachCategory(*ch, lambda);
257 }
258 
259 std::vector<llvm::StringRef> Log::ListChannels() {
260  std::vector<llvm::StringRef> result;
261  for (const auto &channel : *g_channel_map)
262  result.push_back(channel.first());
263  return result;
264 }
265 
266 void Log::ListAllLogChannels(llvm::raw_ostream &stream) {
267  if (g_channel_map->empty()) {
268  stream << "No logging channels are currently registered.\n";
269  return;
270  }
271 
272  for (const auto &channel : *g_channel_map)
273  ListCategories(stream, channel);
274 }
275 
276 bool Log::GetVerbose() const {
277  return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE;
278 }
279 
280 void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
281  llvm::StringRef function) {
282  Flags options = GetOptions();
283  static uint32_t g_sequence_id = 0;
284  // Add a sequence ID if requested
286  OS << ++g_sequence_id << " ";
287 
288  // Timestamp if requested
290  auto now = std::chrono::duration<double>(
291  std::chrono::system_clock::now().time_since_epoch());
292  OS << llvm::formatv("{0:f9} ", now.count());
293  }
294 
295  // Add the process and thread if requested
297  OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(),
298  llvm::get_threadid());
299 
300  // Add the thread name if requested
302  llvm::SmallString<32> thread_name;
303  llvm::get_thread_name(thread_name);
304 
305  llvm::SmallString<12> format_str;
306  llvm::raw_svector_ostream format_os(format_str);
307  format_os << "{0,-" << llvm::alignTo<16>(thread_name.size()) << "} ";
308  OS << llvm::formatv(format_str.c_str(), thread_name);
309  }
310 
311  if (options.Test(LLDB_LOG_OPTION_BACKTRACE))
312  llvm::sys::PrintStackTrace(OS);
313 
315  (!file.empty() || !function.empty())) {
316  file = llvm::sys::path::filename(file).take_front(40);
317  function = function.take_front(40);
318  OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str());
319  }
320 }
321 
323  // Make a copy of our stream shared pointer in case someone disables our log
324  // while we are logging and releases the stream
325  auto stream_sp = GetStream();
326  if (!stream_sp)
327  return;
328 
329  Flags options = GetOptions();
330  if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) {
331  static std::recursive_mutex g_LogThreadedMutex;
332  std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex);
333  *stream_sp << message;
334  stream_sp->flush();
335  } else {
336  *stream_sp << message;
337  stream_sp->flush();
338  }
339 }
340 
341 void Log::Format(llvm::StringRef file, llvm::StringRef function,
342  const llvm::formatv_object_base &payload) {
343  std::string message_string;
344  llvm::raw_string_ostream message(message_string);
345  WriteHeader(message, file, function);
346  message << payload << "\n";
347  WriteMessage(message.str());
348 }
349 
351  // Disable logging by clearing out the atomic variable after forking -- if we
352  // forked while another thread held the channel mutex, we would deadlock when
353  // trying to write to the log.
354  for (auto &c: *g_channel_map)
355  c.second.m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
356 }
lldb_private::Log::m_mask
std::atomic< uint32_t > m_mask
Definition: Log.h:183
lldb_private::Log::VAError
void VAError(const char *format, va_list args)
Definition: Log.cpp:153
LLDB_LOG_OPTION_PREPEND_THREAD_NAME
#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME
Definition: Log.h:41
lldb_private::Log::PutString
void PutString(llvm::StringRef str)
Definition: Log.cpp:119
lldb_private::Log::m_options
std::atomic< uint32_t > m_options
Definition: Log.h:182
lldb_private::Log::GetVerbose
bool GetVerbose() const
Definition: Log.cpp:276
lldb_private::Log::VAPrintf
void VAPrintf(const char *format, va_list args)
Definition: Log.cpp:132
lldb_private::Log::Register
static void Register(llvm::StringRef name, Channel &channel)
Definition: Log.cpp:189
lldb_private::Log::Warning
void void void void Warning(const char *fmt,...) __attribute__((format(printf
Definition: Log.cpp:172
lldb_private::Flags
Definition: Flags.h:22
lldb_private::Log::DisableLogChannel
static bool DisableLogChannel(llvm::StringRef channel, llvm::ArrayRef< const char * > categories, llvm::raw_ostream &error_stream)
Definition: Log.cpp:218
lldb_private::Log::m_stream_sp
std::shared_ptr< llvm::raw_ostream > m_stream_sp
Definition: Log.h:181
lldb_private::Flags::Test
bool Test(ValueType bit) const
Test a single flag bit.
Definition: Flags.h:96
lldb_private::Stream
Definition: Stream.h:28
lldb_private::InitializeLldbChannel
void InitializeLldbChannel()
Definition: Logging.cpp:54
lldb_private::Log::ForEachChannelCategory
static void ForEachChannelCategory(llvm::StringRef channel, llvm::function_ref< void(llvm::StringRef, llvm::StringRef)> lambda)
Calls the given lambda for every category in the given channel.
Definition: Log.cpp:249
lldb_private::Log::GetMask
const Flags GetMask() const
Definition: Log.cpp:114
LLDB_LOG_OPTION_VERBOSE
#define LLDB_LOG_OPTION_VERBOSE
Definition: Log.h:37
lldb_private::Log::ForEachCategory
static void ForEachCategory(const Log::ChannelMap::value_type &entry, llvm::function_ref< void(llvm::StringRef, llvm::StringRef)> lambda)
Definition: Log.cpp:40
lldb_private::Log::GetStream
std::shared_ptr< llvm::raw_ostream > GetStream()
Definition: Log.h:192
lldb_private::Log::DisableLoggingChild
static void DisableLoggingChild()
Definition: Log.cpp:350
LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD
#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD
Definition: Log.h:40
lldb_private::Log::Printf
void Printf(const char *format,...) __attribute__((format(printf
Prefer using LLDB_LOGF whenever possible.
Definition: Log.cpp:122
lldb_private::Log::Category
Definition: Log.h:52
lldb_private::Log::ListChannelCategories
static bool ListChannelCategories(llvm::StringRef channel, llvm::raw_ostream &stream)
Definition: Log.cpp:233
lldb_private::Log::ListAllLogChannels
static void ListAllLogChannels(llvm::raw_ostream &stream)
Definition: Log.cpp:266
lldb_private::Log::Format
void Format(llvm::StringRef file, llvm::StringRef function, const char *format, Args &&... args)
Definition: Log.h:140
VASPrintf.h
Log.h
lldb_private::Log::DisableAllLogChannels
static void DisableAllLogChannels()
Definition: Log.cpp:244
lldb_private::Log::Initialize
static void Initialize()
Definition: Log.cpp:182
lldb_private::Log::Unregister
static void Unregister(llvm::StringRef name)
Definition: Log.cpp:195
lldb_private::Log::m_channel
Channel & m_channel
Definition: Log.h:173
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::VASprintf
bool VASprintf(llvm::SmallVectorImpl< char > &buf, const char *fmt, va_list args)
Definition: VASprintf.cpp:19
lldb_private::Log::WriteHeader
void WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file, llvm::StringRef function)
Definition: Log.cpp:280
lldb_private::Log::EnableLogChannel
static bool EnableLogChannel(const std::shared_ptr< llvm::raw_ostream > &log_stream_sp, uint32_t log_options, llvm::StringRef channel, llvm::ArrayRef< const char * > categories, llvm::raw_ostream &error_stream)
Definition: Log.cpp:202
lldb_private::Log::Channel
Definition: Log.h:60
LLDB_LOG_OPTION_PREPEND_TIMESTAMP
#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP
Definition: Log.h:39
lldb_private::Log::Error
void void Error(const char *fmt,...) __attribute__((format(printf
Definition: Log.cpp:146
message
message(FATAL_ERROR "invalid libipt include path provided") endif() include_directories($
Definition: Plugins/Trace/intel-pt/CMakeLists.txt:6
uint32_t
lldb_private::Log::Verbose
void void void Verbose(const char *fmt,...) __attribute__((format(printf
Definition: Log.cpp:161
lldb_private::Log::g_channel_map
static llvm::ManagedStatic< ChannelMap > g_channel_map
Definition: Log.h:203
lldb_private::Log::m_mutex
llvm::sys::RWMutex m_mutex
Definition: Log.h:179
lldb_private::Log::Enable
void Enable(const std::shared_ptr< llvm::raw_ostream > &stream_sp, uint32_t options, uint32_t flags)
Definition: Log.cpp:88
LLDB_LOG_OPTION_PREPEND_SEQUENCE
#define LLDB_LOG_OPTION_PREPEND_SEQUENCE
Definition: Log.h:38
UINT32_MAX
#define UINT32_MAX
Definition: lldb-defines.h:31
lldb_private::Log::WriteMessage
void WriteMessage(const std::string &message)
Definition: Log.cpp:322
lldb_private::Log::GetFlags
static uint32_t GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &entry, llvm::ArrayRef< const char * > categories)
Definition: Log.cpp:58
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
LLDB_LOG_OPTION_THREADSAFE
#define LLDB_LOG_OPTION_THREADSAFE
Definition: Log.h:36
lldb_private::Log::GetOptions
void void void void const Flags GetOptions() const
Definition: Log.cpp:110
lldb_private::Log::Channel::log_ptr
std::atomic< Log * > log_ptr
Definition: Log.h:61
LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION
#define LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION
Definition: Log.h:44
lldb_private::Log::ListCategories
static void ListCategories(llvm::raw_ostream &stream, const ChannelMap::value_type &entry)
Definition: Log.cpp:49
LLDB_LOG_OPTION_BACKTRACE
#define LLDB_LOG_OPTION_BACKTRACE
Definition: Log.h:42
lldb_private::Log::Disable
void Disable(uint32_t flags)
Definition: Log.cpp:100
lldb_private::Log::ListChannels
static std::vector< llvm::StringRef > ListChannels()
Returns the list of log channels.
Definition: Log.cpp:259
lldb_private::Log::PutCString
void PutCString(const char *cstr)
Definition: Log.cpp:118