JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
fdebug.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------
2// Project : SDK Base
3// Version : 1.0
4//
5// Category : Helpers
6// Filename : base/source/fdebug.cpp
7// Created by : Steinberg, 1995
8// Description : There are 2 levels of debugging messages:
9// DEVELOPMENT During development
10// RELEASE Program is shipping.
11//
12//-----------------------------------------------------------------------------
13// LICENSE
14// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved
15//-----------------------------------------------------------------------------
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19// * Redistributions of source code must retain the above copyright notice,
20// this list of conditions and the following disclaimer.
21// * Redistributions in binary form must reproduce the above copyright notice,
22// this list of conditions and the following disclaimer in the documentation
23// and/or other materials provided with the distribution.
24// * Neither the name of the Steinberg Media Technologies nor the names of its
25// contributors may be used to endorse or promote products derived from this
26// software without specific prior written permission.
27//
28// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
36// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37// OF THE POSSIBILITY OF SUCH DAMAGE.
38//-----------------------------------------------------------------------------
39
40#include "base/source/fdebug.h"
41
42#if SMTG_OS_WINDOWS
43#include <windows.h>
44
45bool AmIBeingDebugged ()
46{
47 return IsDebuggerPresent ();
48}
49#endif
50
51#if SMTG_OS_LINUX
52#include <signal.h>
53#include <sys/types.h>
54#include <unistd.h>
55//--------------------------------------------------------------------------
56bool AmIBeingDebugged ()
57{
58 // TODO: check if GDB or LLDB is attached
59 return true;
60}
61#endif
62
63#if SMTG_OS_MACOS
64
65#include <stdbool.h>
66#include <sys/sysctl.h>
67#include <sys/types.h>
68#include <unistd.h>
69
70//------------------------------------------------------------------------
71// from Technical Q&A QA1361 (http://developer.apple.com/qa/qa2004/qa1361.html)
72//------------------------------------------------------------------------
73bool AmIBeingDebugged ()
74// Returns true if the current process is being debugged (either
75// running under the debugger or has a debugger attached post facto).
76{
77 int mib[4];
78 struct kinfo_proc info;
79 size_t size;
80
81 // Initialize the flags so that, if sysctl fails for some bizarre
82 // reason, we get a predictable result.
83
84 info.kp_proc.p_flag = 0;
85
86 // Initialize mib, which tells sysctl the info we want, in this case
87 // we're looking for information about a specific process ID.
88
89 mib[0] = CTL_KERN;
90 mib[1] = KERN_PROC;
91 mib[2] = KERN_PROC_PID;
92 mib[3] = getpid ();
93
94 // Call sysctl.
95
96 size = sizeof (info);
97 sysctl (mib, sizeof (mib) / sizeof (*mib), &info, &size, NULL, 0);
98
99 // We're being debugged if the P_TRACED flag is set.
100 return ((info.kp_proc.p_flag & P_TRACED) != 0);
101}
102
103#endif // SMTG_OS_MACOS
104
105#if DEVELOPMENT
106
107#include <cassert>
108#include <cstdarg>
109#include <cstdio>
110#include <cstdlib>
111#include <mutex>
112
113#if SMTG_OS_WINDOWS
114#ifndef _WIN32_WINNT
115#define _WIN32_WINNT 0x0400
116#endif
117#if _MSC_VER
118#include <intrin.h>
119#endif
120#define vsnprintf _vsnprintf
121#define snprintf _snprintf
122
123#elif SMTG_OS_MACOS
124#include <errno.h>
125#include <mach/mach_init.h>
126#include <mach/mach_time.h>
127#include <new>
128#include <signal.h>
129
130#define THREAD_ALLOC_WATCH 0 // check allocations on specific threads
131
132#if THREAD_ALLOC_WATCH
133mach_port_t watchThreadID = 0;
134#endif
135
136#endif
137
138AssertionHandler gAssertionHandler = nullptr;
139AssertionHandler gPreAssertionHook = nullptr;
140DebugPrintLogger gDebugPrintLogger = nullptr;
141
142//--------------------------------------------------------------------------
143static const int kDebugPrintfBufferSize = 10000;
144static bool neverDebugger = false; // so I can switch it off in the debugger...
145
146static std::once_flag neverDebuggerEnvCheckFlag {};
147
148//--------------------------------------------------------------------------
149static void initNeverDebugger ()
150{
151 std::call_once (neverDebuggerEnvCheckFlag, [] () {
152 // add this environment variable to not stop in the debugger on ASSERT
153 if (std::getenv ("SMTG_DEBUG_IGNORE_ASSERT"))
154 {
155 neverDebugger = true;
156 }
157 });
158}
159
160//--------------------------------------------------------------------------
161static void printDebugString (const char* string)
162{
163 if (!string)
164 return;
165
166 if (gDebugPrintLogger)
167 {
168 gDebugPrintLogger (string);
169 }
170 else
171 {
172#if SMTG_OS_MACOS || defined(__MINGW32__)
173 fprintf (stderr, "%s", string);
174#elif SMTG_OS_WINDOWS
175 OutputDebugStringA (string);
176#endif
177 }
178}
179
180//--------------------------------------------------------------------------
181// printf style debugging output
182//--------------------------------------------------------------------------
183void FDebugPrint (const char* format, ...)
184{
185 char string[kDebugPrintfBufferSize];
186 va_list marker;
187 va_start (marker, format);
188 vsnprintf (string, kDebugPrintfBufferSize, format, marker);
189
190 printDebugString (string);
191}
192
193//--------------------------------------------------------------------------
194// printf style debugging output
195//--------------------------------------------------------------------------
196void FDebugBreak (const char* format, ...)
197{
198 char string[kDebugPrintfBufferSize];
199 va_list marker;
200 va_start (marker, format);
201 vsnprintf (string, kDebugPrintfBufferSize, format, marker);
202
203 printDebugString (string);
204
205 // The Pre-assertion hook is always called, even if we're not running in the debugger,
206 // so that we can log asserts without displaying them
207 if (gPreAssertionHook)
208 {
209 gPreAssertionHook (string);
210 }
211
212 initNeverDebugger ();
213 if (neverDebugger)
214 return;
215 if (AmIBeingDebugged ())
216 {
217 // do not crash if no debugger present
218 // If there is an assertion handler defined then let this override the UI
219 // and tell us whether we want to break into the debugger
220 bool breakIntoDebugger = true;
221 if (gAssertionHandler && gAssertionHandler (string) == false)
222 {
223 breakIntoDebugger = false;
224 }
225
226 if (breakIntoDebugger)
227 {
228#if SMTG_OS_WINDOWS && _MSC_VER
229 __debugbreak (); // intrinsic version of DebugBreak()
230#elif SMTG_OS_MACOS && __arm64__
231 raise (SIGSTOP);
232
233#elif __ppc64__ || __ppc__ || __arm__
234 kill (getpid (), SIGINT);
235#elif __i386__ || __x86_64__
236 {
237 __asm__ volatile ("int3");
238 }
239#endif
240 }
241 }
242}
243
244//--------------------------------------------------------------------------
245void FPrintLastError (const char* file, int line)
246{
247#if SMTG_OS_WINDOWS
248 LPVOID lpMessageBuffer = nullptr;
249 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr,
250 GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
251 (LPSTR)&lpMessageBuffer, 0, nullptr);
252 FDebugPrint ("%s(%d) : %s\n", file, line, lpMessageBuffer);
253 LocalFree (lpMessageBuffer);
254#endif
255
256#if SMTG_OS_MACOS
257#if !__MACH__
258 extern int errno;
259#endif
260 FDebugPrint ("%s(%d) : Errno %d\n", file, line, errno);
261#endif
262}
263
264#if SMTG_OS_MACOS
265
266//------------------------------------------------------------------------
267void* operator new (size_t size, int, const char* file, int line)
268{
269#if THREAD_ALLOC_WATCH
270 mach_port_t threadID = mach_thread_self ();
271 if (watchThreadID == threadID)
272 {
273 FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
274 }
275#endif
276 try
277 {
278 return ::operator new (size);
279 }
280 catch (std::bad_alloc exception)
281 {
282 FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);
283 }
284 return (void*)-1;
285}
286
287//------------------------------------------------------------------------
288void* operator new[] (size_t size, int, const char* file, int line)
289{
290#if THREAD_ALLOC_WATCH
291 mach_port_t threadID = mach_thread_self ();
292 if (watchThreadID == threadID)
293 {
294 FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
295 }
296#endif
297 try
298 {
299 return ::operator new[] (size);
300 }
301 catch (std::bad_alloc exception)
302 {
303 FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);
304 }
305 return (void*)-1;
306}
307
308//------------------------------------------------------------------------
309void operator delete (void* p, int, const char* file, int line)
310{
311 (void)file;
312 (void)line;
313 ::operator delete (p);
314}
315
316//------------------------------------------------------------------------
317void operator delete[] (void* p, int, const char* file, int line)
318{
319 (void)file;
320 (void)line;
321 ::operator delete[] (p);
322}
323
324#endif // SMTG_OS_MACOS
325
326#endif // DEVELOPMENT
327
328static bool smtg_unit_testing_active = false; // ugly hack to unit testing ...
329
330//------------------------------------------------------------------------
331bool isSmtgUnitTesting ()
332{
333 return smtg_unit_testing_active;
334}
335
336//------------------------------------------------------------------------
337void setSmtgUnitTesting ()
338{
339 smtg_unit_testing_active = true;
340}
T call_once(T... args)
fprintf
errno
Debugging tools.
bool AmIBeingDebugged()
Returns true if a debugger is attached.
T getenv(T... args)
getpid
kill
typedef int
raise
T size(T... args)
va_start
vsnprintf