1//===-- ProcessGDBRemoteLog.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 "ProcessGDBRemoteLog.h"
11
12#include "lldb/Interpreter/Args.h"
13#include "lldb/Core/StreamFile.h"
14
15#include "ProcessGDBRemote.h"
16
17using namespace lldb;
18using namespace lldb_private;
19
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_lob_sp the first time this function is
24// called.
25static bool g_log_enabled = false;
26static Log * g_log = NULL;
27static Log *
28GetLog ()
29{
30    if (!g_log_enabled)
31        return NULL;
32    return g_log;
33}
34
35
36Log *
37ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
38{
39    Log *log(GetLog ());
40    if (log && mask)
41    {
42        uint32_t log_mask = log->GetMask().Get();
43        if ((log_mask & mask) != mask)
44            return NULL;
45    }
46    return log;
47}
48
49Log *
50ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask)
51{
52    Log *log(GetLog ());
53    if (log && log->GetMask().Get() & mask)
54        return log;
55    return NULL;
56}
57
58void
59ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm)
60{
61    Log *log (GetLog ());
62    if (log)
63    {
64        uint32_t flag_bits = 0;
65
66        if (categories[0] != NULL)
67        {
68            flag_bits = log->GetMask().Get();
69            for (size_t i = 0; categories[i] != NULL; ++i)
70            {
71                const char *arg = categories[i];
72
73
74                if      (::strcasecmp (arg, "all")        == 0 ) flag_bits &= ~GDBR_LOG_ALL;
75                else if (::strcasecmp (arg, "async")      == 0 ) flag_bits &= ~GDBR_LOG_ASYNC;
76                else if (::strncasecmp (arg, "break", 5)  == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS;
77                else if (::strncasecmp (arg, "comm", 4)   == 0 ) flag_bits &= ~GDBR_LOG_COMM;
78                else if (::strcasecmp (arg, "default")    == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT;
79                else if (::strcasecmp (arg, "packets")    == 0 ) flag_bits &= ~GDBR_LOG_PACKETS;
80                else if (::strcasecmp (arg, "memory")     == 0 ) flag_bits &= ~GDBR_LOG_MEMORY;
81                else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
82                else if (::strcasecmp (arg, "data-long")  == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
83                else if (::strcasecmp (arg, "process")    == 0 ) flag_bits &= ~GDBR_LOG_PROCESS;
84                else if (::strcasecmp (arg, "step")       == 0 ) flag_bits &= ~GDBR_LOG_STEP;
85                else if (::strcasecmp (arg, "thread")     == 0 ) flag_bits &= ~GDBR_LOG_THREAD;
86                else if (::strcasecmp (arg, "verbose")    == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE;
87                else if (::strncasecmp (arg, "watch", 5)  == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS;
88                else
89                {
90                    feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
91                    ListLogCategories (feedback_strm);
92                }
93
94            }
95        }
96
97        if (flag_bits == 0)
98            g_log_enabled = false;
99        else
100            log->GetMask().Reset (flag_bits);
101    }
102
103    return;
104}
105
106Log *
107ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
108{
109    // Try see if there already is a log - that way we can reuse its settings.
110    // We could reuse the log in toto, but we don't know that the stream is the same.
111    uint32_t flag_bits = 0;
112    if (g_log)
113        flag_bits = g_log->GetMask().Get();
114
115    // Now make a new log with this stream if one was provided
116    if (log_stream_sp)
117    {
118        if (g_log)
119            g_log->SetStream(log_stream_sp);
120        else
121            g_log = new Log(log_stream_sp);
122    }
123
124    if (g_log)
125    {
126        bool got_unknown_category = false;
127        for (size_t i=0; categories[i] != NULL; ++i)
128        {
129            const char *arg = categories[i];
130
131            if      (::strcasecmp (arg, "all")        == 0 ) flag_bits |= GDBR_LOG_ALL;
132            else if (::strcasecmp (arg, "async")      == 0 ) flag_bits |= GDBR_LOG_ASYNC;
133            else if (::strncasecmp (arg, "break", 5)  == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS;
134            else if (::strncasecmp (arg, "comm", 4)   == 0 ) flag_bits |= GDBR_LOG_COMM;
135            else if (::strcasecmp (arg, "default")    == 0 ) flag_bits |= GDBR_LOG_DEFAULT;
136            else if (::strcasecmp (arg, "packets")    == 0 ) flag_bits |= GDBR_LOG_PACKETS;
137            else if (::strcasecmp (arg, "memory")     == 0 ) flag_bits |= GDBR_LOG_MEMORY;
138            else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
139            else if (::strcasecmp (arg, "data-long")  == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
140            else if (::strcasecmp (arg, "process")    == 0 ) flag_bits |= GDBR_LOG_PROCESS;
141            else if (::strcasecmp (arg, "step")       == 0 ) flag_bits |= GDBR_LOG_STEP;
142            else if (::strcasecmp (arg, "thread")     == 0 ) flag_bits |= GDBR_LOG_THREAD;
143            else if (::strcasecmp (arg, "verbose")    == 0 ) flag_bits |= GDBR_LOG_VERBOSE;
144            else if (::strncasecmp (arg, "watch", 5)  == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS;
145            else
146            {
147                feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
148                if (got_unknown_category == false)
149                {
150                    got_unknown_category = true;
151                    ListLogCategories (feedback_strm);
152                }
153            }
154        }
155        if (flag_bits == 0)
156            flag_bits = GDBR_LOG_DEFAULT;
157        g_log->GetMask().Reset(flag_bits);
158        g_log->GetOptions().Reset(log_options);
159    }
160    g_log_enabled = true;
161    return g_log;
162}
163
164void
165ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
166{
167    strm->Printf ("Logging categories for '%s':\n"
168                  "  all - turn on all available logging categories\n"
169                  "  async - log asynchronous activity\n"
170                  "  break - log breakpoints\n"
171                  "  communication - log communication activity\n"
172                  "  default - enable the default set of logging categories for liblldb\n"
173                  "  packets - log gdb remote packets\n"
174                  "  memory - log memory reads and writes\n"
175                  "  data-short - log memory bytes for memory reads and writes for short transactions only\n"
176                  "  data-long - log memory bytes for memory reads and writes for all transactions\n"
177                  "  process - log process events and activities\n"
178                  "  thread - log thread events and activities\n"
179                  "  step - log step related activities\n"
180                  "  verbose - enable verbose logging\n"
181                  "  watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString());
182}
183
184
185void
186ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...)
187{
188    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask));
189    if (log)
190    {
191        va_list args;
192        va_start (args, format);
193        log->VAPrintf (format, args);
194        va_end (args);
195    }
196}
197