1b9c1b51eSKate Stone //===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ 2b9c1b51eSKate Stone //-*-===// 39ed5b49cSJohnny Chen // 49ed5b49cSJohnny Chen // The LLVM Compiler Infrastructure 59ed5b49cSJohnny Chen // 69ed5b49cSJohnny Chen // This file is distributed under the University of Illinois Open Source 79ed5b49cSJohnny Chen // License. See LICENSE.TXT for details. 89ed5b49cSJohnny Chen // 99ed5b49cSJohnny Chen //===----------------------------------------------------------------------===// 109ed5b49cSJohnny Chen 119ed5b49cSJohnny Chen #include "ProcessPOSIXLog.h" 129ed5b49cSJohnny Chen 135f4b6c7cSRobert Flack #include <mutex> 145f4b6c7cSRobert Flack 159ed5b49cSJohnny Chen #include "lldb/Core/StreamFile.h" 16b9c1b51eSKate Stone #include "lldb/Interpreter/Args.h" 179ed5b49cSJohnny Chen 18*c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h" 19*c5f28e2aSKamil Rytarowski 209ed5b49cSJohnny Chen #include "ProcessPOSIXLog.h" 219ed5b49cSJohnny Chen 229ed5b49cSJohnny Chen using namespace lldb; 239ed5b49cSJohnny Chen using namespace lldb_private; 249ed5b49cSJohnny Chen 259ed5b49cSJohnny Chen // We want to avoid global constructors where code needs to be run so here we 269ed5b49cSJohnny Chen // control access to our static g_log_sp by hiding it in a singleton function 2701186359SAshok Thirumurthi // that will construct the static g_log_sp the first time this function is 289ed5b49cSJohnny Chen // called. 2901186359SAshok Thirumurthi static bool g_log_enabled = false; 3001186359SAshok Thirumurthi static Log *g_log = NULL; 31b9c1b51eSKate Stone static Log *GetLog() { 3201186359SAshok Thirumurthi if (!g_log_enabled) 3301186359SAshok Thirumurthi return NULL; 3401186359SAshok Thirumurthi return g_log; 359ed5b49cSJohnny Chen } 369ed5b49cSJohnny Chen 37b9c1b51eSKate Stone void ProcessPOSIXLog::Initialize(ConstString name) { 38*c5f28e2aSKamil Rytarowski static llvm::once_flag g_once_flag; 395f4b6c7cSRobert Flack 40*c5f28e2aSKamil Rytarowski llvm::call_once(g_once_flag, [name]() { 41b9c1b51eSKate Stone Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories}; 425f4b6c7cSRobert Flack 435f4b6c7cSRobert Flack Log::RegisterLogChannel(name, log_callbacks); 445f4b6c7cSRobert Flack RegisterPluginName(name); 455f4b6c7cSRobert Flack }); 465f4b6c7cSRobert Flack } 4701186359SAshok Thirumurthi 48b9c1b51eSKate Stone Log *ProcessPOSIXLog::GetLogIfAllCategoriesSet(uint32_t mask) { 4901186359SAshok Thirumurthi Log *log(GetLog()); 50b9c1b51eSKate Stone if (log && mask) { 519ed5b49cSJohnny Chen uint32_t log_mask = log->GetMask().Get(); 529ed5b49cSJohnny Chen if ((log_mask & mask) != mask) 5301186359SAshok Thirumurthi return NULL; 549ed5b49cSJohnny Chen } 559ed5b49cSJohnny Chen return log; 569ed5b49cSJohnny Chen } 579ed5b49cSJohnny Chen 58b9c1b51eSKate Stone static uint32_t GetFlagBits(const char *arg) { 59b9c1b51eSKate Stone if (::strcasecmp(arg, "all") == 0) 60b9c1b51eSKate Stone return POSIX_LOG_ALL; 61b9c1b51eSKate Stone else if (::strcasecmp(arg, "async") == 0) 62b9c1b51eSKate Stone return POSIX_LOG_ASYNC; 63b9c1b51eSKate Stone else if (::strncasecmp(arg, "break", 5) == 0) 64b9c1b51eSKate Stone return POSIX_LOG_BREAKPOINTS; 65b9c1b51eSKate Stone else if (::strncasecmp(arg, "comm", 4) == 0) 66b9c1b51eSKate Stone return POSIX_LOG_COMM; 67b9c1b51eSKate Stone else if (::strcasecmp(arg, "default") == 0) 68b9c1b51eSKate Stone return POSIX_LOG_DEFAULT; 69b9c1b51eSKate Stone else if (::strcasecmp(arg, "packets") == 0) 70b9c1b51eSKate Stone return POSIX_LOG_PACKETS; 71b9c1b51eSKate Stone else if (::strcasecmp(arg, "memory") == 0) 72b9c1b51eSKate Stone return POSIX_LOG_MEMORY; 73b9c1b51eSKate Stone else if (::strcasecmp(arg, "data-short") == 0) 74b9c1b51eSKate Stone return POSIX_LOG_MEMORY_DATA_SHORT; 75b9c1b51eSKate Stone else if (::strcasecmp(arg, "data-long") == 0) 76b9c1b51eSKate Stone return POSIX_LOG_MEMORY_DATA_LONG; 77b9c1b51eSKate Stone else if (::strcasecmp(arg, "process") == 0) 78b9c1b51eSKate Stone return POSIX_LOG_PROCESS; 79b9c1b51eSKate Stone else if (::strcasecmp(arg, "ptrace") == 0) 80b9c1b51eSKate Stone return POSIX_LOG_PTRACE; 81b9c1b51eSKate Stone else if (::strcasecmp(arg, "registers") == 0) 82b9c1b51eSKate Stone return POSIX_LOG_REGISTERS; 83b9c1b51eSKate Stone else if (::strcasecmp(arg, "step") == 0) 84b9c1b51eSKate Stone return POSIX_LOG_STEP; 85b9c1b51eSKate Stone else if (::strcasecmp(arg, "thread") == 0) 86b9c1b51eSKate Stone return POSIX_LOG_THREAD; 87b9c1b51eSKate Stone else if (::strcasecmp(arg, "verbose") == 0) 88b9c1b51eSKate Stone return POSIX_LOG_VERBOSE; 89b9c1b51eSKate Stone else if (::strncasecmp(arg, "watch", 5) == 0) 90b9c1b51eSKate Stone return POSIX_LOG_WATCHPOINTS; 9176ad5d75SEd Maste return 0; 9276ad5d75SEd Maste } 9376ad5d75SEd Maste 94b9c1b51eSKate Stone void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) { 9501186359SAshok Thirumurthi Log *log(GetLog()); 96b9c1b51eSKate Stone if (log) { 979ed5b49cSJohnny Chen uint32_t flag_bits = 0; 989ed5b49cSJohnny Chen 999ed5b49cSJohnny Chen flag_bits = log->GetMask().Get(); 1004fd57542SPavel Labath for (; args && args[0]; args++) { 1010c90ef47SGreg Clayton const char *arg = args[0]; 10276ad5d75SEd Maste uint32_t bits = GetFlagBits(arg); 1039ed5b49cSJohnny Chen 104b9c1b51eSKate Stone if (bits) { 10576ad5d75SEd Maste flag_bits &= ~bits; 106b9c1b51eSKate Stone } else { 1079ed5b49cSJohnny Chen feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); 1089ed5b49cSJohnny Chen ListLogCategories(feedback_strm); 1099ed5b49cSJohnny Chen } 1109ed5b49cSJohnny Chen } 1119ed5b49cSJohnny Chen 1129ed5b49cSJohnny Chen log->GetMask().Reset(flag_bits); 11301186359SAshok Thirumurthi if (flag_bits == 0) 11401186359SAshok Thirumurthi g_log_enabled = false; 1159ed5b49cSJohnny Chen } 1169ed5b49cSJohnny Chen 1179ed5b49cSJohnny Chen return; 1189ed5b49cSJohnny Chen } 1199ed5b49cSJohnny Chen 120b9c1b51eSKate Stone Log *ProcessPOSIXLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options, 121b9c1b51eSKate Stone const char **args, Stream *feedback_strm) { 1229ed5b49cSJohnny Chen // Try see if there already is a log - that way we can reuse its settings. 123b9c1b51eSKate Stone // We could reuse the log in toto, but we don't know that the stream is the 124b9c1b51eSKate Stone // same. 1259ed5b49cSJohnny Chen uint32_t flag_bits = 0; 12601186359SAshok Thirumurthi if (g_log) 12701186359SAshok Thirumurthi flag_bits = g_log->GetMask().Get(); 1289ed5b49cSJohnny Chen 1299ed5b49cSJohnny Chen // Now make a new log with this stream if one was provided 130b9c1b51eSKate Stone if (log_stream_sp) { 13101186359SAshok Thirumurthi if (g_log) 13201186359SAshok Thirumurthi g_log->SetStream(log_stream_sp); 13301186359SAshok Thirumurthi else 13401186359SAshok Thirumurthi g_log = new Log(log_stream_sp); 1359ed5b49cSJohnny Chen } 1369ed5b49cSJohnny Chen 137b9c1b51eSKate Stone if (g_log) { 1389ed5b49cSJohnny Chen bool got_unknown_category = false; 1394fd57542SPavel Labath for (; args && args[0]; args++) { 1400c90ef47SGreg Clayton const char *arg = args[0]; 14176ad5d75SEd Maste uint32_t bits = GetFlagBits(arg); 1429ed5b49cSJohnny Chen 143b9c1b51eSKate Stone if (bits) { 14476ad5d75SEd Maste flag_bits |= bits; 145b9c1b51eSKate Stone } else { 1469ed5b49cSJohnny Chen feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); 147b9c1b51eSKate Stone if (got_unknown_category == false) { 1489ed5b49cSJohnny Chen got_unknown_category = true; 1499ed5b49cSJohnny Chen ListLogCategories(feedback_strm); 1509ed5b49cSJohnny Chen } 1519ed5b49cSJohnny Chen } 1529ed5b49cSJohnny Chen } 1539ed5b49cSJohnny Chen if (flag_bits == 0) 1549ed5b49cSJohnny Chen flag_bits = POSIX_LOG_DEFAULT; 15501186359SAshok Thirumurthi g_log->GetMask().Reset(flag_bits); 15601186359SAshok Thirumurthi g_log->GetOptions().Reset(log_options); 15701186359SAshok Thirumurthi g_log_enabled = true; 1589ed5b49cSJohnny Chen } 15901186359SAshok Thirumurthi return g_log; 1609ed5b49cSJohnny Chen } 1619ed5b49cSJohnny Chen 162b9c1b51eSKate Stone void ProcessPOSIXLog::ListLogCategories(Stream *strm) { 163b9c1b51eSKate Stone strm->Printf( 164b9c1b51eSKate Stone "Logging categories for '%s':\n" 1659ed5b49cSJohnny Chen " all - turn on all available logging categories\n" 1669ed5b49cSJohnny Chen " async - log asynchronous activity\n" 1679ed5b49cSJohnny Chen " break - log breakpoints\n" 1689ed5b49cSJohnny Chen " communication - log communication activity\n" 1699ed5b49cSJohnny Chen " default - enable the default set of logging categories for liblldb\n" 1709ed5b49cSJohnny Chen " packets - log gdb remote packets\n" 1719ed5b49cSJohnny Chen " memory - log memory reads and writes\n" 172b9c1b51eSKate Stone " data-short - log memory bytes for memory reads and writes for short " 173b9c1b51eSKate Stone "transactions only\n" 174b9c1b51eSKate Stone " data-long - log memory bytes for memory reads and writes for all " 175b9c1b51eSKate Stone "transactions\n" 1769ed5b49cSJohnny Chen " process - log process events and activities\n" 1779ed5b49cSJohnny Chen #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION 1789ed5b49cSJohnny Chen " ptrace - log all calls to ptrace\n" 1799ed5b49cSJohnny Chen #endif 1809ed5b49cSJohnny Chen " registers - log register read/writes\n" 1819ed5b49cSJohnny Chen " thread - log thread events and activities\n" 1829ed5b49cSJohnny Chen " step - log step related activities\n" 1839ed5b49cSJohnny Chen " verbose - enable verbose logging\n" 184b9c1b51eSKate Stone " watch - log watchpoint related activities\n", 185b9c1b51eSKate Stone ProcessPOSIXLog::m_pluginname); 1869ed5b49cSJohnny Chen } 1879ed5b49cSJohnny Chen 188b9c1b51eSKate Stone void ProcessPOSIXLog::LogIf(uint32_t mask, const char *format, ...) { 18901186359SAshok Thirumurthi Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(mask)); 190b9c1b51eSKate Stone if (log) { 1919ed5b49cSJohnny Chen va_list args; 1929ed5b49cSJohnny Chen va_start(args, format); 1939ed5b49cSJohnny Chen log->VAPrintf(format, args); 1949ed5b49cSJohnny Chen va_end(args); 1959ed5b49cSJohnny Chen } 1969ed5b49cSJohnny Chen } 1979ed5b49cSJohnny Chen 1989ed5b49cSJohnny Chen int ProcessPOSIXLog::m_nestinglevel; 1999ed5b49cSJohnny Chen const char *ProcessPOSIXLog::m_pluginname = ""; 200