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