1*b9c1b51eSKate Stone //===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ 2*b9c1b51eSKate 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" 16*b9c1b51eSKate Stone #include "lldb/Interpreter/Args.h" 179ed5b49cSJohnny Chen 189ed5b49cSJohnny Chen #include "ProcessPOSIXLog.h" 199ed5b49cSJohnny Chen 209ed5b49cSJohnny Chen using namespace lldb; 219ed5b49cSJohnny Chen using namespace lldb_private; 229ed5b49cSJohnny Chen 239ed5b49cSJohnny Chen // We want to avoid global constructors where code needs to be run so here we 249ed5b49cSJohnny Chen // control access to our static g_log_sp by hiding it in a singleton function 2501186359SAshok Thirumurthi // that will construct the static g_log_sp the first time this function is 269ed5b49cSJohnny Chen // called. 2701186359SAshok Thirumurthi static bool g_log_enabled = false; 2801186359SAshok Thirumurthi static Log *g_log = NULL; 29*b9c1b51eSKate Stone static Log *GetLog() { 3001186359SAshok Thirumurthi if (!g_log_enabled) 3101186359SAshok Thirumurthi return NULL; 3201186359SAshok Thirumurthi return g_log; 339ed5b49cSJohnny Chen } 349ed5b49cSJohnny Chen 35*b9c1b51eSKate Stone void ProcessPOSIXLog::Initialize(ConstString name) { 365f4b6c7cSRobert Flack static std::once_flag g_once_flag; 375f4b6c7cSRobert Flack 385f4b6c7cSRobert Flack std::call_once(g_once_flag, [name]() { 39*b9c1b51eSKate Stone Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories}; 405f4b6c7cSRobert Flack 415f4b6c7cSRobert Flack Log::RegisterLogChannel(name, log_callbacks); 425f4b6c7cSRobert Flack RegisterPluginName(name); 435f4b6c7cSRobert Flack }); 445f4b6c7cSRobert Flack } 4501186359SAshok Thirumurthi 46*b9c1b51eSKate Stone Log *ProcessPOSIXLog::GetLogIfAllCategoriesSet(uint32_t mask) { 4701186359SAshok Thirumurthi Log *log(GetLog()); 48*b9c1b51eSKate Stone if (log && mask) { 499ed5b49cSJohnny Chen uint32_t log_mask = log->GetMask().Get(); 509ed5b49cSJohnny Chen if ((log_mask & mask) != mask) 5101186359SAshok Thirumurthi return NULL; 529ed5b49cSJohnny Chen } 539ed5b49cSJohnny Chen return log; 549ed5b49cSJohnny Chen } 559ed5b49cSJohnny Chen 56*b9c1b51eSKate Stone static uint32_t GetFlagBits(const char *arg) { 57*b9c1b51eSKate Stone if (::strcasecmp(arg, "all") == 0) 58*b9c1b51eSKate Stone return POSIX_LOG_ALL; 59*b9c1b51eSKate Stone else if (::strcasecmp(arg, "async") == 0) 60*b9c1b51eSKate Stone return POSIX_LOG_ASYNC; 61*b9c1b51eSKate Stone else if (::strncasecmp(arg, "break", 5) == 0) 62*b9c1b51eSKate Stone return POSIX_LOG_BREAKPOINTS; 63*b9c1b51eSKate Stone else if (::strncasecmp(arg, "comm", 4) == 0) 64*b9c1b51eSKate Stone return POSIX_LOG_COMM; 65*b9c1b51eSKate Stone else if (::strcasecmp(arg, "default") == 0) 66*b9c1b51eSKate Stone return POSIX_LOG_DEFAULT; 67*b9c1b51eSKate Stone else if (::strcasecmp(arg, "packets") == 0) 68*b9c1b51eSKate Stone return POSIX_LOG_PACKETS; 69*b9c1b51eSKate Stone else if (::strcasecmp(arg, "memory") == 0) 70*b9c1b51eSKate Stone return POSIX_LOG_MEMORY; 71*b9c1b51eSKate Stone else if (::strcasecmp(arg, "data-short") == 0) 72*b9c1b51eSKate Stone return POSIX_LOG_MEMORY_DATA_SHORT; 73*b9c1b51eSKate Stone else if (::strcasecmp(arg, "data-long") == 0) 74*b9c1b51eSKate Stone return POSIX_LOG_MEMORY_DATA_LONG; 75*b9c1b51eSKate Stone else if (::strcasecmp(arg, "process") == 0) 76*b9c1b51eSKate Stone return POSIX_LOG_PROCESS; 77*b9c1b51eSKate Stone else if (::strcasecmp(arg, "ptrace") == 0) 78*b9c1b51eSKate Stone return POSIX_LOG_PTRACE; 79*b9c1b51eSKate Stone else if (::strcasecmp(arg, "registers") == 0) 80*b9c1b51eSKate Stone return POSIX_LOG_REGISTERS; 81*b9c1b51eSKate Stone else if (::strcasecmp(arg, "step") == 0) 82*b9c1b51eSKate Stone return POSIX_LOG_STEP; 83*b9c1b51eSKate Stone else if (::strcasecmp(arg, "thread") == 0) 84*b9c1b51eSKate Stone return POSIX_LOG_THREAD; 85*b9c1b51eSKate Stone else if (::strcasecmp(arg, "verbose") == 0) 86*b9c1b51eSKate Stone return POSIX_LOG_VERBOSE; 87*b9c1b51eSKate Stone else if (::strncasecmp(arg, "watch", 5) == 0) 88*b9c1b51eSKate Stone return POSIX_LOG_WATCHPOINTS; 8976ad5d75SEd Maste return 0; 9076ad5d75SEd Maste } 9176ad5d75SEd Maste 92*b9c1b51eSKate Stone void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) { 9301186359SAshok Thirumurthi Log *log(GetLog()); 94*b9c1b51eSKate Stone if (log) { 959ed5b49cSJohnny Chen uint32_t flag_bits = 0; 969ed5b49cSJohnny Chen 979ed5b49cSJohnny Chen flag_bits = log->GetMask().Get(); 98*b9c1b51eSKate Stone for (; args[0]; args++) { 990c90ef47SGreg Clayton const char *arg = args[0]; 10076ad5d75SEd Maste uint32_t bits = GetFlagBits(arg); 1019ed5b49cSJohnny Chen 102*b9c1b51eSKate Stone if (bits) { 10376ad5d75SEd Maste flag_bits &= ~bits; 104*b9c1b51eSKate Stone } else { 1059ed5b49cSJohnny Chen feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); 1069ed5b49cSJohnny Chen ListLogCategories(feedback_strm); 1079ed5b49cSJohnny Chen } 1089ed5b49cSJohnny Chen } 1099ed5b49cSJohnny Chen 1109ed5b49cSJohnny Chen log->GetMask().Reset(flag_bits); 11101186359SAshok Thirumurthi if (flag_bits == 0) 11201186359SAshok Thirumurthi g_log_enabled = false; 1139ed5b49cSJohnny Chen } 1149ed5b49cSJohnny Chen 1159ed5b49cSJohnny Chen return; 1169ed5b49cSJohnny Chen } 1179ed5b49cSJohnny Chen 118*b9c1b51eSKate Stone Log *ProcessPOSIXLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options, 119*b9c1b51eSKate Stone const char **args, Stream *feedback_strm) { 1209ed5b49cSJohnny Chen // Try see if there already is a log - that way we can reuse its settings. 121*b9c1b51eSKate Stone // We could reuse the log in toto, but we don't know that the stream is the 122*b9c1b51eSKate Stone // same. 1239ed5b49cSJohnny Chen uint32_t flag_bits = 0; 12401186359SAshok Thirumurthi if (g_log) 12501186359SAshok Thirumurthi flag_bits = g_log->GetMask().Get(); 1269ed5b49cSJohnny Chen 1279ed5b49cSJohnny Chen // Now make a new log with this stream if one was provided 128*b9c1b51eSKate Stone if (log_stream_sp) { 12901186359SAshok Thirumurthi if (g_log) 13001186359SAshok Thirumurthi g_log->SetStream(log_stream_sp); 13101186359SAshok Thirumurthi else 13201186359SAshok Thirumurthi g_log = new Log(log_stream_sp); 1339ed5b49cSJohnny Chen } 1349ed5b49cSJohnny Chen 135*b9c1b51eSKate Stone if (g_log) { 1369ed5b49cSJohnny Chen bool got_unknown_category = false; 137*b9c1b51eSKate Stone for (; args[0]; args++) { 1380c90ef47SGreg Clayton const char *arg = args[0]; 13976ad5d75SEd Maste uint32_t bits = GetFlagBits(arg); 1409ed5b49cSJohnny Chen 141*b9c1b51eSKate Stone if (bits) { 14276ad5d75SEd Maste flag_bits |= bits; 143*b9c1b51eSKate Stone } else { 1449ed5b49cSJohnny Chen feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); 145*b9c1b51eSKate Stone if (got_unknown_category == false) { 1469ed5b49cSJohnny Chen got_unknown_category = true; 1479ed5b49cSJohnny Chen ListLogCategories(feedback_strm); 1489ed5b49cSJohnny Chen } 1499ed5b49cSJohnny Chen } 1509ed5b49cSJohnny Chen } 1519ed5b49cSJohnny Chen if (flag_bits == 0) 1529ed5b49cSJohnny Chen flag_bits = POSIX_LOG_DEFAULT; 15301186359SAshok Thirumurthi g_log->GetMask().Reset(flag_bits); 15401186359SAshok Thirumurthi g_log->GetOptions().Reset(log_options); 15501186359SAshok Thirumurthi g_log_enabled = true; 1569ed5b49cSJohnny Chen } 15701186359SAshok Thirumurthi return g_log; 1589ed5b49cSJohnny Chen } 1599ed5b49cSJohnny Chen 160*b9c1b51eSKate Stone void ProcessPOSIXLog::ListLogCategories(Stream *strm) { 161*b9c1b51eSKate Stone strm->Printf( 162*b9c1b51eSKate Stone "Logging categories for '%s':\n" 1639ed5b49cSJohnny Chen " all - turn on all available logging categories\n" 1649ed5b49cSJohnny Chen " async - log asynchronous activity\n" 1659ed5b49cSJohnny Chen " break - log breakpoints\n" 1669ed5b49cSJohnny Chen " communication - log communication activity\n" 1679ed5b49cSJohnny Chen " default - enable the default set of logging categories for liblldb\n" 1689ed5b49cSJohnny Chen " packets - log gdb remote packets\n" 1699ed5b49cSJohnny Chen " memory - log memory reads and writes\n" 170*b9c1b51eSKate Stone " data-short - log memory bytes for memory reads and writes for short " 171*b9c1b51eSKate Stone "transactions only\n" 172*b9c1b51eSKate Stone " data-long - log memory bytes for memory reads and writes for all " 173*b9c1b51eSKate Stone "transactions\n" 1749ed5b49cSJohnny Chen " process - log process events and activities\n" 1759ed5b49cSJohnny Chen #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION 1769ed5b49cSJohnny Chen " ptrace - log all calls to ptrace\n" 1779ed5b49cSJohnny Chen #endif 1789ed5b49cSJohnny Chen " registers - log register read/writes\n" 1799ed5b49cSJohnny Chen " thread - log thread events and activities\n" 1809ed5b49cSJohnny Chen " step - log step related activities\n" 1819ed5b49cSJohnny Chen " verbose - enable verbose logging\n" 182*b9c1b51eSKate Stone " watch - log watchpoint related activities\n", 183*b9c1b51eSKate Stone ProcessPOSIXLog::m_pluginname); 1849ed5b49cSJohnny Chen } 1859ed5b49cSJohnny Chen 186*b9c1b51eSKate Stone void ProcessPOSIXLog::LogIf(uint32_t mask, const char *format, ...) { 18701186359SAshok Thirumurthi Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(mask)); 188*b9c1b51eSKate Stone if (log) { 1899ed5b49cSJohnny Chen va_list args; 1909ed5b49cSJohnny Chen va_start(args, format); 1919ed5b49cSJohnny Chen log->VAPrintf(format, args); 1929ed5b49cSJohnny Chen va_end(args); 1939ed5b49cSJohnny Chen } 1949ed5b49cSJohnny Chen } 1959ed5b49cSJohnny Chen 1969ed5b49cSJohnny Chen int ProcessPOSIXLog::m_nestinglevel; 1979ed5b49cSJohnny Chen const char *ProcessPOSIXLog::m_pluginname = ""; 198