1 //===-- ProcessPOSIXLog.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 "ProcessPOSIXLog.h"
11
12 #include <mutex>
13
14 #include "lldb/Interpreter/Args.h"
15 #include "lldb/Core/StreamFile.h"
16
17 #include "ProcessPOSIXLog.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_log_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 *
GetLog()30 GetLog ()
31 {
32 if (!g_log_enabled)
33 return NULL;
34 return g_log;
35 }
36
37 void
Initialize(ConstString name)38 ProcessPOSIXLog::Initialize(ConstString name)
39 {
40 static std::once_flag g_once_flag;
41
42 std::call_once(g_once_flag, [name](){
43 Log::Callbacks log_callbacks = {
44 DisableLog,
45 EnableLog,
46 ListLogCategories
47 };
48
49 Log::RegisterLogChannel (name, log_callbacks);
50 RegisterPluginName(name);
51 });
52 }
53
54 Log *
GetLogIfAllCategoriesSet(uint32_t mask)55 ProcessPOSIXLog::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 static uint32_t
GetFlagBits(const char * arg)68 GetFlagBits (const char *arg)
69 {
70 if (::strcasecmp (arg, "all") == 0 ) return POSIX_LOG_ALL;
71 else if (::strcasecmp (arg, "async") == 0 ) return POSIX_LOG_ASYNC;
72 else if (::strncasecmp (arg, "break", 5) == 0 ) return POSIX_LOG_BREAKPOINTS;
73 else if (::strncasecmp (arg, "comm", 4) == 0 ) return POSIX_LOG_COMM;
74 else if (::strcasecmp (arg, "default") == 0 ) return POSIX_LOG_DEFAULT;
75 else if (::strcasecmp (arg, "packets") == 0 ) return POSIX_LOG_PACKETS;
76 else if (::strcasecmp (arg, "memory") == 0 ) return POSIX_LOG_MEMORY;
77 else if (::strcasecmp (arg, "data-short") == 0 ) return POSIX_LOG_MEMORY_DATA_SHORT;
78 else if (::strcasecmp (arg, "data-long") == 0 ) return POSIX_LOG_MEMORY_DATA_LONG;
79 else if (::strcasecmp (arg, "process") == 0 ) return POSIX_LOG_PROCESS;
80 else if (::strcasecmp (arg, "ptrace") == 0 ) return POSIX_LOG_PTRACE;
81 else if (::strcasecmp (arg, "registers") == 0 ) return POSIX_LOG_REGISTERS;
82 else if (::strcasecmp (arg, "step") == 0 ) return POSIX_LOG_STEP;
83 else if (::strcasecmp (arg, "thread") == 0 ) return POSIX_LOG_THREAD;
84 else if (::strcasecmp (arg, "verbose") == 0 ) return POSIX_LOG_VERBOSE;
85 else if (::strncasecmp (arg, "watch", 5) == 0 ) return POSIX_LOG_WATCHPOINTS;
86 return 0;
87 }
88
89 void
DisableLog(const char ** args,Stream * feedback_strm)90 ProcessPOSIXLog::DisableLog (const char **args, Stream *feedback_strm)
91 {
92 Log *log (GetLog ());
93 if (log)
94 {
95 uint32_t flag_bits = 0;
96
97 flag_bits = log->GetMask().Get();
98 for (; args[0]; args++)
99 {
100 const char *arg = args[0];
101 uint32_t bits = GetFlagBits(arg);
102
103 if (bits)
104 {
105 flag_bits &= ~bits;
106 }
107 else
108 {
109 feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
110 ListLogCategories (feedback_strm);
111 }
112 }
113
114 log->GetMask().Reset (flag_bits);
115 if (flag_bits == 0)
116 g_log_enabled = false;
117 }
118
119 return;
120 }
121
122 Log *
EnableLog(StreamSP & log_stream_sp,uint32_t log_options,const char ** args,Stream * feedback_strm)123 ProcessPOSIXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
124 {
125 // Try see if there already is a log - that way we can reuse its settings.
126 // We could reuse the log in toto, but we don't know that the stream is the 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 {
134 if (g_log)
135 g_log->SetStream(log_stream_sp);
136 else
137 g_log = new Log(log_stream_sp);
138 }
139
140 if (g_log)
141 {
142 bool got_unknown_category = false;
143 for (; args[0]; args++)
144 {
145 const char *arg = args[0];
146 uint32_t bits = GetFlagBits(arg);
147
148 if (bits)
149 {
150 flag_bits |= bits;
151 }
152 else
153 {
154 feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
155 if (got_unknown_category == false)
156 {
157 got_unknown_category = true;
158 ListLogCategories (feedback_strm);
159 }
160 }
161 }
162 if (flag_bits == 0)
163 flag_bits = POSIX_LOG_DEFAULT;
164 g_log->GetMask().Reset(flag_bits);
165 g_log->GetOptions().Reset(log_options);
166 g_log_enabled = true;
167 }
168 return g_log;
169 }
170
171 void
ListLogCategories(Stream * strm)172 ProcessPOSIXLog::ListLogCategories (Stream *strm)
173 {
174 strm->Printf ("Logging categories for '%s':\n"
175 " all - turn on all available logging categories\n"
176 " async - log asynchronous activity\n"
177 " break - log breakpoints\n"
178 " communication - log communication activity\n"
179 " default - enable the default set of logging categories for liblldb\n"
180 " packets - log gdb remote packets\n"
181 " memory - log memory reads and writes\n"
182 " data-short - log memory bytes for memory reads and writes for short transactions only\n"
183 " data-long - log memory bytes for memory reads and writes for all transactions\n"
184 " process - log process events and activities\n"
185 #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
186 " ptrace - log all calls to ptrace\n"
187 #endif
188 " registers - log register read/writes\n"
189 " thread - log thread events and activities\n"
190 " step - log step related activities\n"
191 " verbose - enable verbose logging\n"
192 " watch - log watchpoint related activities\n", ProcessPOSIXLog::m_pluginname);
193 }
194
195
196 void
LogIf(uint32_t mask,const char * format,...)197 ProcessPOSIXLog::LogIf (uint32_t mask, const char *format, ...)
198 {
199 Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (mask));
200 if (log)
201 {
202 va_list args;
203 va_start (args, format);
204 log->VAPrintf (format, args);
205 va_end (args);
206 }
207 }
208
209 int ProcessPOSIXLog::m_nestinglevel;
210 const char *ProcessPOSIXLog::m_pluginname = "";
211