xref: /llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp (revision c5f28e2a05f2ebff09e1cd02a5faa84369c5c655)
1 //===-- ProcessGDBRemoteLog.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 "ProcessGDBRemoteLog.h"
11 
12 #include <mutex>
13 
14 #include "lldb/Core/StreamFile.h"
15 #include "lldb/Interpreter/Args.h"
16 
17 #include "llvm/Support/Threading.h"
18 
19 #include "ProcessGDBRemote.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace lldb_private::process_gdb_remote;
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_lob_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 ProcessGDBRemoteLog::Initialize() {
38   static ConstString g_name("gdb-remote");
39   static llvm::once_flag g_once_flag;
40 
41   llvm::call_once(g_once_flag, []() {
42     Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
43 
44     Log::RegisterLogChannel(g_name, log_callbacks);
45   });
46 }
47 
48 Log *ProcessGDBRemoteLog::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 Log *ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(uint32_t mask) {
59   Log *log(GetLog());
60   if (log && log->GetMask().Get() & mask)
61     return log;
62   return NULL;
63 }
64 
65 void ProcessGDBRemoteLog::DisableLog(const char **categories,
66                                      Stream *feedback_strm) {
67   Log *log(GetLog());
68   if (log) {
69     uint32_t flag_bits = 0;
70 
71     if (categories && categories[0]) {
72       flag_bits = log->GetMask().Get();
73       for (size_t i = 0; categories[i] != NULL; ++i) {
74         const char *arg = categories[i];
75 
76         if (::strcasecmp(arg, "all") == 0)
77           flag_bits &= ~GDBR_LOG_ALL;
78         else if (::strcasecmp(arg, "async") == 0)
79           flag_bits &= ~GDBR_LOG_ASYNC;
80         else if (::strncasecmp(arg, "break", 5) == 0)
81           flag_bits &= ~GDBR_LOG_BREAKPOINTS;
82         else if (::strncasecmp(arg, "comm", 4) == 0)
83           flag_bits &= ~GDBR_LOG_COMM;
84         else if (::strcasecmp(arg, "default") == 0)
85           flag_bits &= ~GDBR_LOG_DEFAULT;
86         else if (::strcasecmp(arg, "packets") == 0)
87           flag_bits &= ~GDBR_LOG_PACKETS;
88         else if (::strcasecmp(arg, "memory") == 0)
89           flag_bits &= ~GDBR_LOG_MEMORY;
90         else if (::strcasecmp(arg, "data-short") == 0)
91           flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
92         else if (::strcasecmp(arg, "data-long") == 0)
93           flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
94         else if (::strcasecmp(arg, "process") == 0)
95           flag_bits &= ~GDBR_LOG_PROCESS;
96         else if (::strcasecmp(arg, "step") == 0)
97           flag_bits &= ~GDBR_LOG_STEP;
98         else if (::strcasecmp(arg, "thread") == 0)
99           flag_bits &= ~GDBR_LOG_THREAD;
100         else if (::strcasecmp(arg, "verbose") == 0)
101           flag_bits &= ~GDBR_LOG_VERBOSE;
102         else if (::strncasecmp(arg, "watch", 5) == 0)
103           flag_bits &= ~GDBR_LOG_WATCHPOINTS;
104         else {
105           feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
106           ListLogCategories(feedback_strm);
107         }
108       }
109     }
110 
111     if (flag_bits == 0)
112       g_log_enabled = false;
113     else
114       log->GetMask().Reset(flag_bits);
115   }
116 
117   return;
118 }
119 
120 Log *ProcessGDBRemoteLog::EnableLog(StreamSP &log_stream_sp,
121                                     uint32_t log_options,
122                                     const char **categories,
123                                     Stream *feedback_strm) {
124   // Try see if there already is a log - that way we can reuse its settings.
125   // We could reuse the log in toto, but we don't know that the stream is the
126   // same.
127   uint32_t flag_bits = 0;
128   if (g_log)
129     flag_bits = g_log->GetMask().Get();
130 
131   // Now make a new log with this stream if one was provided
132   if (log_stream_sp) {
133     if (g_log)
134       g_log->SetStream(log_stream_sp);
135     else
136       g_log = new Log(log_stream_sp);
137   }
138 
139   if (g_log) {
140     bool got_unknown_category = false;
141     for (size_t i = 0; categories[i] != NULL; ++i) {
142       const char *arg = categories[i];
143 
144       if (::strcasecmp(arg, "all") == 0)
145         flag_bits |= GDBR_LOG_ALL;
146       else if (::strcasecmp(arg, "async") == 0)
147         flag_bits |= GDBR_LOG_ASYNC;
148       else if (::strncasecmp(arg, "break", 5) == 0)
149         flag_bits |= GDBR_LOG_BREAKPOINTS;
150       else if (::strncasecmp(arg, "comm", 4) == 0)
151         flag_bits |= GDBR_LOG_COMM;
152       else if (::strcasecmp(arg, "default") == 0)
153         flag_bits |= GDBR_LOG_DEFAULT;
154       else if (::strcasecmp(arg, "packets") == 0)
155         flag_bits |= GDBR_LOG_PACKETS;
156       else if (::strcasecmp(arg, "memory") == 0)
157         flag_bits |= GDBR_LOG_MEMORY;
158       else if (::strcasecmp(arg, "data-short") == 0)
159         flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
160       else if (::strcasecmp(arg, "data-long") == 0)
161         flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
162       else if (::strcasecmp(arg, "process") == 0)
163         flag_bits |= GDBR_LOG_PROCESS;
164       else if (::strcasecmp(arg, "step") == 0)
165         flag_bits |= GDBR_LOG_STEP;
166       else if (::strcasecmp(arg, "thread") == 0)
167         flag_bits |= GDBR_LOG_THREAD;
168       else if (::strcasecmp(arg, "verbose") == 0)
169         flag_bits |= GDBR_LOG_VERBOSE;
170       else if (::strncasecmp(arg, "watch", 5) == 0)
171         flag_bits |= GDBR_LOG_WATCHPOINTS;
172       else {
173         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
174         if (got_unknown_category == false) {
175           got_unknown_category = true;
176           ListLogCategories(feedback_strm);
177         }
178       }
179     }
180     if (flag_bits == 0)
181       flag_bits = GDBR_LOG_DEFAULT;
182     g_log->GetMask().Reset(flag_bits);
183     g_log->GetOptions().Reset(log_options);
184   }
185   g_log_enabled = true;
186   return g_log;
187 }
188 
189 void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) {
190   strm->Printf(
191       "Logging categories for '%s':\n"
192       "  all - turn on all available logging categories\n"
193       "  async - log asynchronous activity\n"
194       "  break - log breakpoints\n"
195       "  communication - log communication activity\n"
196       "  default - enable the default set of logging categories for liblldb\n"
197       "  packets - log gdb remote packets\n"
198       "  memory - log memory reads and writes\n"
199       "  data-short - log memory bytes for memory reads and writes for short "
200       "transactions only\n"
201       "  data-long - log memory bytes for memory reads and writes for all "
202       "transactions\n"
203       "  process - log process events and activities\n"
204       "  thread - log thread events and activities\n"
205       "  step - log step related activities\n"
206       "  verbose - enable verbose logging\n"
207       "  watch - log watchpoint related activities\n",
208       ProcessGDBRemote::GetPluginNameStatic().GetCString());
209 }
210 
211 void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) {
212   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask));
213   if (log) {
214     va_list args;
215     va_start(args, format);
216     log->VAPrintf(format, args);
217     va_end(args);
218   }
219 }
220