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::GetLogIfAny(uint32_t mask) {
45   return (g_log_enabled && g_log->GetMask().AnySet(mask)) ? g_log : nullptr;
46 }
47 
48 static uint32_t GetFlagBits(const char *arg) {
49   if (::strcasecmp(arg, "all") == 0)
50     return WINDOWS_LOG_ALL;
51   else if (::strcasecmp(arg, "break") == 0)
52     return WINDOWS_LOG_BREAKPOINTS;
53   else if (::strcasecmp(arg, "event") == 0)
54     return WINDOWS_LOG_EVENT;
55   else if (::strcasecmp(arg, "exception") == 0)
56     return WINDOWS_LOG_EXCEPTION;
57   else if (::strcasecmp(arg, "memory") == 0)
58     return WINDOWS_LOG_MEMORY;
59   else if (::strcasecmp(arg, "process") == 0)
60     return WINDOWS_LOG_PROCESS;
61   else if (::strcasecmp(arg, "registers") == 0)
62     return WINDOWS_LOG_REGISTERS;
63   else if (::strcasecmp(arg, "step") == 0)
64     return WINDOWS_LOG_STEP;
65   else if (::strcasecmp(arg, "thread") == 0)
66     return WINDOWS_LOG_THREAD;
67   else if (::strcasecmp(arg, "verbose") == 0)
68     return WINDOWS_LOG_VERBOSE;
69   return 0;
70 }
71 
72 void ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm) {
73   Log *log(g_log);
74   if (log) {
75     uint32_t flag_bits = 0;
76 
77     if (args[0] != nullptr) {
78       flag_bits = log->GetMask().Get();
79       for (; args[0]; args++) {
80         const char *arg = args[0];
81         uint32_t bits = GetFlagBits(arg);
82 
83         if (bits) {
84           flag_bits &= ~bits;
85         } else {
86           feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
87           ListLogCategories(feedback_strm);
88         }
89       }
90     }
91 
92     log->GetMask().Reset(flag_bits);
93     if (flag_bits == 0) {
94       g_log_enabled = false;
95       log->SetStream(nullptr);
96     }
97   }
98 
99   return;
100 }
101 
102 Log *ProcessWindowsLog::EnableLog(
103     const std::shared_ptr<llvm::raw_ostream> &log_stream_sp, uint32_t log_options,
104     const char **args, Stream *feedback_strm) {
105   // Try see if there already is a log - that way we can reuse its settings.
106   // We could reuse the log in toto, but we don't know that the stream is the
107   // same.
108   uint32_t flag_bits = 0;
109   if (g_log)
110     flag_bits = g_log->GetMask().Get();
111 
112   // Now make a new log with this stream if one was provided
113   if (log_stream_sp) {
114     if (g_log)
115       g_log->SetStream(log_stream_sp);
116     else
117       g_log = new Log(log_stream_sp);
118   }
119 
120   if (g_log) {
121     bool got_unknown_category = false;
122     for (; args[0]; args++) {
123       const char *arg = args[0];
124       uint32_t bits = GetFlagBits(arg);
125 
126       if (bits) {
127         flag_bits |= bits;
128       } else {
129         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
130         if (got_unknown_category == false) {
131           got_unknown_category = true;
132           ListLogCategories(feedback_strm);
133         }
134       }
135     }
136     if (flag_bits == 0)
137       flag_bits = WINDOWS_LOG_ALL;
138     g_log->GetMask().Reset(flag_bits);
139     g_log->GetOptions().Reset(log_options);
140     g_log_enabled = true;
141   }
142   return g_log;
143 }
144 
145 void ProcessWindowsLog::ListLogCategories(Stream *strm) {
146   strm->Printf("Logging categories for '%s':\n"
147                "  all - turn on all available logging categories\n"
148                "  break - log breakpoints\n"
149                "  event - log low level debugger events\n"
150                "  exception - log exception information\n"
151                "  memory - log memory reads and writes\n"
152                "  process - log process events and activities\n"
153                "  registers - log register read/writes\n"
154                "  thread - log thread events and activities\n"
155                "  step - log step related activities\n"
156                "  verbose - enable verbose logging\n",
157                ProcessWindowsLog::m_pluginname);
158 }
159 
160 const char *ProcessWindowsLog::m_pluginname = "";
161