xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick //===-- DNBLog.cpp ----------------------------------------------*- C++ -*-===//
2*061da546Spatrick //
3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*061da546Spatrick //
7*061da546Spatrick //===----------------------------------------------------------------------===//
8*061da546Spatrick //
9*061da546Spatrick //  Created by Greg Clayton on 6/18/07.
10*061da546Spatrick //
11*061da546Spatrick //===----------------------------------------------------------------------===//
12*061da546Spatrick 
13*061da546Spatrick #include "DNBLog.h"
14*061da546Spatrick 
15*061da546Spatrick static int g_debug = 0;
16*061da546Spatrick static int g_verbose = 0;
17*061da546Spatrick 
18*061da546Spatrick #if defined(DNBLOG_ENABLED)
19*061da546Spatrick 
20*061da546Spatrick #include "PThreadMutex.h"
21*061da546Spatrick #include <mach/mach.h>
22*061da546Spatrick #include <pthread.h>
23*061da546Spatrick #include <stdarg.h>
24*061da546Spatrick #include <stdio.h>
25*061da546Spatrick #include <stdlib.h>
26*061da546Spatrick #include <sys/time.h>
27*061da546Spatrick #include <unistd.h>
28*061da546Spatrick 
29*061da546Spatrick uint32_t g_log_bits = 0;
30*061da546Spatrick static DNBCallbackLog g_log_callback = NULL;
31*061da546Spatrick static void *g_log_baton = NULL;
32*061da546Spatrick 
33*061da546Spatrick int DNBLogGetDebug() { return g_debug; }
34*061da546Spatrick 
35*061da546Spatrick void DNBLogSetDebug(int g) { g_debug = g; }
36*061da546Spatrick 
37*061da546Spatrick int DNBLogGetVerbose() { return g_verbose; }
38*061da546Spatrick 
39*061da546Spatrick void DNBLogSetVerbose(int v) { g_verbose = v; }
40*061da546Spatrick 
41*061da546Spatrick bool DNBLogCheckLogBit(uint32_t bit) { return (g_log_bits & bit) != 0; }
42*061da546Spatrick 
43*061da546Spatrick uint32_t DNBLogSetLogMask(uint32_t mask) {
44*061da546Spatrick   uint32_t old = g_log_bits;
45*061da546Spatrick   g_log_bits = mask;
46*061da546Spatrick   return old;
47*061da546Spatrick }
48*061da546Spatrick 
49*061da546Spatrick uint32_t DNBLogGetLogMask() { return g_log_bits; }
50*061da546Spatrick 
51*061da546Spatrick void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton) {
52*061da546Spatrick   g_log_callback = callback;
53*061da546Spatrick   g_log_baton = baton;
54*061da546Spatrick }
55*061da546Spatrick 
56*061da546Spatrick DNBCallbackLog DNBLogGetLogCallback() { return g_log_callback; }
57*061da546Spatrick 
58*061da546Spatrick bool DNBLogEnabled() { return g_log_callback != NULL; }
59*061da546Spatrick 
60*061da546Spatrick bool DNBLogEnabledForAny(uint32_t mask) {
61*061da546Spatrick   if (g_log_callback)
62*061da546Spatrick     return (g_log_bits & mask) != 0;
63*061da546Spatrick   return false;
64*061da546Spatrick }
65*061da546Spatrick static inline void _DNBLogVAPrintf(uint32_t flags, const char *format,
66*061da546Spatrick                                    va_list args) {
67*061da546Spatrick   static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE);
68*061da546Spatrick   PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex);
69*061da546Spatrick 
70*061da546Spatrick   if (g_log_callback)
71*061da546Spatrick     g_log_callback(g_log_baton, flags, format, args);
72*061da546Spatrick }
73*061da546Spatrick 
74*061da546Spatrick void _DNBLog(uint32_t flags, const char *format, ...) {
75*061da546Spatrick   va_list args;
76*061da546Spatrick   va_start(args, format);
77*061da546Spatrick   _DNBLogVAPrintf(flags, format, args);
78*061da546Spatrick   va_end(args);
79*061da546Spatrick }
80*061da546Spatrick 
81*061da546Spatrick // Print debug strings if and only if the global g_debug is set to
82*061da546Spatrick // a non-zero value.
83*061da546Spatrick void _DNBLogDebug(const char *format, ...) {
84*061da546Spatrick   if (DNBLogEnabled() && g_debug) {
85*061da546Spatrick     va_list args;
86*061da546Spatrick     va_start(args, format);
87*061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args);
88*061da546Spatrick     va_end(args);
89*061da546Spatrick   }
90*061da546Spatrick }
91*061da546Spatrick 
92*061da546Spatrick // Print debug strings if and only if the global g_debug is set to
93*061da546Spatrick // a non-zero value.
94*061da546Spatrick void _DNBLogDebugVerbose(const char *format, ...) {
95*061da546Spatrick   if (DNBLogEnabled() && g_debug && g_verbose) {
96*061da546Spatrick     va_list args;
97*061da546Spatrick     va_start(args, format);
98*061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args);
99*061da546Spatrick     va_end(args);
100*061da546Spatrick   }
101*061da546Spatrick }
102*061da546Spatrick 
103*061da546Spatrick static uint32_t g_message_id = 0;
104*061da546Spatrick 
105*061da546Spatrick // Prefix the formatted log string with process and thread IDs and
106*061da546Spatrick // suffix it with a newline.
107*061da546Spatrick void _DNBLogThreaded(const char *format, ...) {
108*061da546Spatrick   if (DNBLogEnabled()) {
109*061da546Spatrick     // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
110*061da546Spatrick 
111*061da546Spatrick     char *arg_msg = NULL;
112*061da546Spatrick     va_list args;
113*061da546Spatrick     va_start(args, format);
114*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
115*061da546Spatrick     va_end(args);
116*061da546Spatrick 
117*061da546Spatrick     if (arg_msg != NULL) {
118*061da546Spatrick       static struct timeval g_timeval = {0, 0};
119*061da546Spatrick       static struct timeval tv;
120*061da546Spatrick       static struct timeval delta;
121*061da546Spatrick       gettimeofday(&tv, NULL);
122*061da546Spatrick       if (g_timeval.tv_sec == 0) {
123*061da546Spatrick         delta.tv_sec = 0;
124*061da546Spatrick         delta.tv_usec = 0;
125*061da546Spatrick       } else {
126*061da546Spatrick         timersub(&tv, &g_timeval, &delta);
127*061da546Spatrick       }
128*061da546Spatrick       g_timeval = tv;
129*061da546Spatrick 
130*061da546Spatrick       // Calling "mach_port_deallocate()" bumps the reference count on the
131*061da546Spatrick       // thread
132*061da546Spatrick       // port, so we need to deallocate it. mach_task_self() doesn't bump the
133*061da546Spatrick       // ref
134*061da546Spatrick       // count.
135*061da546Spatrick       thread_port_t thread_self = mach_thread_self();
136*061da546Spatrick 
137*061da546Spatrick       _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
138*061da546Spatrick               ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(),
139*061da546Spatrick               thread_self, arg_msg);
140*061da546Spatrick 
141*061da546Spatrick       mach_port_deallocate(mach_task_self(), thread_self);
142*061da546Spatrick       free(arg_msg);
143*061da546Spatrick     }
144*061da546Spatrick   }
145*061da546Spatrick }
146*061da546Spatrick 
147*061da546Spatrick // Prefix the formatted log string with process and thread IDs and
148*061da546Spatrick // suffix it with a newline.
149*061da546Spatrick void _DNBLogThreadedIf(uint32_t log_bit, const char *format, ...) {
150*061da546Spatrick   if (DNBLogEnabled() && (log_bit & g_log_bits) == log_bit) {
151*061da546Spatrick     // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
152*061da546Spatrick 
153*061da546Spatrick     char *arg_msg = NULL;
154*061da546Spatrick     va_list args;
155*061da546Spatrick     va_start(args, format);
156*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
157*061da546Spatrick     va_end(args);
158*061da546Spatrick 
159*061da546Spatrick     if (arg_msg != NULL) {
160*061da546Spatrick       static struct timeval g_timeval = {0, 0};
161*061da546Spatrick       static struct timeval tv;
162*061da546Spatrick       static struct timeval delta;
163*061da546Spatrick       gettimeofday(&tv, NULL);
164*061da546Spatrick       if (g_timeval.tv_sec == 0) {
165*061da546Spatrick         delta.tv_sec = 0;
166*061da546Spatrick         delta.tv_usec = 0;
167*061da546Spatrick       } else {
168*061da546Spatrick         timersub(&tv, &g_timeval, &delta);
169*061da546Spatrick       }
170*061da546Spatrick       g_timeval = tv;
171*061da546Spatrick 
172*061da546Spatrick       // Calling "mach_port_deallocate()" bumps the reference count on the
173*061da546Spatrick       // thread
174*061da546Spatrick       // port, so we need to deallocate it. mach_task_self() doesn't bump the
175*061da546Spatrick       // ref
176*061da546Spatrick       // count.
177*061da546Spatrick       thread_port_t thread_self = mach_thread_self();
178*061da546Spatrick 
179*061da546Spatrick       _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
180*061da546Spatrick               ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(),
181*061da546Spatrick               thread_self, arg_msg);
182*061da546Spatrick 
183*061da546Spatrick       mach_port_deallocate(mach_task_self(), thread_self);
184*061da546Spatrick 
185*061da546Spatrick       free(arg_msg);
186*061da546Spatrick     }
187*061da546Spatrick   }
188*061da546Spatrick }
189*061da546Spatrick 
190*061da546Spatrick // Printing of errors that are not fatal.
191*061da546Spatrick void _DNBLogError(const char *format, ...) {
192*061da546Spatrick   if (DNBLogEnabled()) {
193*061da546Spatrick     char *arg_msg = NULL;
194*061da546Spatrick     va_list args;
195*061da546Spatrick     va_start(args, format);
196*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
197*061da546Spatrick     va_end(args);
198*061da546Spatrick 
199*061da546Spatrick     if (arg_msg != NULL) {
200*061da546Spatrick       _DNBLog(DNBLOG_FLAG_ERROR, "error: %s", arg_msg);
201*061da546Spatrick       free(arg_msg);
202*061da546Spatrick     }
203*061da546Spatrick   }
204*061da546Spatrick }
205*061da546Spatrick 
206*061da546Spatrick // Printing of errors that ARE fatal. Exit with ERR exit code
207*061da546Spatrick // immediately.
208*061da546Spatrick void _DNBLogFatalError(int err, const char *format, ...) {
209*061da546Spatrick   if (DNBLogEnabled()) {
210*061da546Spatrick     char *arg_msg = NULL;
211*061da546Spatrick     va_list args;
212*061da546Spatrick     va_start(args, format);
213*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
214*061da546Spatrick     va_end(args);
215*061da546Spatrick 
216*061da546Spatrick     if (arg_msg != NULL) {
217*061da546Spatrick       _DNBLog(DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg);
218*061da546Spatrick       free(arg_msg);
219*061da546Spatrick     }
220*061da546Spatrick     ::exit(err);
221*061da546Spatrick   }
222*061da546Spatrick }
223*061da546Spatrick 
224*061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is
225*061da546Spatrick // enabled.
226*061da546Spatrick void _DNBLogVerbose(const char *format, ...) {
227*061da546Spatrick   if (DNBLogEnabled() && g_verbose) {
228*061da546Spatrick     va_list args;
229*061da546Spatrick     va_start(args, format);
230*061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args);
231*061da546Spatrick     va_end(args);
232*061da546Spatrick   }
233*061da546Spatrick }
234*061da546Spatrick 
235*061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is
236*061da546Spatrick // enabled.
237*061da546Spatrick void _DNBLogWarningVerbose(const char *format, ...) {
238*061da546Spatrick   if (DNBLogEnabled() && g_verbose) {
239*061da546Spatrick     char *arg_msg = NULL;
240*061da546Spatrick     va_list args;
241*061da546Spatrick     va_start(args, format);
242*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
243*061da546Spatrick     va_end(args);
244*061da546Spatrick 
245*061da546Spatrick     if (arg_msg != NULL) {
246*061da546Spatrick       _DNBLog(DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s",
247*061da546Spatrick               arg_msg);
248*061da546Spatrick       free(arg_msg);
249*061da546Spatrick     }
250*061da546Spatrick   }
251*061da546Spatrick }
252*061da546Spatrick // Printing of warnings that are not fatal.
253*061da546Spatrick void _DNBLogWarning(const char *format, ...) {
254*061da546Spatrick   if (DNBLogEnabled()) {
255*061da546Spatrick     char *arg_msg = NULL;
256*061da546Spatrick     va_list args;
257*061da546Spatrick     va_start(args, format);
258*061da546Spatrick     ::vasprintf(&arg_msg, format, args);
259*061da546Spatrick     va_end(args);
260*061da546Spatrick 
261*061da546Spatrick     if (arg_msg != NULL) {
262*061da546Spatrick       _DNBLog(DNBLOG_FLAG_WARNING, "warning: %s", arg_msg);
263*061da546Spatrick       free(arg_msg);
264*061da546Spatrick     }
265*061da546Spatrick   }
266*061da546Spatrick }
267*061da546Spatrick 
268*061da546Spatrick #endif
269