From f7b7f18e0df86873130addca90b43060995ec62c Mon Sep 17 00:00:00 2001 From: "Azamat H. Hackimov" Date: Mon, 23 Sep 2024 17:01:28 +0300 Subject: [PATCH] Replace debugbreak with SDL_assert() Reworked ASSERT() and Int3() macros to use SDL_assert(). SDL_assert() allows to debug break from user decision. Major reorganizing platform-dependent code to make it platform-independent. --- Descent3/DllWrappers.cpp | 7 +- ddebug/CMakeLists.txt | 2 +- ddebug/debug.h | 16 +--- ddebug/debugbreak.h | 192 --------------------------------------- ddebug/error.cpp | 28 +++--- ddebug/lnxdebug.cpp | 5 +- ddebug/pserror.h | 54 +++++------ ddebug/windebug.cpp | 2 +- win32/winapp.cpp | 4 +- 9 files changed, 48 insertions(+), 262 deletions(-) delete mode 100644 ddebug/debugbreak.h diff --git a/Descent3/DllWrappers.cpp b/Descent3/DllWrappers.cpp index a21c438e..6505fc4b 100644 --- a/Descent3/DllWrappers.cpp +++ b/Descent3/DllWrappers.cpp @@ -106,11 +106,8 @@ void SetObjectDeadFlagDLL(object *obj, bool tell_clients_to_remove, bool tell_cl void assertdll(int x, const char *expression, const char *file, int line) { #ifndef RELEASE if (!(unsigned)(x)) { - LOG_ERROR.printf("Assertion failed (%s) in %s line %d.", expression, file, line); - if (Debug_break) - DEBUG_BREAK(); - else - AssertionFailed(expression, file, line); + LOG_ERROR.printf("Assertion failed (%s) in %s:%d.", expression, file, line); + SDL_assert(x); } #endif } diff --git a/ddebug/CMakeLists.txt b/ddebug/CMakeLists.txt index 2ebe1779..8d4aec7d 100644 --- a/ddebug/CMakeLists.txt +++ b/ddebug/CMakeLists.txt @@ -1,6 +1,5 @@ set(HEADERS debug.h - debugbreak.h mono.h pserror.h ) @@ -31,5 +30,6 @@ target_link_libraries(ddebug PRIVATE misc > PUBLIC + SDL2::SDL2 logger ) diff --git a/ddebug/debug.h b/ddebug/debug.h index 336fb789..7efecb3f 100644 --- a/ddebug/debug.h +++ b/ddebug/debug.h @@ -164,24 +164,12 @@ int Debug_MessageBox(int type, const char *title, const char *str); // these functions deal with debug spew support void Debug_ConsolePrintf(int n, const char *format, ...); -// DEBUGGING MACROS -// Break into the debugger, if this feature was enabled in Debug_init() -#if !defined(RELEASE) -#include "debugbreak.h" -#if defined(WIN32) -#elif defined(POSIX) -void ddio_InternalKeyClose(); -#else -#define debug_break() -#endif -#else -#define debug_break() -#endif - #if defined(WIN32) #include long WINAPI RecordExceptionInfo(PEXCEPTION_POINTERS data); + #endif + #endif diff --git a/ddebug/debugbreak.h b/ddebug/debugbreak.h deleted file mode 100644 index 110f6436..00000000 --- a/ddebug/debugbreak.h +++ /dev/null @@ -1,192 +0,0 @@ -/* -* Descent 3 -* Copyright (C) 2024 Parallax Software -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -/* Copyright (c) 2011-2021, Scott Tsai - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. 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. - * - * 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 HOLDER 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. - */ -#ifndef DEBUG_BREAK_H -#define DEBUG_BREAK_H - -#ifdef _MSC_VER - -#define debug_break __debugbreak - -#else - -#ifdef __cplusplus -extern "C" { -#endif - -#define DEBUG_BREAK_USE_TRAP_INSTRUCTION 1 -#define DEBUG_BREAK_USE_BULTIN_TRAP 2 -#define DEBUG_BREAK_USE_SIGTRAP 3 - -#if defined(__i386__) || defined(__x86_64__) - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -__inline__ static void trap_instruction(void) -{ - __asm__ volatile("int $0x03"); -} -#elif defined(__thumb__) - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -/* FIXME: handle __THUMB_INTERWORK__ */ -__attribute__((always_inline)) -__inline__ static void trap_instruction(void) -{ - /* See 'arm-linux-tdep.c' in GDB source. - * Both instruction sequences below work. */ -#if 1 - /* 'eabi_linux_thumb_le_breakpoint' */ - __asm__ volatile(".inst 0xde01"); -#else - /* 'eabi_linux_thumb2_le_breakpoint' */ - __asm__ volatile(".inst.w 0xf7f0a000"); -#endif - - /* Known problem: - * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. - * 'step' would keep getting stuck on the same instruction. - * - * Workaround: use the new GDB commands 'debugbreak-step' and - * 'debugbreak-continue' that become available - * after you source the script from GDB: - * - * $ gdb -x debugbreak-gdb.py <... USUAL ARGUMENTS ...> - * - * 'debugbreak-step' would jump over the breakpoint instruction with - * roughly equivalent of: - * (gdb) set $instruction_len = 2 - * (gdb) tbreak *($pc + $instruction_len) - * (gdb) jump *($pc + $instruction_len) - */ -} -#elif defined(__arm__) && !defined(__thumb__) - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -__attribute__((always_inline)) -__inline__ static void trap_instruction(void) -{ - /* See 'arm-linux-tdep.c' in GDB source, - * 'eabi_linux_arm_le_breakpoint' */ - __asm__ volatile(".inst 0xe7f001f0"); - /* Known problem: - * Same problem and workaround as Thumb mode */ -} -#elif defined(__aarch64__) && defined(__APPLE__) - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_BULTIN_DEBUGTRAP -#elif defined(__aarch64__) - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -__attribute__((always_inline)) -__inline__ static void trap_instruction(void) -{ - /* See 'aarch64-tdep.c' in GDB source, - * 'aarch64_default_breakpoint' */ - __asm__ volatile(".inst 0xd4200000"); -} -#elif defined(__powerpc__) - /* PPC 32 or 64-bit, big or little endian */ - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -__attribute__((always_inline)) -__inline__ static void trap_instruction(void) -{ - /* See 'rs6000-tdep.c' in GDB source, - * 'rs6000_breakpoint' */ - __asm__ volatile(".4byte 0x7d821008"); - - /* Known problem: - * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. - * 'step' stuck on the same instruction ("twge r2,r2"). - * - * The workaround is the same as ARM Thumb mode: use debugbreak-gdb.py - * or manually jump over the instruction. */ -} -#elif defined(__riscv) - /* RISC-V 32 or 64-bit, whether the "C" extension - * for compressed, 16-bit instructions are supported or not */ - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION -__attribute__((always_inline)) -__inline__ static void trap_instruction(void) -{ - /* See 'riscv-tdep.c' in GDB source, - * 'riscv_sw_breakpoint_from_kind' */ - __asm__ volatile(".4byte 0x00100073"); -} -#else - #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_SIGTRAP -#endif - - -#ifndef DEBUG_BREAK_IMPL -#error "debugbreak.h is not supported on this target" -#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_TRAP_INSTRUCTION -__attribute__((always_inline)) -__inline__ static void debug_break(void) -{ - trap_instruction(); -} -#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_DEBUGTRAP -__attribute__((always_inline)) -__inline__ static void debug_break(void) -{ - __builtin_debugtrap(); -} -#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_TRAP -__attribute__((always_inline)) -__inline__ static void debug_break(void) -{ - __builtin_trap(); -} -#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_SIGTRAP -#include -__attribute__((always_inline)) -__inline__ static void debug_break(void) -{ - raise(SIGTRAP); -} -#else -#error "invalid DEBUG_BREAK_IMPL value" -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ifdef _MSC_VER */ - -#endif /* ifndef DEBUG_BREAK_H */ diff --git a/ddebug/error.cpp b/ddebug/error.cpp index bf58414a..4c081ad5 100644 --- a/ddebug/error.cpp +++ b/ddebug/error.cpp @@ -66,20 +66,17 @@ #include #include +#include +#include -#include -#include - -#include "mono.h" -#include "pserror.h" #include "debug.h" -#include "application.h" +#include "pserror.h" #define MAX_MSG_LEN 2000 // Debug break chain handlers -void (*DebugBreak_callback_stop)() = NULL; -void (*DebugBreak_callback_resume)() = NULL; +void (*DebugBreak_callback_stop)() = nullptr; +void (*DebugBreak_callback_resume)() = nullptr; // library initialized flag static bool Error_initialized = false; @@ -115,17 +112,16 @@ bool error_Init(bool debugger, const char *app_title) { // exits the application and prints out a standard error message void Error(const char *fmt, ...) { std::va_list arglist; - int exit_msg_len; strcpy(Exit_message, "Error: "); va_start(arglist, fmt); - exit_msg_len = strlen(Exit_message); + size_t exit_msg_len = strlen(Exit_message); std::vsnprintf(Exit_message + exit_msg_len, MAX_MSG_LEN - exit_msg_len, fmt, arglist); va_end(arglist); snprintf(Exit_title_str, sizeof(Exit_title_str), "%s Error", App_title); - mprintf(0, "%s\n", Exit_message); + LOG_ERROR.printf("%s", Exit_message); #ifdef _DEBUG int answer = IDOK; @@ -141,7 +137,7 @@ void Error(const char *fmt, ...) { switch (answer) { case IDRETRY: - debug_break(); // Step Out of this function to see where Error() was called + SDL_TriggerBreakpoint(); // Step Out of this function to see where Error() was called // fall into ignore/cancel case case IDIGNORE: case IDCANCEL: @@ -162,7 +158,7 @@ void Error(const char *fmt, ...) { #endif // Clear the DEBUG_BREAK() callbacks - SetDebugBreakHandlers(NULL, NULL); + SetDebugBreakHandlers(nullptr, nullptr); // Leave the program exit(0); @@ -175,7 +171,7 @@ void Int3MessageBox(const char *file, int line) { int answer; snprintf(title, sizeof(title), "%s Debug Break", App_title); - snprintf(message, sizeof(message), "Int3 in %s at line %d.", file, line); + snprintf(message, sizeof(message), "Int3 in %s:%d.", file, line); if (DebugBreak_callback_stop) (*DebugBreak_callback_stop)(); @@ -183,7 +179,7 @@ void Int3MessageBox(const char *file, int line) { answer = Debug_ErrorBox(OSMBOX_YESNO, title, message, "It's probably safe to continue. Continue?"); if (answer == IDNO) { - SetDebugBreakHandlers(NULL, NULL); + SetDebugBreakHandlers(nullptr, nullptr); exit(1); } @@ -207,7 +203,7 @@ void AssertionFailed(const char *expstr, const char *file, int line) { answer = Debug_ErrorBox(OSMBOX_YESNO, title, message, "Continue?"); if (answer == IDNO) { - SetDebugBreakHandlers(NULL, NULL); + SetDebugBreakHandlers(nullptr, nullptr); exit(1); } diff --git a/ddebug/lnxdebug.cpp b/ddebug/lnxdebug.cpp index 20afb47f..4541f3b2 100644 --- a/ddebug/lnxdebug.cpp +++ b/ddebug/lnxdebug.cpp @@ -39,6 +39,7 @@ */ #include +#include #include "debug.h" @@ -50,9 +51,9 @@ int Debug_ErrorBox(int type, const char *topstring, const char *title, const char *bottomstring) { int answer = 0; - fprintf(stderr, "\n%s(%s)\n\n%s\n\n%s\n", title, topstring, "System Error", bottomstring); + fprintf(stderr, "\n%s (%s)\n\n%s\n\n%s\n", topstring, title, "System Error", bottomstring); - debug_break(); + SDL_TriggerBreakpoint(); return answer; } diff --git a/ddebug/pserror.h b/ddebug/pserror.h index c6e24349..dfc3a084 100644 --- a/ddebug/pserror.h +++ b/ddebug/pserror.h @@ -148,9 +148,11 @@ #ifndef PSERROR_H #define PSERROR_H -#include + +#include + #include "debug.h" -#include "mono.h" +#include "log.h" // initializes error handler. bool error_Init(bool debugger, const char *app_title); @@ -161,10 +163,12 @@ void AssertionFailed(const char *expstr, const char *file, int line); // Brings up an error message for an int3 void Int3MessageBox(const char *file, int line); // Message box functions + #define MBOX_OK 1 #define MBOX_YESNO 2 #define MBOX_YESNOCANCEL 3 #define MBOX_ABORTRETRYIGNORE 4 + // prints out a standard OS messagebox void OutrageMessageBox(const char *str, ...); int OutrageMessageBox(int type, const char *str, ...); @@ -172,6 +176,7 @@ int OutrageMessageBox(int type, const char *str, ...); void SetMessageBoxTitle(const char *title); // Write a block of text to the system clipboard void DumpTextToClipboard(char *text); + ////////////////////////////////////////////////////////////////////////////// // development debugging functions // adds a function to be called when a debug break occurs. @@ -179,69 +184,60 @@ void DumpTextToClipboard(char *text); #ifdef ASSERT #undef ASSERT #endif + // this callback is invoked when a DEBUG_BREAK macro is used. // arguments // style = 1 if ASSERT // = 0 if Int3 debugger break. extern void (*DebugBreak_callback_stop)(); extern void (*DebugBreak_callback_resume)(); + // set DEBUG_BREAK callback static inline void SetDebugBreakHandlers(void (*stop)(), void (*resume)()) { DebugBreak_callback_stop = stop; DebugBreak_callback_resume = resume; } -// DEBUG_BREAK() -// Calls the debug_break() macro surrounded by calls to the debug callbacks (to turn off & on graphics) -// ASSERT() -// Like the standard C assert(), but if the condition failed and debugging on, -// does a DEBUG_BREAK(). If debugging on, brings up a dialog. -// Int3() -// Does a DEBUG_BREAK() if debugging is turned on. Also does an mprintf(). -// Define the macros + #ifndef RELEASE #include +// Calls the SDL_assert(false) macro surrounded by calls to the debug callbacks (to turn off & on graphics) #define DEBUG_BREAK() \ do { \ if (DebugBreak_callback_stop) \ (*DebugBreak_callback_stop)(); \ - debug_break(); \ + SDL_assert(false); \ if (DebugBreak_callback_resume) \ (*DebugBreak_callback_resume)(); \ } while (0) +// Does a DEBUG_BREAK() if debugging is turned on. #define Int3() \ do { \ - mprintf(0, "Int3 at %s line %d.\n", __FILE__, __LINE__); \ - if (Debug_break) \ - DEBUG_BREAK(); \ - else \ - Int3MessageBox(__FILE__, __LINE__); \ + LOG_ERROR.printf("Int3 at %s:%d.", __FILE__, __LINE__); \ + DEBUG_BREAK(); \ + } while (0) + +// Like the standard C assert(), but if the condition failed and debugging on does a SDL_assert() with debug window. +#define ASSERT(x) \ + do { \ + if (!(x)) { \ + LOG_ERROR.printf("Assertion failed (%s) in %s:%d.", #x, __FILE__, __LINE__); \ + SDL_assert(x); \ + } \ } while (0) #if defined(WIN32) -#define ASSERT(x) \ - do { \ - if (!(x)) { \ - mprintf(0, "Assertion failed (%s) in %s line %d.\n", #x, __FILE__, __LINE__); \ - if (Debug_break) \ - DEBUG_BREAK(); \ - else \ - AssertionFailed(#x, __FILE__, __LINE__); \ - } \ - } while (0) #define HEAPCHECK() \ do { \ if (_heapchk() != _HEAPOK) \ Int3(); \ } while (0) + #elif defined(POSIX) -#include - -#define ASSERT(x) SDL_assert(x) #define HEAPCHECK() #endif diff --git a/ddebug/windebug.cpp b/ddebug/windebug.cpp index e5396bfe..75ebc04c 100644 --- a/ddebug/windebug.cpp +++ b/ddebug/windebug.cpp @@ -217,7 +217,7 @@ int Debug_ErrorBox(int type, const char *title, const char *topstring, const cha else if (type == OSMBOX_OKCANCEL) flags = MB_OKCANCEL; else - debug_break(); + DEBUG_BREAK(); char *tmpbuf = mem_rmalloc(strlen(topstring) + strlen(bottomstring) + 5); wsprintf(tmpbuf, "%s\r\n\r\n%s", topstring, bottomstring); diff --git a/win32/winapp.cpp b/win32/winapp.cpp index 21163e4e..2ddbf516 100644 --- a/win32/winapp.cpp +++ b/win32/winapp.cpp @@ -149,9 +149,9 @@ #include "Application.h" #include "AppConsole.h" -#include "debugbreak.h" #include "log.h" #include "networking.h" +#include "pserror.h" #include #include @@ -639,7 +639,7 @@ LRESULT WINAPI MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (Win32_AppObjects[i].hWnd == NULL) break; if (i == MAX_WIN32APPS) - debug_break(); + Int3(); Win32_AppObjects[i].hWnd = hWnd; Win32_AppObjects[i].app = (oeWin32Application *)lpCreateStruct->lpCreateParams;