xref: /llvm-project/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp (revision 38e2d5859418f360e6fb345c12041c08e4ca4ea3)
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(nullptr);
106     }
107   }
108 
109   return;
110 }
111 
112 Log *ProcessWindowsLog::EnableLog(
113     const std::shared_ptr<llvm::raw_ostream> &log_stream_sp, uint32_t log_options,
114     const char **args, Stream *feedback_strm) {
115   // Try see if there already is a log - that way we can reuse its settings.
116   // We could reuse the log in toto, but we don't know that the stream is the
117   // same.
118   uint32_t flag_bits = 0;
119   if (g_log)
120     flag_bits = g_log->GetMask().Get();
121 
122   // Now make a new log with this stream if one was provided
123   if (log_stream_sp) {
124     if (g_log)
125       g_log->SetStream(log_stream_sp);
126     else
127       g_log = new Log(log_stream_sp);
128   }
129 
130   if (g_log) {
131     bool got_unknown_category = false;
132     for (; args[0]; args++) {
133       const char *arg = args[0];
134       uint32_t bits = GetFlagBits(arg);
135 
136       if (bits) {
137         flag_bits |= bits;
138       } else {
139         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
140         if (got_unknown_category == false) {
141           got_unknown_category = true;
142           ListLogCategories(feedback_strm);
143         }
144       }
145     }
146     if (flag_bits == 0)
147       flag_bits = WINDOWS_LOG_ALL;
148     g_log->GetMask().Reset(flag_bits);
149     g_log->GetOptions().Reset(log_options);
150     g_log_enabled = true;
151   }
152   return g_log;
153 }
154 
155 void ProcessWindowsLog::ListLogCategories(Stream *strm) {
156   strm->Printf("Logging categories for '%s':\n"
157                "  all - turn on all available logging categories\n"
158                "  break - log breakpoints\n"
159                "  event - log low level debugger events\n"
160                "  exception - log exception information\n"
161                "  memory - log memory reads and writes\n"
162                "  process - log process events and activities\n"
163                "  registers - log register read/writes\n"
164                "  thread - log thread events and activities\n"
165                "  step - log step related activities\n"
166                "  verbose - enable verbose logging\n",
167                ProcessWindowsLog::m_pluginname);
168 }
169 
170 const char *ProcessWindowsLog::m_pluginname = "";
171