118a9135dSAdrian McCarthy //===-- ProcessWindowsLog.cpp -----------------------------------*- C++ -*-===//
218a9135dSAdrian McCarthy //
318a9135dSAdrian McCarthy //                     The LLVM Compiler Infrastructure
418a9135dSAdrian McCarthy //
518a9135dSAdrian McCarthy // This file is distributed under the University of Illinois Open Source
618a9135dSAdrian McCarthy // License. See LICENSE.TXT for details.
718a9135dSAdrian McCarthy //
818a9135dSAdrian McCarthy //===----------------------------------------------------------------------===//
918a9135dSAdrian McCarthy 
1018a9135dSAdrian McCarthy #include "ProcessWindowsLog.h"
1118a9135dSAdrian McCarthy 
1218a9135dSAdrian McCarthy #include <mutex>
1318a9135dSAdrian McCarthy 
1418a9135dSAdrian McCarthy #include "lldb/Core/StreamFile.h"
1518a9135dSAdrian McCarthy #include "lldb/Interpreter/Args.h"
1618a9135dSAdrian McCarthy #include "llvm/Support/ManagedStatic.h"
1718a9135dSAdrian McCarthy 
1818a9135dSAdrian McCarthy using namespace lldb;
1918a9135dSAdrian McCarthy using namespace lldb_private;
2018a9135dSAdrian McCarthy 
2118a9135dSAdrian McCarthy // We want to avoid global constructors where code needs to be run so here we
2218a9135dSAdrian McCarthy // control access to our static g_log_sp by hiding it in a singleton function
2318a9135dSAdrian McCarthy // that will construct the static g_log_sp the first time this function is
2418a9135dSAdrian McCarthy // called.
2518a9135dSAdrian McCarthy static bool g_log_enabled = false;
2618a9135dSAdrian McCarthy static Log *g_log = nullptr;
2718a9135dSAdrian McCarthy 
2818a9135dSAdrian McCarthy static llvm::ManagedStatic<std::once_flag> g_once_flag;
2918a9135dSAdrian McCarthy 
30*b9c1b51eSKate Stone void ProcessWindowsLog::Initialize() {
3118a9135dSAdrian McCarthy   static ConstString g_name("windows");
3218a9135dSAdrian McCarthy 
3318a9135dSAdrian McCarthy   std::call_once(*g_once_flag, []() {
34*b9c1b51eSKate Stone     Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
3518a9135dSAdrian McCarthy 
3618a9135dSAdrian McCarthy     Log::RegisterLogChannel(g_name, log_callbacks);
3718a9135dSAdrian McCarthy     RegisterPluginName(g_name);
3818a9135dSAdrian McCarthy   });
3918a9135dSAdrian McCarthy }
4018a9135dSAdrian McCarthy 
41*b9c1b51eSKate Stone void ProcessWindowsLog::Terminate() {}
4218a9135dSAdrian McCarthy 
43*b9c1b51eSKate Stone Log *ProcessWindowsLog::GetLog() { return (g_log_enabled) ? g_log : nullptr; }
4418a9135dSAdrian McCarthy 
45*b9c1b51eSKate Stone bool ProcessWindowsLog::TestLogFlags(uint32_t mask, LogMaskReq req) {
4618a9135dSAdrian McCarthy   Log *log = GetLog();
4718a9135dSAdrian McCarthy   if (!log)
4818a9135dSAdrian McCarthy     return false;
4918a9135dSAdrian McCarthy 
5018a9135dSAdrian McCarthy   uint32_t log_mask = log->GetMask().Get();
5118a9135dSAdrian McCarthy   if (req == LogMaskReq::All)
5218a9135dSAdrian McCarthy     return ((log_mask & mask) == mask);
5318a9135dSAdrian McCarthy   else
5418a9135dSAdrian McCarthy     return (log_mask & mask);
5518a9135dSAdrian McCarthy }
5618a9135dSAdrian McCarthy 
57*b9c1b51eSKate Stone static uint32_t GetFlagBits(const char *arg) {
58*b9c1b51eSKate Stone   if (::strcasecmp(arg, "all") == 0)
59*b9c1b51eSKate Stone     return WINDOWS_LOG_ALL;
60*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "break") == 0)
61*b9c1b51eSKate Stone     return WINDOWS_LOG_BREAKPOINTS;
62*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "event") == 0)
63*b9c1b51eSKate Stone     return WINDOWS_LOG_EVENT;
64*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "exception") == 0)
65*b9c1b51eSKate Stone     return WINDOWS_LOG_EXCEPTION;
66*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "memory") == 0)
67*b9c1b51eSKate Stone     return WINDOWS_LOG_MEMORY;
68*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "process") == 0)
69*b9c1b51eSKate Stone     return WINDOWS_LOG_PROCESS;
70*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "registers") == 0)
71*b9c1b51eSKate Stone     return WINDOWS_LOG_REGISTERS;
72*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "step") == 0)
73*b9c1b51eSKate Stone     return WINDOWS_LOG_STEP;
74*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "thread") == 0)
75*b9c1b51eSKate Stone     return WINDOWS_LOG_THREAD;
76*b9c1b51eSKate Stone   else if (::strcasecmp(arg, "verbose") == 0)
77*b9c1b51eSKate Stone     return WINDOWS_LOG_VERBOSE;
7818a9135dSAdrian McCarthy   return 0;
7918a9135dSAdrian McCarthy }
8018a9135dSAdrian McCarthy 
81*b9c1b51eSKate Stone void ProcessWindowsLog::DisableLog(const char **args, Stream *feedback_strm) {
8218a9135dSAdrian McCarthy   Log *log(GetLog());
83*b9c1b51eSKate Stone   if (log) {
8418a9135dSAdrian McCarthy     uint32_t flag_bits = 0;
8518a9135dSAdrian McCarthy 
86*b9c1b51eSKate Stone     if (args[0] != nullptr) {
8718a9135dSAdrian McCarthy       flag_bits = log->GetMask().Get();
88*b9c1b51eSKate Stone       for (; args[0]; args++) {
8918a9135dSAdrian McCarthy         const char *arg = args[0];
9018a9135dSAdrian McCarthy         uint32_t bits = GetFlagBits(arg);
9118a9135dSAdrian McCarthy 
92*b9c1b51eSKate Stone         if (bits) {
9318a9135dSAdrian McCarthy           flag_bits &= ~bits;
94*b9c1b51eSKate Stone         } else {
9518a9135dSAdrian McCarthy           feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
9618a9135dSAdrian McCarthy           ListLogCategories(feedback_strm);
9718a9135dSAdrian McCarthy         }
9818a9135dSAdrian McCarthy       }
9918a9135dSAdrian McCarthy     }
10018a9135dSAdrian McCarthy 
10118a9135dSAdrian McCarthy     log->GetMask().Reset(flag_bits);
102*b9c1b51eSKate Stone     if (flag_bits == 0) {
10318a9135dSAdrian McCarthy       g_log_enabled = false;
10418a9135dSAdrian McCarthy       log->SetStream(lldb::StreamSP());
10518a9135dSAdrian McCarthy     }
10618a9135dSAdrian McCarthy   }
10718a9135dSAdrian McCarthy 
10818a9135dSAdrian McCarthy   return;
10918a9135dSAdrian McCarthy }
11018a9135dSAdrian McCarthy 
111*b9c1b51eSKate Stone Log *ProcessWindowsLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
112*b9c1b51eSKate Stone                                   const char **args, Stream *feedback_strm) {
11318a9135dSAdrian McCarthy   // Try see if there already is a log - that way we can reuse its settings.
114*b9c1b51eSKate Stone   // We could reuse the log in toto, but we don't know that the stream is the
115*b9c1b51eSKate Stone   // same.
11618a9135dSAdrian McCarthy   uint32_t flag_bits = 0;
11718a9135dSAdrian McCarthy   if (g_log)
11818a9135dSAdrian McCarthy     flag_bits = g_log->GetMask().Get();
11918a9135dSAdrian McCarthy 
12018a9135dSAdrian McCarthy   // Now make a new log with this stream if one was provided
121*b9c1b51eSKate Stone   if (log_stream_sp) {
12218a9135dSAdrian McCarthy     if (g_log)
12318a9135dSAdrian McCarthy       g_log->SetStream(log_stream_sp);
12418a9135dSAdrian McCarthy     else
12518a9135dSAdrian McCarthy       g_log = new Log(log_stream_sp);
12618a9135dSAdrian McCarthy   }
12718a9135dSAdrian McCarthy 
128*b9c1b51eSKate Stone   if (g_log) {
12918a9135dSAdrian McCarthy     bool got_unknown_category = false;
130*b9c1b51eSKate Stone     for (; args[0]; args++) {
13118a9135dSAdrian McCarthy       const char *arg = args[0];
13218a9135dSAdrian McCarthy       uint32_t bits = GetFlagBits(arg);
13318a9135dSAdrian McCarthy 
134*b9c1b51eSKate Stone       if (bits) {
13518a9135dSAdrian McCarthy         flag_bits |= bits;
136*b9c1b51eSKate Stone       } else {
13718a9135dSAdrian McCarthy         feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
138*b9c1b51eSKate Stone         if (got_unknown_category == false) {
13918a9135dSAdrian McCarthy           got_unknown_category = true;
14018a9135dSAdrian McCarthy           ListLogCategories(feedback_strm);
14118a9135dSAdrian McCarthy         }
14218a9135dSAdrian McCarthy       }
14318a9135dSAdrian McCarthy     }
14418a9135dSAdrian McCarthy     if (flag_bits == 0)
14518a9135dSAdrian McCarthy       flag_bits = WINDOWS_LOG_ALL;
14618a9135dSAdrian McCarthy     g_log->GetMask().Reset(flag_bits);
14718a9135dSAdrian McCarthy     g_log->GetOptions().Reset(log_options);
14818a9135dSAdrian McCarthy     g_log_enabled = true;
14918a9135dSAdrian McCarthy   }
15018a9135dSAdrian McCarthy   return g_log;
15118a9135dSAdrian McCarthy }
15218a9135dSAdrian McCarthy 
153*b9c1b51eSKate Stone void ProcessWindowsLog::ListLogCategories(Stream *strm) {
15418a9135dSAdrian McCarthy   strm->Printf("Logging categories for '%s':\n"
15518a9135dSAdrian McCarthy                "  all - turn on all available logging categories\n"
15618a9135dSAdrian McCarthy                "  break - log breakpoints\n"
15718a9135dSAdrian McCarthy                "  event - log low level debugger events\n"
15818a9135dSAdrian McCarthy                "  exception - log exception information\n"
15918a9135dSAdrian McCarthy                "  memory - log memory reads and writes\n"
16018a9135dSAdrian McCarthy                "  process - log process events and activities\n"
16118a9135dSAdrian McCarthy                "  registers - log register read/writes\n"
16218a9135dSAdrian McCarthy                "  thread - log thread events and activities\n"
16318a9135dSAdrian McCarthy                "  step - log step related activities\n"
16418a9135dSAdrian McCarthy                "  verbose - enable verbose logging\n",
16518a9135dSAdrian McCarthy                ProcessWindowsLog::m_pluginname);
16618a9135dSAdrian McCarthy }
16718a9135dSAdrian McCarthy 
16818a9135dSAdrian McCarthy const char *ProcessWindowsLog::m_pluginname = "";
169