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.

320 lines
9.0KB

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