xref: /llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp (revision e8a7b9841c583059115f5136fae3c85880773513)
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 (::strncasecmp(arg, "watch", 5) == 0)
101           flag_bits &= ~GDBR_LOG_WATCHPOINTS;
102         else {
103           feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
104           ListLogCategories(feedback_strm);
105         }
106       }
107     }
108 
109     if (flag_bits == 0)
110       g_log_enabled = false;
111     else
112       log->GetMask().Reset(flag_bits);
113   }
114 
115   return;
116 }
117 
118 Log *ProcessGDBRemoteLog::EnableLog(StreamSP &log_stream_sp,
119                                     uint32_t log_options,
120                                     const char **categories,
121                                     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 (size_t i = 0; categories[i] != NULL; ++i) {
140       const char *arg = categories[i];
141 
142       if (::strcasecmp(arg, "all") == 0)
143         flag_bits |= GDBR_LOG_ALL;
144       else if (::strcasecmp(arg, "async") == 0)
145         flag_bits |= GDBR_LOG_ASYNC;
146       else if (::strncasecmp(arg, "break", 5) == 0)
147         flag_bits |= GDBR_LOG_BREAKPOINTS;
148       else if (::strncasecmp(arg, "comm", 4) == 0)
149         flag_bits |= GDBR_LOG_COMM;
150       else if (::strcasecmp(arg, "default") == 0)
151         flag_bits |= GDBR_LOG_DEFAULT;
152       else if (::strcasecmp(arg, "packets") == 0)
153         flag_bits |= GDBR_LOG_PACKETS;
154       else if (::strcasecmp(arg, "memory") == 0)
155         flag_bits |= GDBR_LOG_MEMORY;
156       else if (::strcasecmp(arg, "data-short") == 0)
157         flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
158       else if (::strcasecmp(arg, "data-long") == 0)
159         flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
160       else if (::strcasecmp(arg, "process") == 0)
161         flag_bits |= GDBR_LOG_PROCESS;
162       else if (::strcasecmp(arg, "step") == 0)
163         flag_bits |= GDBR_LOG_STEP;
164       else if (::strcasecmp(arg, "thread") == 0)
165         flag_bits |= GDBR_LOG_THREAD;
166       else if (::strncasecmp(arg, "watch", 5) == 0)
167         flag_bits |= GDBR_LOG_WATCHPOINTS;
168       else {
169         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
170         if (got_unknown_category == false) {
171           got_unknown_category = true;
172           ListLogCategories(feedback_strm);
173         }
174       }
175     }
176     if (flag_bits == 0)
177       flag_bits = GDBR_LOG_DEFAULT;
178     g_log->GetMask().Reset(flag_bits);
179     g_log->GetOptions().Reset(log_options);
180   }
181   g_log_enabled = true;
182   return g_log;
183 }
184 
185 void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) {
186   strm->Printf(
187       "Logging categories for '%s':\n"
188       "  all - turn on all available logging categories\n"
189       "  async - log asynchronous activity\n"
190       "  break - log breakpoints\n"
191       "  communication - log communication activity\n"
192       "  default - enable the default set of logging categories for liblldb\n"
193       "  packets - log gdb remote packets\n"
194       "  memory - log memory reads and writes\n"
195       "  data-short - log memory bytes for memory reads and writes for short "
196       "transactions only\n"
197       "  data-long - log memory bytes for memory reads and writes for all "
198       "transactions\n"
199       "  process - log process events and activities\n"
200       "  thread - log thread events and activities\n"
201       "  step - log step related activities\n"
202       "  verbose - enable verbose logging\n"
203       "  watch - log watchpoint related activities\n",
204       ProcessGDBRemote::GetPluginNameStatic().GetCString());
205 }
206 
207 void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) {
208   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask));
209   if (log) {
210     va_list args;
211     va_start(args, format);
212     log->VAPrintf(format, args);
213     va_end(args);
214   }
215 }
216