1 //===-- ProcessWindowsLog.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 "ProcessWindowsLog.h"
11 
12 #include <mutex>
13 
14 #include "lldb/Core/StreamFile.h"
15 #include "lldb/Interpreter/Args.h"
16 #include "llvm/Support/ManagedStatic.h"
17 #include "llvm/Support/Threading.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 // We want to avoid global constructors where code needs to be run so here we
23 // control access to our static g_log_sp by hiding it in a singleton function
24 // that will construct the static g_log_sp the first time this function is
25 // called.
26 static bool g_log_enabled = false;
27 static Log *g_log = nullptr;
28 
29 static llvm::ManagedStatic<llvm::once_flag> g_once_flag;
30 
31 void ProcessWindowsLog::Initialize() {
32   static ConstString g_name("windows");
33 
34   llvm::call_once(*g_once_flag, []() {
35     Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
36 
37     Log::RegisterLogChannel(g_name, log_callbacks);
38     RegisterPluginName(g_name);
39   });
40 }
41 
42 void ProcessWindowsLog::Terminate() {}
43 
44 Log *ProcessWindowsLog::GetLog() { return (g_log_enabled) ? g_log : nullptr; }
45 
46 bool ProcessWindowsLog::TestLogFlags(uint32_t mask, LogMaskReq req) {
47   Log *log = GetLog();
48   if (!log)
49     return false;
50 
51   uint32_t log_mask = log->GetMask().Get();
52   if (req == LogMaskReq::All)
53     return ((log_mask & mask) == mask);
54   else
55     return (log_mask & mask);
56 }
57 
58 static uint32_t GetFlagBits(const char *arg) {
59   if (::strcasecmp(arg, "all") == 0)
60     return WINDOWS_LOG_ALL;
61   else if (::strcasecmp(arg, "break") == 0)
62     return WINDOWS_LOG_BREAKPOINTS;
63   else if (::strcasecmp(arg, "event") == 0)
64     return WINDOWS_LOG_EVENT;
65   else if (::strcasecmp(arg, "exception") == 0)
66     return WINDOWS_LOG_EXCEPTION;
67   else if (::strcasecmp(arg, "memory") == 0)
68     return WINDOWS_LOG_MEMORY;
69   else if (::strcasecmp(arg, "process") == 0)
70     return WINDOWS_LOG_PROCESS;
71   else if (::strcasecmp(arg, "registers") == 0)
72     return WINDOWS_LOG_REGISTERS;
73   else if (::strcasecmp(arg, "step") == 0)
74     return WINDOWS_LOG_STEP;
75   else if (::strcasecmp(arg, "thread") == 0)
76     return WINDOWS_LOG_THREAD;
77   else if (::strcasecmp(arg, "verbose") == 0)
78     return WINDOWS_LOG_VERBOSE;
79   return 0;
80 }
81 
82 void ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm) {
83   Log *log(GetLog());
84   if (log) {
85     uint32_t flag_bits = 0;
86 
87     if (args[0] != nullptr) {
88       flag_bits = log->GetMask().Get();
89       for (; args[0]; args++) {
90         const char *arg = args[0];
91         uint32_t bits = GetFlagBits(arg);
92 
93         if (bits) {
94           flag_bits &= ~bits;
95         } else {
96           feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
97           ListLogCategories(feedback_strm);
98         }
99       }
100     }
101 
102     log->GetMask().Reset(flag_bits);
103     if (flag_bits == 0) {
104       g_log_enabled = false;
105       log->SetStream(lldb::StreamSP());
106     }
107   }
108 
109   return;
110 }
111 
112 Log *ProcessWindowsLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
113                                   const char **args, Stream *feedback_strm) {
114   // Try see if there already is a log - that way we can reuse its settings.
115   // We could reuse the log in toto, but we don't know that the stream is the
116   // same.
117   uint32_t flag_bits = 0;
118   if (g_log)
119     flag_bits = g_log->GetMask().Get();
120 
121   // Now make a new log with this stream if one was provided
122   if (log_stream_sp) {
123     if (g_log)
124       g_log->SetStream(log_stream_sp);
125     else
126       g_log = new Log(log_stream_sp);
127   }
128 
129   if (g_log) {
130     bool got_unknown_category = false;
131     for (; args[0]; args++) {
132       const char *arg = args[0];
133       uint32_t bits = GetFlagBits(arg);
134 
135       if (bits) {
136         flag_bits |= bits;
137       } else {
138         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
139         if (got_unknown_category == false) {
140           got_unknown_category = true;
141           ListLogCategories(feedback_strm);
142         }
143       }
144     }
145     if (flag_bits == 0)
146       flag_bits = WINDOWS_LOG_ALL;
147     g_log->GetMask().Reset(flag_bits);
148     g_log->GetOptions().Reset(log_options);
149     g_log_enabled = true;
150   }
151   return g_log;
152 }
153 
154 void ProcessWindowsLog::ListLogCategories(Stream *strm) {
155   strm->Printf("Logging categories for '%s':\n"
156                "  all - turn on all available logging categories\n"
157                "  break - log breakpoints\n"
158                "  event - log low level debugger events\n"
159                "  exception - log exception information\n"
160                "  memory - log memory reads and writes\n"
161                "  process - log process events and activities\n"
162                "  registers - log register read/writes\n"
163                "  thread - log thread events and activities\n"
164                "  step - log step related activities\n"
165                "  verbose - enable verbose logging\n",
166                ProcessWindowsLog::m_pluginname);
167 }
168 
169 const char *ProcessWindowsLog::m_pluginname = "";
170