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