|
- //------------------------------------------------------------------------
- // Project : SDK Base
- // Version : 1.0
- //
- // Category : Helpers
- // Filename : base/source/fdebug.cpp
- // Created by : Steinberg, 1995
- // Description : There are 2 levels of debugging messages:
- // DEVELOPMENT During development
- // RELEASE Program is shipping.
- //
- //-----------------------------------------------------------------------------
- // LICENSE
- // (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
- //-----------------------------------------------------------------------------
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- // * Neither the name of the Steinberg Media Technologies nor the names of its
- // contributors may be used to endorse or promote products derived from this
- // software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- // OF THE POSSIBILITY OF SUCH DAMAGE.
- //-----------------------------------------------------------------------------
-
- #include "base/source/fdebug.h"
-
- #if DEVELOPMENT
-
- #include <cstdio>
- #include <cstdarg>
-
- #if WINDOWS
- #ifndef _WIN32_WINNT
- #define _WIN32_WINNT 0x0400
- #endif
- #include <windows.h>
- #include <intrin.h>
- #define vsnprintf _vsnprintf
-
- #elif MAC
- #include <mach/mach_time.h>
- #include <mach/mach_init.h>
- #include <errno.h>
- #include <new>
- #include <stdbool.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/sysctl.h>
- #include <signal.h>
-
- static bool AmIBeingDebugged (void);
-
- #define THREAD_ALLOC_WATCH 0 // check allocations on specific threads
-
- #if THREAD_ALLOC_WATCH
- mach_port_t watchThreadID = 0;
- #endif
-
- #endif
-
- AssertionHandler gAssertionHandler = 0;
-
- //--------------------------------------------------------------------------
- static const int kDebugPrintfBufferSize = 10000;
- static bool neverDebugger = false; // so I can switch it off in the debugger...
-
- //--------------------------------------------------------------------------
- static void printDebugString (const char* string)
- {
- if (!string)
- return;
-
- #if MAC
- fprintf (stderr, "%s", string);
-
- #elif WINDOWS
- OutputDebugStringA (string);
- #endif
- }
-
-
- //--------------------------------------------------------------------------
- // printf style debugging output
- //--------------------------------------------------------------------------
- void FDebugPrint (const char *format, ...)
- {
- char string[kDebugPrintfBufferSize];
- va_list marker;
- va_start (marker, format);
- vsnprintf (string, kDebugPrintfBufferSize, format, marker);
-
- printDebugString (string);
- }
-
-
- #if WINDOWS
- #define AmIBeingDebugged IsDebuggerPresent
- #endif
-
- #if LINUX
- #include <sys/types.h>
- #include <unistd.h>
- #include <signal.h>
- //--------------------------------------------------------------------------
- static inline bool AmIBeingDebugged ()
- {
- // TODO: check if GDB or LLDB is attached
- return true;
- }
- #endif
-
- //--------------------------------------------------------------------------
- // printf style debugging output
- //--------------------------------------------------------------------------
- void FDebugBreak (const char *format, ...)
- {
- char string[kDebugPrintfBufferSize];
- va_list marker;
- va_start (marker, format);
- vsnprintf (string, kDebugPrintfBufferSize, format, marker);
-
- printDebugString (string);
-
- if (neverDebugger)
- return;
- if (AmIBeingDebugged ())
- {
- // do not crash if no debugger present
- // If there is an assertion handler defined then let this override the UI
- // and tell us whether we want to break into the debugger
- bool breakIntoDebugger = true;
- if (gAssertionHandler && gAssertionHandler (string) == false)
- {
- breakIntoDebugger = false;
- }
-
- if (breakIntoDebugger)
- {
- #if WINDOWS
- __debugbreak (); // intrinsic version of DebugBreak()
- #elif __ppc64__ || __ppc__ || __arm__
- kill (getpid (), SIGINT);
- #elif __i386__ || __x86_64__
- { __asm__ volatile ("int3"); }
- #endif
- }
- }
- }
-
- //--------------------------------------------------------------------------
- void FPrintLastError (const char* file, int line)
- {
- #if WINDOWS
- LPVOID lpMessageBuffer;
- FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPSTR) &lpMessageBuffer, 0, NULL);
- FDebugPrint ("%s(%d) : %s\n", file, line, lpMessageBuffer);
- LocalFree (lpMessageBuffer);
- #endif
-
- #if MAC
- #if !__MACH__
- extern int errno;
- #endif
- FDebugPrint ("%s(%d) : Errno %d\n", file, line, errno);
- #endif
- }
-
-
-
-
- #if MAC
-
- //------------------------------------------------------------------------
- void* operator new (size_t size, int, const char *file, int line)
- {
- #if THREAD_ALLOC_WATCH
- mach_port_t threadID = mach_thread_self ();
- if (watchThreadID == threadID)
- {
- FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
- }
- #endif
- try {
- return ::operator new (size);
- } catch (std::bad_alloc exception) { FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line); }
- return (void*)-1;
- }
-
- //------------------------------------------------------------------------
- void* operator new [](size_t size, int, const char *file, int line)
- {
- #if THREAD_ALLOC_WATCH
- mach_port_t threadID = mach_thread_self ();
- if (watchThreadID == threadID)
- {
- FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
- }
- #endif
- try {
- return ::operator new [](size);
- } catch (std::bad_alloc exception) { FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);}
- return (void*)-1;
- }
-
- //------------------------------------------------------------------------
- void operator delete(void* p, int, const char *file, int line)
- {
- ::operator delete (p);
- }
-
- //------------------------------------------------------------------------
- void operator delete[](void* p, int, const char *file, int line)
- {
- ::operator delete[] (p);
- }
-
- //------------------------------------------------------------------------
- // from Technical Q&A QA1361 (http://developer.apple.com/qa/qa2004/qa1361.html)
- //------------------------------------------------------------------------
- bool AmIBeingDebugged(void)
- // Returns true if the current process is being debugged (either
- // running under the debugger or has a debugger attached post facto).
- {
- int mib[4];
- struct kinfo_proc info;
- size_t size;
-
- // Initialize the flags so that, if sysctl fails for some bizarre
- // reason, we get a predictable result.
-
- info.kp_proc.p_flag = 0;
-
- // Initialize mib, which tells sysctl the info we want, in this case
- // we're looking for information about a specific process ID.
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- // Call sysctl.
-
- size = sizeof(info);
- sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
-
- // We're being debugged if the P_TRACED flag is set.
-
- return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
- }
-
- #endif // MAC
-
- #endif // DEVELOPMENT
|