Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
9.1KB

  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) 2019, 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. #include "base/source/fdebug.h"
  40. #if DEVELOPMENT
  41. #include <assert.h>
  42. #include <cstdarg>
  43. #include <cstdio>
  44. #if SMTG_OS_WINDOWS
  45. #ifndef _WIN32_WINNT
  46. #define _WIN32_WINNT 0x0400
  47. #endif
  48. #include <intrin.h>
  49. #include <windows.h>
  50. #define vsnprintf _vsnprintf
  51. #define snprintf _snprintf
  52. #elif SMTG_OS_MACOS
  53. #include <errno.h>
  54. #include <mach/mach_init.h>
  55. #include <mach/mach_time.h>
  56. #include <new>
  57. #include <signal.h>
  58. #include <stdbool.h>
  59. #include <sys/sysctl.h>
  60. #include <sys/types.h>
  61. #include <unistd.h>
  62. static bool AmIBeingDebugged (void);
  63. #define THREAD_ALLOC_WATCH 0 // check allocations on specific threads
  64. #if THREAD_ALLOC_WATCH
  65. mach_port_t watchThreadID = 0;
  66. #endif
  67. #endif
  68. AssertionHandler gAssertionHandler = nullptr;
  69. AssertionHandler gPreAssertionHook = nullptr;
  70. DebugPrintLogger gDebugPrintLogger = nullptr;
  71. namespace boost {
  72. // Define the boost assertion handler to redirect to our assertion handler,
  73. // otherwise it just calls abort(). Note that we don't need to include any boost
  74. // headers for this, it just provides the handler.
  75. void assertion_failed (char const* expr, char const* function, char const* file, long line)
  76. {
  77. #if DEVELOPMENT
  78. char message[512];
  79. snprintf (message, 512, "%s at %s, %s:%ld", expr, function, file, line);
  80. if (gAssertionHandler)
  81. {
  82. FDebugBreak (message);
  83. }
  84. else
  85. {
  86. assert (!(const char *)message);
  87. }
  88. #endif
  89. }
  90. }
  91. //--------------------------------------------------------------------------
  92. static const int kDebugPrintfBufferSize = 10000;
  93. static bool neverDebugger = false; // so I can switch it off in the debugger...
  94. //--------------------------------------------------------------------------
  95. static void printDebugString (const char* string)
  96. {
  97. if (!string)
  98. return;
  99. if (gDebugPrintLogger)
  100. {
  101. gDebugPrintLogger (string);
  102. }
  103. else
  104. {
  105. #if SMTG_OS_MACOS
  106. fprintf (stderr, "%s", string);
  107. #elif SMTG_OS_WINDOWS
  108. OutputDebugStringA (string);
  109. #endif
  110. }
  111. }
  112. //--------------------------------------------------------------------------
  113. // printf style debugging output
  114. //--------------------------------------------------------------------------
  115. void FDebugPrint (const char* format, ...)
  116. {
  117. char string[kDebugPrintfBufferSize];
  118. va_list marker;
  119. va_start (marker, format);
  120. vsnprintf (string, kDebugPrintfBufferSize, format, marker);
  121. printDebugString (string);
  122. }
  123. #if SMTG_OS_WINDOWS
  124. #define AmIBeingDebugged IsDebuggerPresent
  125. #endif
  126. #if SMTG_OS_LINUX
  127. #include <signal.h>
  128. #include <sys/types.h>
  129. #include <unistd.h>
  130. //--------------------------------------------------------------------------
  131. static inline bool AmIBeingDebugged ()
  132. {
  133. // TODO: check if GDB or LLDB is attached
  134. return true;
  135. }
  136. #endif
  137. //--------------------------------------------------------------------------
  138. // printf style debugging output
  139. //--------------------------------------------------------------------------
  140. void FDebugBreak (const char* format, ...)
  141. {
  142. char string[kDebugPrintfBufferSize];
  143. va_list marker;
  144. va_start (marker, format);
  145. vsnprintf (string, kDebugPrintfBufferSize, format, marker);
  146. printDebugString (string);
  147. // The Pre-assertion hook is always called, even if we're not running in the debugger,
  148. // so that we can log asserts without displaying them
  149. if (gPreAssertionHook)
  150. {
  151. gPreAssertionHook (string);
  152. }
  153. if (neverDebugger)
  154. return;
  155. if (AmIBeingDebugged ())
  156. {
  157. // do not crash if no debugger present
  158. // If there is an assertion handler defined then let this override the UI
  159. // and tell us whether we want to break into the debugger
  160. bool breakIntoDebugger = true;
  161. if (gAssertionHandler && gAssertionHandler (string) == false)
  162. {
  163. breakIntoDebugger = false;
  164. }
  165. if (breakIntoDebugger)
  166. {
  167. #if SMTG_OS_WINDOWS
  168. __debugbreak (); // intrinsic version of DebugBreak()
  169. #elif __ppc64__ || __ppc__ || __arm__
  170. kill (getpid (), SIGINT);
  171. #elif __i386__ || __x86_64__
  172. {
  173. __asm__ volatile ("int3");
  174. }
  175. #endif
  176. }
  177. }
  178. }
  179. //--------------------------------------------------------------------------
  180. void FPrintLastError (const char* file, int line)
  181. {
  182. #if SMTG_OS_WINDOWS
  183. LPVOID lpMessageBuffer;
  184. FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
  185. GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  186. (LPSTR)&lpMessageBuffer, 0, NULL);
  187. FDebugPrint ("%s(%d) : %s\n", file, line, lpMessageBuffer);
  188. LocalFree (lpMessageBuffer);
  189. #endif
  190. #if SMTG_OS_MACOS
  191. #if !__MACH__
  192. extern int errno;
  193. #endif
  194. FDebugPrint ("%s(%d) : Errno %d\n", file, line, errno);
  195. #endif
  196. }
  197. #if SMTG_OS_MACOS
  198. //------------------------------------------------------------------------
  199. void* operator new (size_t size, int, const char* file, int line)
  200. {
  201. #if THREAD_ALLOC_WATCH
  202. mach_port_t threadID = mach_thread_self ();
  203. if (watchThreadID == threadID)
  204. {
  205. FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
  206. }
  207. #endif
  208. try
  209. {
  210. return ::operator new (size);
  211. }
  212. catch (std::bad_alloc exception)
  213. {
  214. FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);
  215. }
  216. return (void*)-1;
  217. }
  218. //------------------------------------------------------------------------
  219. void* operator new[] (size_t size, int, const char* file, int line)
  220. {
  221. #if THREAD_ALLOC_WATCH
  222. mach_port_t threadID = mach_thread_self ();
  223. if (watchThreadID == threadID)
  224. {
  225. FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
  226. }
  227. #endif
  228. try
  229. {
  230. return ::operator new[] (size);
  231. }
  232. catch (std::bad_alloc exception)
  233. {
  234. FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);
  235. }
  236. return (void*)-1;
  237. }
  238. //------------------------------------------------------------------------
  239. void operator delete (void* p, int, const char* file, int line)
  240. {
  241. ::operator delete (p);
  242. }
  243. //------------------------------------------------------------------------
  244. void operator delete[] (void* p, int, const char* file, int line)
  245. {
  246. ::operator delete[] (p);
  247. }
  248. //------------------------------------------------------------------------
  249. // from Technical Q&A QA1361 (http://developer.apple.com/qa/qa2004/qa1361.html)
  250. //------------------------------------------------------------------------
  251. bool AmIBeingDebugged (void)
  252. // Returns true if the current process is being debugged (either
  253. // running under the debugger or has a debugger attached post facto).
  254. {
  255. int mib[4];
  256. struct kinfo_proc info;
  257. size_t size;
  258. // Initialize the flags so that, if sysctl fails for some bizarre
  259. // reason, we get a predictable result.
  260. info.kp_proc.p_flag = 0;
  261. // Initialize mib, which tells sysctl the info we want, in this case
  262. // we're looking for information about a specific process ID.
  263. mib[0] = CTL_KERN;
  264. mib[1] = KERN_PROC;
  265. mib[2] = KERN_PROC_PID;
  266. mib[3] = getpid ();
  267. // Call sysctl.
  268. size = sizeof (info);
  269. sysctl (mib, sizeof (mib) / sizeof (*mib), &info, &size, NULL, 0);
  270. // We're being debugged if the P_TRACED flag is set.
  271. return ((info.kp_proc.p_flag & P_TRACED) != 0);
  272. }
  273. #endif // SMTG_OS_MACOS
  274. #endif // DEVELOPMENT