xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1061da546Spatrick //===-- DNBLog.cpp ----------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick //  Created by Greg Clayton on 6/18/07.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick 
13061da546Spatrick #include "DNBLog.h"
14061da546Spatrick 
15061da546Spatrick static int g_debug = 0;
16061da546Spatrick static int g_verbose = 0;
17061da546Spatrick 
18061da546Spatrick #if defined(DNBLOG_ENABLED)
19061da546Spatrick 
20061da546Spatrick #include "PThreadMutex.h"
21*be691f3bSpatrick #include <cstdarg>
22*be691f3bSpatrick #include <cstdio>
23*be691f3bSpatrick #include <cstdlib>
24061da546Spatrick #include <mach/mach.h>
25061da546Spatrick #include <pthread.h>
26061da546Spatrick #include <sys/time.h>
27061da546Spatrick #include <unistd.h>
28061da546Spatrick 
29061da546Spatrick uint32_t g_log_bits = 0;
30061da546Spatrick static DNBCallbackLog g_log_callback = NULL;
31061da546Spatrick static void *g_log_baton = NULL;
32061da546Spatrick 
DNBLogGetDebug()33061da546Spatrick int DNBLogGetDebug() { return g_debug; }
34061da546Spatrick 
DNBLogSetDebug(int g)35061da546Spatrick void DNBLogSetDebug(int g) { g_debug = g; }
36061da546Spatrick 
DNBLogGetVerbose()37061da546Spatrick int DNBLogGetVerbose() { return g_verbose; }
38061da546Spatrick 
DNBLogSetVerbose(int v)39061da546Spatrick void DNBLogSetVerbose(int v) { g_verbose = v; }
40061da546Spatrick 
DNBLogCheckLogBit(uint32_t bit)41061da546Spatrick bool DNBLogCheckLogBit(uint32_t bit) { return (g_log_bits & bit) != 0; }
42061da546Spatrick 
DNBLogSetLogMask(uint32_t mask)43061da546Spatrick uint32_t DNBLogSetLogMask(uint32_t mask) {
44061da546Spatrick   uint32_t old = g_log_bits;
45061da546Spatrick   g_log_bits = mask;
46061da546Spatrick   return old;
47061da546Spatrick }
48061da546Spatrick 
DNBLogGetLogMask()49061da546Spatrick uint32_t DNBLogGetLogMask() { return g_log_bits; }
50061da546Spatrick 
DNBLogSetLogCallback(DNBCallbackLog callback,void * baton)51061da546Spatrick void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton) {
52061da546Spatrick   g_log_callback = callback;
53061da546Spatrick   g_log_baton = baton;
54061da546Spatrick }
55061da546Spatrick 
DNBLogGetLogCallback()56061da546Spatrick DNBCallbackLog DNBLogGetLogCallback() { return g_log_callback; }
57061da546Spatrick 
DNBLogEnabled()58061da546Spatrick bool DNBLogEnabled() { return g_log_callback != NULL; }
59061da546Spatrick 
DNBLogEnabledForAny(uint32_t mask)60061da546Spatrick bool DNBLogEnabledForAny(uint32_t mask) {
61061da546Spatrick   if (g_log_callback)
62061da546Spatrick     return (g_log_bits & mask) != 0;
63061da546Spatrick   return false;
64061da546Spatrick }
_DNBLogVAPrintf(uint32_t flags,const char * format,va_list args)65061da546Spatrick static inline void _DNBLogVAPrintf(uint32_t flags, const char *format,
66061da546Spatrick                                    va_list args) {
67061da546Spatrick   static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE);
68061da546Spatrick   PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex);
69061da546Spatrick 
70061da546Spatrick   if (g_log_callback)
71061da546Spatrick     g_log_callback(g_log_baton, flags, format, args);
72061da546Spatrick }
73061da546Spatrick 
_DNBLog(uint32_t flags,const char * format,...)74061da546Spatrick void _DNBLog(uint32_t flags, const char *format, ...) {
75061da546Spatrick   va_list args;
76061da546Spatrick   va_start(args, format);
77061da546Spatrick   _DNBLogVAPrintf(flags, format, args);
78061da546Spatrick   va_end(args);
79061da546Spatrick }
80061da546Spatrick 
81061da546Spatrick // Print debug strings if and only if the global g_debug is set to
82061da546Spatrick // a non-zero value.
_DNBLogDebug(const char * format,...)83061da546Spatrick void _DNBLogDebug(const char *format, ...) {
84061da546Spatrick   if (DNBLogEnabled() && g_debug) {
85061da546Spatrick     va_list args;
86061da546Spatrick     va_start(args, format);
87061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args);
88061da546Spatrick     va_end(args);
89061da546Spatrick   }
90061da546Spatrick }
91061da546Spatrick 
92061da546Spatrick // Print debug strings if and only if the global g_debug is set to
93061da546Spatrick // a non-zero value.
_DNBLogDebugVerbose(const char * format,...)94061da546Spatrick void _DNBLogDebugVerbose(const char *format, ...) {
95061da546Spatrick   if (DNBLogEnabled() && g_debug && g_verbose) {
96061da546Spatrick     va_list args;
97061da546Spatrick     va_start(args, format);
98061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args);
99061da546Spatrick     va_end(args);
100061da546Spatrick   }
101061da546Spatrick }
102061da546Spatrick 
103061da546Spatrick static uint32_t g_message_id = 0;
104061da546Spatrick 
105061da546Spatrick // Prefix the formatted log string with process and thread IDs and
106061da546Spatrick // suffix it with a newline.
_DNBLogThreaded(const char * format,...)107061da546Spatrick void _DNBLogThreaded(const char *format, ...) {
108061da546Spatrick   if (DNBLogEnabled()) {
109061da546Spatrick     // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
110061da546Spatrick 
111061da546Spatrick     char *arg_msg = NULL;
112061da546Spatrick     va_list args;
113061da546Spatrick     va_start(args, format);
114061da546Spatrick     ::vasprintf(&arg_msg, format, args);
115061da546Spatrick     va_end(args);
116061da546Spatrick 
117061da546Spatrick     if (arg_msg != NULL) {
118061da546Spatrick       static struct timeval g_timeval = {0, 0};
119061da546Spatrick       static struct timeval tv;
120061da546Spatrick       static struct timeval delta;
121061da546Spatrick       gettimeofday(&tv, NULL);
122061da546Spatrick       if (g_timeval.tv_sec == 0) {
123061da546Spatrick         delta.tv_sec = 0;
124061da546Spatrick         delta.tv_usec = 0;
125061da546Spatrick       } else {
126061da546Spatrick         timersub(&tv, &g_timeval, &delta);
127061da546Spatrick       }
128061da546Spatrick       g_timeval = tv;
129061da546Spatrick 
130061da546Spatrick       // Calling "mach_port_deallocate()" bumps the reference count on the
131061da546Spatrick       // thread
132061da546Spatrick       // port, so we need to deallocate it. mach_task_self() doesn't bump the
133061da546Spatrick       // ref
134061da546Spatrick       // count.
135061da546Spatrick       thread_port_t thread_self = mach_thread_self();
136061da546Spatrick 
137061da546Spatrick       _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
138061da546Spatrick               ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(),
139061da546Spatrick               thread_self, arg_msg);
140061da546Spatrick 
141061da546Spatrick       mach_port_deallocate(mach_task_self(), thread_self);
142061da546Spatrick       free(arg_msg);
143061da546Spatrick     }
144061da546Spatrick   }
145061da546Spatrick }
146061da546Spatrick 
147061da546Spatrick // Prefix the formatted log string with process and thread IDs and
148061da546Spatrick // suffix it with a newline.
_DNBLogThreadedIf(uint32_t log_bit,const char * format,...)149061da546Spatrick void _DNBLogThreadedIf(uint32_t log_bit, const char *format, ...) {
150061da546Spatrick   if (DNBLogEnabled() && (log_bit & g_log_bits) == log_bit) {
151061da546Spatrick     // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex());
152061da546Spatrick 
153061da546Spatrick     char *arg_msg = NULL;
154061da546Spatrick     va_list args;
155061da546Spatrick     va_start(args, format);
156061da546Spatrick     ::vasprintf(&arg_msg, format, args);
157061da546Spatrick     va_end(args);
158061da546Spatrick 
159061da546Spatrick     if (arg_msg != NULL) {
160061da546Spatrick       static struct timeval g_timeval = {0, 0};
161061da546Spatrick       static struct timeval tv;
162061da546Spatrick       static struct timeval delta;
163061da546Spatrick       gettimeofday(&tv, NULL);
164061da546Spatrick       if (g_timeval.tv_sec == 0) {
165061da546Spatrick         delta.tv_sec = 0;
166061da546Spatrick         delta.tv_usec = 0;
167061da546Spatrick       } else {
168061da546Spatrick         timersub(&tv, &g_timeval, &delta);
169061da546Spatrick       }
170061da546Spatrick       g_timeval = tv;
171061da546Spatrick 
172061da546Spatrick       // Calling "mach_port_deallocate()" bumps the reference count on the
173061da546Spatrick       // thread
174061da546Spatrick       // port, so we need to deallocate it. mach_task_self() doesn't bump the
175061da546Spatrick       // ref
176061da546Spatrick       // count.
177061da546Spatrick       thread_port_t thread_self = mach_thread_self();
178061da546Spatrick 
179061da546Spatrick       _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s",
180061da546Spatrick               ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(),
181061da546Spatrick               thread_self, arg_msg);
182061da546Spatrick 
183061da546Spatrick       mach_port_deallocate(mach_task_self(), thread_self);
184061da546Spatrick 
185061da546Spatrick       free(arg_msg);
186061da546Spatrick     }
187061da546Spatrick   }
188061da546Spatrick }
189061da546Spatrick 
190061da546Spatrick // Printing of errors that are not fatal.
_DNBLogError(const char * format,...)191061da546Spatrick void _DNBLogError(const char *format, ...) {
192061da546Spatrick   if (DNBLogEnabled()) {
193061da546Spatrick     char *arg_msg = NULL;
194061da546Spatrick     va_list args;
195061da546Spatrick     va_start(args, format);
196061da546Spatrick     ::vasprintf(&arg_msg, format, args);
197061da546Spatrick     va_end(args);
198061da546Spatrick 
199061da546Spatrick     if (arg_msg != NULL) {
200061da546Spatrick       _DNBLog(DNBLOG_FLAG_ERROR, "error: %s", arg_msg);
201061da546Spatrick       free(arg_msg);
202061da546Spatrick     }
203061da546Spatrick   }
204061da546Spatrick }
205061da546Spatrick 
206061da546Spatrick // Printing of errors that ARE fatal. Exit with ERR exit code
207061da546Spatrick // immediately.
_DNBLogFatalError(int err,const char * format,...)208061da546Spatrick void _DNBLogFatalError(int err, const char *format, ...) {
209061da546Spatrick   if (DNBLogEnabled()) {
210061da546Spatrick     char *arg_msg = NULL;
211061da546Spatrick     va_list args;
212061da546Spatrick     va_start(args, format);
213061da546Spatrick     ::vasprintf(&arg_msg, format, args);
214061da546Spatrick     va_end(args);
215061da546Spatrick 
216061da546Spatrick     if (arg_msg != NULL) {
217061da546Spatrick       _DNBLog(DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg);
218061da546Spatrick       free(arg_msg);
219061da546Spatrick     }
220061da546Spatrick     ::exit(err);
221061da546Spatrick   }
222061da546Spatrick }
223061da546Spatrick 
224061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is
225061da546Spatrick // enabled.
_DNBLogVerbose(const char * format,...)226061da546Spatrick void _DNBLogVerbose(const char *format, ...) {
227061da546Spatrick   if (DNBLogEnabled() && g_verbose) {
228061da546Spatrick     va_list args;
229061da546Spatrick     va_start(args, format);
230061da546Spatrick     _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args);
231061da546Spatrick     va_end(args);
232061da546Spatrick   }
233061da546Spatrick }
234061da546Spatrick 
235061da546Spatrick // Printing of warnings that are not fatal only if verbose mode is
236061da546Spatrick // enabled.
_DNBLogWarningVerbose(const char * format,...)237061da546Spatrick void _DNBLogWarningVerbose(const char *format, ...) {
238061da546Spatrick   if (DNBLogEnabled() && g_verbose) {
239061da546Spatrick     char *arg_msg = NULL;
240061da546Spatrick     va_list args;
241061da546Spatrick     va_start(args, format);
242061da546Spatrick     ::vasprintf(&arg_msg, format, args);
243061da546Spatrick     va_end(args);
244061da546Spatrick 
245061da546Spatrick     if (arg_msg != NULL) {
246061da546Spatrick       _DNBLog(DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s",
247061da546Spatrick               arg_msg);
248061da546Spatrick       free(arg_msg);
249061da546Spatrick     }
250061da546Spatrick   }
251061da546Spatrick }
252061da546Spatrick // Printing of warnings that are not fatal.
_DNBLogWarning(const char * format,...)253061da546Spatrick void _DNBLogWarning(const char *format, ...) {
254061da546Spatrick   if (DNBLogEnabled()) {
255061da546Spatrick     char *arg_msg = NULL;
256061da546Spatrick     va_list args;
257061da546Spatrick     va_start(args, format);
258061da546Spatrick     ::vasprintf(&arg_msg, format, args);
259061da546Spatrick     va_end(args);
260061da546Spatrick 
261061da546Spatrick     if (arg_msg != NULL) {
262061da546Spatrick       _DNBLog(DNBLOG_FLAG_WARNING, "warning: %s", arg_msg);
263061da546Spatrick       free(arg_msg);
264061da546Spatrick     }
265061da546Spatrick   }
266061da546Spatrick }
267061da546Spatrick 
268061da546Spatrick #endif
269