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