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 (::strncasecmp(arg, "watch", 5) == 0)
88     return POSIX_LOG_WATCHPOINTS;
89   return 0;
90 }
91 
92 void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) {
93   Log *log(GetLog());
94   if (log) {
95     uint32_t flag_bits = 0;
96 
97     flag_bits = log->GetMask().Get();
98     for (; args && args[0]; args++) {
99       const char *arg = args[0];
100       uint32_t bits = GetFlagBits(arg);
101 
102       if (bits) {
103         flag_bits &= ~bits;
104       } else {
105         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
106         ListLogCategories(feedback_strm);
107       }
108     }
109 
110     log->GetMask().Reset(flag_bits);
111     if (flag_bits == 0)
112       g_log_enabled = false;
113   }
114 
115   return;
116 }
117 
118 Log *ProcessPOSIXLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
119                                 const char **args, Stream *feedback_strm) {
120   // Try see if there already is a log - that way we can reuse its settings.
121   // We could reuse the log in toto, but we don't know that the stream is the
122   // same.
123   uint32_t flag_bits = 0;
124   if (g_log)
125     flag_bits = g_log->GetMask().Get();
126 
127   // Now make a new log with this stream if one was provided
128   if (log_stream_sp) {
129     if (g_log)
130       g_log->SetStream(log_stream_sp);
131     else
132       g_log = new Log(log_stream_sp);
133   }
134 
135   if (g_log) {
136     bool got_unknown_category = false;
137     for (; args && args[0]; args++) {
138       const char *arg = args[0];
139       uint32_t bits = GetFlagBits(arg);
140 
141       if (bits) {
142         flag_bits |= bits;
143       } else {
144         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
145         if (got_unknown_category == false) {
146           got_unknown_category = true;
147           ListLogCategories(feedback_strm);
148         }
149       }
150     }
151     if (flag_bits == 0)
152       flag_bits = POSIX_LOG_DEFAULT;
153     g_log->GetMask().Reset(flag_bits);
154     g_log->GetOptions().Reset(log_options);
155     g_log_enabled = true;
156   }
157   return g_log;
158 }
159 
160 void ProcessPOSIXLog::ListLogCategories(Stream *strm) {
161   strm->Printf(
162       "Logging categories for '%s':\n"
163       "  all - turn on all available logging categories\n"
164       "  async - log asynchronous activity\n"
165       "  break - log breakpoints\n"
166       "  communication - log communication activity\n"
167       "  default - enable the default set of logging categories for liblldb\n"
168       "  packets - log gdb remote packets\n"
169       "  memory - log memory reads and writes\n"
170       "  data-short - log memory bytes for memory reads and writes for short "
171       "transactions only\n"
172       "  data-long - log memory bytes for memory reads and writes for all "
173       "transactions\n"
174       "  process - log process events and activities\n"
175 #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
176       "  ptrace - log all calls to ptrace\n"
177 #endif
178       "  registers - log register read/writes\n"
179       "  thread - log thread events and activities\n"
180       "  step - log step related activities\n"
181       "  verbose - enable verbose logging\n"
182       "  watch - log watchpoint related activities\n",
183       ProcessPOSIXLog::m_pluginname);
184 }
185 
186 void ProcessPOSIXLog::LogIf(uint32_t mask, const char *format, ...) {
187   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(mask));
188   if (log) {
189     va_list args;
190     va_start(args, format);
191     log->VAPrintf(format, args);
192     va_end(args);
193   }
194 }
195 
196 int ProcessPOSIXLog::m_nestinglevel;
197 const char *ProcessPOSIXLog::m_pluginname = "";
198