1 //===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "ProcessPOSIXLog.h"
12 
13 #include <mutex>
14 
15 #include "lldb/Core/StreamFile.h"
16 #include "lldb/Interpreter/Args.h"
17 
18 #include "llvm/Support/Threading.h"
19 
20 #include "ProcessPOSIXLog.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 // We want to avoid global constructors where code needs to be run so here we
26 // control access to our static g_log_sp by hiding it in a singleton function
27 // that will construct the static g_log_sp the first time this function is
28 // called.
29 static bool g_log_enabled = false;
30 static Log *g_log = NULL;
31 static Log *GetLog() {
32   if (!g_log_enabled)
33     return NULL;
34   return g_log;
35 }
36 
37 void ProcessPOSIXLog::Initialize(ConstString name) {
38   static llvm::once_flag g_once_flag;
39 
40   llvm::call_once(g_once_flag, [name]() {
41     Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
42 
43     Log::RegisterLogChannel(name, log_callbacks);
44     RegisterPluginName(name);
45   });
46 }
47 
48 Log *ProcessPOSIXLog::GetLogIfAllCategoriesSet(uint32_t mask) {
49   Log *log(GetLog());
50   if (log && mask) {
51     uint32_t log_mask = log->GetMask().Get();
52     if ((log_mask & mask) != mask)
53       return NULL;
54   }
55   return log;
56 }
57 
58 static uint32_t GetFlagBits(const char *arg) {
59   if (::strcasecmp(arg, "all") == 0)
60     return POSIX_LOG_ALL;
61   else if (::strcasecmp(arg, "async") == 0)
62     return POSIX_LOG_ASYNC;
63   else if (::strncasecmp(arg, "break", 5) == 0)
64     return POSIX_LOG_BREAKPOINTS;
65   else if (::strncasecmp(arg, "comm", 4) == 0)
66     return POSIX_LOG_COMM;
67   else if (::strcasecmp(arg, "default") == 0)
68     return POSIX_LOG_DEFAULT;
69   else if (::strcasecmp(arg, "packets") == 0)
70     return POSIX_LOG_PACKETS;
71   else if (::strcasecmp(arg, "memory") == 0)
72     return POSIX_LOG_MEMORY;
73   else if (::strcasecmp(arg, "data-short") == 0)
74     return POSIX_LOG_MEMORY_DATA_SHORT;
75   else if (::strcasecmp(arg, "data-long") == 0)
76     return POSIX_LOG_MEMORY_DATA_LONG;
77   else if (::strcasecmp(arg, "process") == 0)
78     return POSIX_LOG_PROCESS;
79   else if (::strcasecmp(arg, "ptrace") == 0)
80     return POSIX_LOG_PTRACE;
81   else if (::strcasecmp(arg, "registers") == 0)
82     return POSIX_LOG_REGISTERS;
83   else if (::strcasecmp(arg, "step") == 0)
84     return POSIX_LOG_STEP;
85   else if (::strcasecmp(arg, "thread") == 0)
86     return POSIX_LOG_THREAD;
87   else if (::strncasecmp(arg, "watch", 5) == 0)
88     return POSIX_LOG_WATCHPOINTS;
89   return 0;
90 }
91 
92 void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) {
93   Log *log(GetLog());
94   if (log) {
95     uint32_t flag_bits = 0;
96 
97     flag_bits = log->GetMask().Get();
98     for (; args && args[0]; args++) {
99       const char *arg = args[0];
100       uint32_t bits = GetFlagBits(arg);
101 
102       if (bits) {
103         flag_bits &= ~bits;
104       } else {
105         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
106         ListLogCategories(feedback_strm);
107       }
108     }
109 
110     log->GetMask().Reset(flag_bits);
111     if (flag_bits == 0)
112       g_log_enabled = false;
113   }
114 
115   return;
116 }
117 
118 Log *ProcessPOSIXLog::EnableLog(
119     const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
120     uint32_t log_options, const char **args, Stream *feedback_strm) {
121   // Try see if there already is a log - that way we can reuse its settings.
122   // We could reuse the log in toto, but we don't know that the stream is the
123   // same.
124   uint32_t flag_bits = 0;
125   if (g_log)
126     flag_bits = g_log->GetMask().Get();
127 
128   // Now make a new log with this stream if one was provided
129   if (log_stream_sp) {
130     if (g_log)
131       g_log->SetStream(log_stream_sp);
132     else
133       g_log = new Log(log_stream_sp);
134   }
135 
136   if (g_log) {
137     bool got_unknown_category = false;
138     for (; args && args[0]; args++) {
139       const char *arg = args[0];
140       uint32_t bits = GetFlagBits(arg);
141 
142       if (bits) {
143         flag_bits |= bits;
144       } else {
145         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
146         if (got_unknown_category == false) {
147           got_unknown_category = true;
148           ListLogCategories(feedback_strm);
149         }
150       }
151     }
152     if (flag_bits == 0)
153       flag_bits = POSIX_LOG_DEFAULT;
154     g_log->GetMask().Reset(flag_bits);
155     g_log->GetOptions().Reset(log_options);
156     g_log_enabled = true;
157   }
158   return g_log;
159 }
160 
161 void ProcessPOSIXLog::ListLogCategories(Stream *strm) {
162   strm->Printf(
163       "Logging categories for '%s':\n"
164       "  all - turn on all available logging categories\n"
165       "  async - log asynchronous activity\n"
166       "  break - log breakpoints\n"
167       "  communication - log communication activity\n"
168       "  default - enable the default set of logging categories for liblldb\n"
169       "  packets - log gdb remote packets\n"
170       "  memory - log memory reads and writes\n"
171       "  data-short - log memory bytes for memory reads and writes for short "
172       "transactions only\n"
173       "  data-long - log memory bytes for memory reads and writes for all "
174       "transactions\n"
175       "  process - log process events and activities\n"
176 #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
177       "  ptrace - log all calls to ptrace\n"
178 #endif
179       "  registers - log register read/writes\n"
180       "  thread - log thread events and activities\n"
181       "  step - log step related activities\n"
182       "  verbose - enable verbose logging\n"
183       "  watch - log watchpoint related activities\n",
184       ProcessPOSIXLog::m_pluginname);
185 }
186 
187 const char *ProcessPOSIXLog::m_pluginname = "";
188