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