1 //===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "ProcessPOSIXLog.h"
12 
13 #include <mutex>
14 
15 #include "lldb/Core/StreamFile.h"
16 #include "lldb/Interpreter/Args.h"
17 
18 #include "llvm/Support/Threading.h"
19 
20 #include "ProcessPOSIXLog.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 // We want to avoid global constructors where code needs to be run so here we
26 // control access to our static g_log_sp by hiding it in a singleton function
27 // that will construct the static g_log_sp the first time this function is
28 // called.
29 static bool g_log_enabled = false;
30 static Log *g_log = NULL;
31 static Log *GetLog() {
32   if (!g_log_enabled)
33     return NULL;
34   return g_log;
35 }
36 
37 void ProcessPOSIXLog::Initialize(ConstString name) {
38   static llvm::once_flag g_once_flag;
39 
40   llvm::call_once(g_once_flag, [name]() {
41     Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
42 
43     Log::RegisterLogChannel(name, log_callbacks);
44     RegisterPluginName(name);
45   });
46 }
47 
48 Log *ProcessPOSIXLog::GetLogIfAllCategoriesSet(uint32_t mask) {
49   Log *log(GetLog());
50   if (log && mask) {
51     uint32_t log_mask = log->GetMask().Get();
52     if ((log_mask & mask) != mask)
53       return NULL;
54   }
55   return log;
56 }
57 
58 static uint32_t GetFlagBits(const char *arg) {
59   if (::strcasecmp(arg, "all") == 0)
60     return POSIX_LOG_ALL;
61   else if (::strcasecmp(arg, "async") == 0)
62     return POSIX_LOG_ASYNC;
63   else if (::strncasecmp(arg, "break", 5) == 0)
64     return POSIX_LOG_BREAKPOINTS;
65   else if (::strncasecmp(arg, "comm", 4) == 0)
66     return POSIX_LOG_COMM;
67   else if (::strcasecmp(arg, "default") == 0)
68     return POSIX_LOG_DEFAULT;
69   else if (::strcasecmp(arg, "packets") == 0)
70     return POSIX_LOG_PACKETS;
71   else if (::strcasecmp(arg, "memory") == 0)
72     return POSIX_LOG_MEMORY;
73   else if (::strcasecmp(arg, "data-short") == 0)
74     return POSIX_LOG_MEMORY_DATA_SHORT;
75   else if (::strcasecmp(arg, "data-long") == 0)
76     return POSIX_LOG_MEMORY_DATA_LONG;
77   else if (::strcasecmp(arg, "process") == 0)
78     return POSIX_LOG_PROCESS;
79   else if (::strcasecmp(arg, "ptrace") == 0)
80     return POSIX_LOG_PTRACE;
81   else if (::strcasecmp(arg, "registers") == 0)
82     return POSIX_LOG_REGISTERS;
83   else if (::strcasecmp(arg, "step") == 0)
84     return POSIX_LOG_STEP;
85   else if (::strcasecmp(arg, "thread") == 0)
86     return POSIX_LOG_THREAD;
87   else if (::strcasecmp(arg, "verbose") == 0)
88     return POSIX_LOG_VERBOSE;
89   else if (::strncasecmp(arg, "watch", 5) == 0)
90     return POSIX_LOG_WATCHPOINTS;
91   return 0;
92 }
93 
94 void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) {
95   Log *log(GetLog());
96   if (log) {
97     uint32_t flag_bits = 0;
98 
99     flag_bits = log->GetMask().Get();
100     for (; args && args[0]; args++) {
101       const char *arg = args[0];
102       uint32_t bits = GetFlagBits(arg);
103 
104       if (bits) {
105         flag_bits &= ~bits;
106       } else {
107         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
108         ListLogCategories(feedback_strm);
109       }
110     }
111 
112     log->GetMask().Reset(flag_bits);
113     if (flag_bits == 0)
114       g_log_enabled = false;
115   }
116 
117   return;
118 }
119 
120 Log *ProcessPOSIXLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
121                                 const char **args, Stream *feedback_strm) {
122   // Try see if there already is a log - that way we can reuse its settings.
123   // We could reuse the log in toto, but we don't know that the stream is the
124   // same.
125   uint32_t flag_bits = 0;
126   if (g_log)
127     flag_bits = g_log->GetMask().Get();
128 
129   // Now make a new log with this stream if one was provided
130   if (log_stream_sp) {
131     if (g_log)
132       g_log->SetStream(log_stream_sp);
133     else
134       g_log = new Log(log_stream_sp);
135   }
136 
137   if (g_log) {
138     bool got_unknown_category = false;
139     for (; args && args[0]; args++) {
140       const char *arg = args[0];
141       uint32_t bits = GetFlagBits(arg);
142 
143       if (bits) {
144         flag_bits |= bits;
145       } else {
146         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
147         if (got_unknown_category == false) {
148           got_unknown_category = true;
149           ListLogCategories(feedback_strm);
150         }
151       }
152     }
153     if (flag_bits == 0)
154       flag_bits = POSIX_LOG_DEFAULT;
155     g_log->GetMask().Reset(flag_bits);
156     g_log->GetOptions().Reset(log_options);
157     g_log_enabled = true;
158   }
159   return g_log;
160 }
161 
162 void ProcessPOSIXLog::ListLogCategories(Stream *strm) {
163   strm->Printf(
164       "Logging categories for '%s':\n"
165       "  all - turn on all available logging categories\n"
166       "  async - log asynchronous activity\n"
167       "  break - log breakpoints\n"
168       "  communication - log communication activity\n"
169       "  default - enable the default set of logging categories for liblldb\n"
170       "  packets - log gdb remote packets\n"
171       "  memory - log memory reads and writes\n"
172       "  data-short - log memory bytes for memory reads and writes for short "
173       "transactions only\n"
174       "  data-long - log memory bytes for memory reads and writes for all "
175       "transactions\n"
176       "  process - log process events and activities\n"
177 #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
178       "  ptrace - log all calls to ptrace\n"
179 #endif
180       "  registers - log register read/writes\n"
181       "  thread - log thread events and activities\n"
182       "  step - log step related activities\n"
183       "  verbose - enable verbose logging\n"
184       "  watch - log watchpoint related activities\n",
185       ProcessPOSIXLog::m_pluginname);
186 }
187 
188 void ProcessPOSIXLog::LogIf(uint32_t mask, const char *format, ...) {
189   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(mask));
190   if (log) {
191     va_list args;
192     va_start(args, format);
193     log->VAPrintf(format, args);
194     va_end(args);
195   }
196 }
197 
198 int ProcessPOSIXLog::m_nestinglevel;
199 const char *ProcessPOSIXLog::m_pluginname = "";
200