xref: /llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp (revision 5fae71c51cc8c3d51e86cd597ce91a254e9175f4)
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(
119     const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
120     uint32_t log_options, const char **categories, Stream *feedback_strm) {
121   // Try see if there already is a log - that way we can reuse its settings.
122   // We could reuse the log in toto, but we don't know that the stream is the
123   // same.
124   uint32_t flag_bits = 0;
125   if (g_log)
126     flag_bits = g_log->GetMask().Get();
127 
128   // Now make a new log with this stream if one was provided
129   if (log_stream_sp) {
130     if (g_log)
131       g_log->SetStream(log_stream_sp);
132     else
133       g_log = new Log(log_stream_sp);
134   }
135 
136   if (g_log) {
137     bool got_unknown_category = false;
138     for (size_t i = 0; categories[i] != NULL; ++i) {
139       const char *arg = categories[i];
140 
141       if (::strcasecmp(arg, "all") == 0)
142         flag_bits |= GDBR_LOG_ALL;
143       else if (::strcasecmp(arg, "async") == 0)
144         flag_bits |= GDBR_LOG_ASYNC;
145       else if (::strncasecmp(arg, "break", 5) == 0)
146         flag_bits |= GDBR_LOG_BREAKPOINTS;
147       else if (::strncasecmp(arg, "comm", 4) == 0)
148         flag_bits |= GDBR_LOG_COMM;
149       else if (::strcasecmp(arg, "default") == 0)
150         flag_bits |= GDBR_LOG_DEFAULT;
151       else if (::strcasecmp(arg, "packets") == 0)
152         flag_bits |= GDBR_LOG_PACKETS;
153       else if (::strcasecmp(arg, "memory") == 0)
154         flag_bits |= GDBR_LOG_MEMORY;
155       else if (::strcasecmp(arg, "data-short") == 0)
156         flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
157       else if (::strcasecmp(arg, "data-long") == 0)
158         flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
159       else if (::strcasecmp(arg, "process") == 0)
160         flag_bits |= GDBR_LOG_PROCESS;
161       else if (::strcasecmp(arg, "step") == 0)
162         flag_bits |= GDBR_LOG_STEP;
163       else if (::strcasecmp(arg, "thread") == 0)
164         flag_bits |= GDBR_LOG_THREAD;
165       else if (::strncasecmp(arg, "watch", 5) == 0)
166         flag_bits |= GDBR_LOG_WATCHPOINTS;
167       else {
168         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
169         if (got_unknown_category == false) {
170           got_unknown_category = true;
171           ListLogCategories(feedback_strm);
172         }
173       }
174     }
175     if (flag_bits == 0)
176       flag_bits = GDBR_LOG_DEFAULT;
177     g_log->GetMask().Reset(flag_bits);
178     g_log->GetOptions().Reset(log_options);
179   }
180   g_log_enabled = true;
181   return g_log;
182 }
183 
184 void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) {
185   strm->Printf(
186       "Logging categories for '%s':\n"
187       "  all - turn on all available logging categories\n"
188       "  async - log asynchronous activity\n"
189       "  break - log breakpoints\n"
190       "  communication - log communication activity\n"
191       "  default - enable the default set of logging categories for liblldb\n"
192       "  packets - log gdb remote packets\n"
193       "  memory - log memory reads and writes\n"
194       "  data-short - log memory bytes for memory reads and writes for short "
195       "transactions only\n"
196       "  data-long - log memory bytes for memory reads and writes for all "
197       "transactions\n"
198       "  process - log process events and activities\n"
199       "  thread - log thread events and activities\n"
200       "  step - log step related activities\n"
201       "  verbose - enable verbose logging\n"
202       "  watch - log watchpoint related activities\n",
203       ProcessGDBRemote::GetPluginNameStatic().GetCString());
204 }
205 
206 void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) {
207   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask));
208   if (log) {
209     va_list args;
210     va_start(args, format);
211     log->VAPrintf(format, args);
212     va_end(args);
213   }
214 }
215