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