From d0464ef602976a9b9575835b6d849ec0052bb96c Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Sun, 2 Feb 2025 18:06:18 +0300 Subject: [PATCH] engine: platform: posix: use glibc-based backtrace implementation for crash handling, if execinfo.h can be found --- engine/platform/posix/crash_glibc.c | 82 +++++++++++++++++++++++++++++ engine/platform/posix/crash_posix.c | 11 ++-- engine/wscript | 2 + 3 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 engine/platform/posix/crash_glibc.c diff --git a/engine/platform/posix/crash_glibc.c b/engine/platform/posix/crash_glibc.c new file mode 100644 index 00000000..7e518b91 --- /dev/null +++ b/engine/platform/posix/crash_glibc.c @@ -0,0 +1,82 @@ +/* +crashhandler.c - advanced crashhandler +Copyright (C) 2016 Mittorn + +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. +*/ + +// on Glibc (which potentially might not be only Linux) systems we +// have backtrace() and backtrace_symbols() calls, which replace for us +// platform-specific code +#if HAVE_EXECINFO +#include "common.h" +#include +#include + +void Sys_Crash( int signal, siginfo_t *si, void *context ) +{ + char message[8192]; + int len, logfd, i = 0; + int size; + void *addrs[16]; + char **syms; + + // safe actions first, stack and memory may be corrupted + len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n", + Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() ); + +#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD + len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr ); +#else + len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr ); +#endif + + write( STDERR_FILENO, message, len ); + + // flush buffers before writing directly to descriptors + fflush( stdout ); + fflush( stderr ); + + // now get log fd and write trace directly to log + logfd = Sys_LogFileNo(); + write( logfd, message, len ); + + size = backtrace( addrs, sizeof( addrs ) / sizeof( addrs[0] )); + syms = backtrace_symbols( addrs, size ); + + for( i = 0; i < size && syms; i++ ) + { + size_t symlen = Q_strlen( syms[i] ); + char ch = '\n'; + + write( logfd, syms[i], symlen ); + write( logfd, &ch, 1 ); + + len += Q_snprintf( message + len, sizeof( message ) - len, "%2d: %s\n", i, syms[i] ); + } + + // put MessageBox as Sys_Error + Msg( "%s\n", message ); +#ifdef XASH_SDL + SDL_SetWindowGrab( host.hWnd, SDL_FALSE ); +#endif + host.crashed = true; + Platform_MessageBox( "Xash Error", message, false ); + + // log saved, now we can try to save configs and close log correctly, it may crash + if( host.type == HOST_NORMAL ) + CL_Crashed(); + host.status = HOST_CRASHED; + + Sys_Quit( "crashed" ); +} + +#endif // HAVE_EXECINFO diff --git a/engine/platform/posix/crash_posix.c b/engine/platform/posix/crash_posix.c index cd90641b..764440ab 100644 --- a/engine/platform/posix/crash_posix.c +++ b/engine/platform/posix/crash_posix.c @@ -26,6 +26,11 @@ GNU General Public License for more details. #include #include "library.h" +void Sys_Crash( int signal, siginfo_t *si, void *context ); +static struct sigaction oldFilter; + +#if !HAVE_EXECINFO + #define STACK_BACKTRACE_STR "Stack backtrace:\n" #define STACK_DUMP_STR "Stack dump:\n" @@ -33,8 +38,6 @@ GNU General Public License for more details. #define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 ) #define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 )) -static struct sigaction oldFilter; - static int Sys_PrintFrame( char *buf, int len, int i, void *addr ) { Dl_info dlinfo; @@ -53,7 +56,7 @@ static int Sys_PrintFrame( char *buf, int len, int i, void *addr ) return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address } -static void Sys_Crash( int signal, siginfo_t *si, void *context) +void Sys_Crash( int signal, siginfo_t *si, void *context ) { void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS! char message[8192]; @@ -200,6 +203,8 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context) Sys_Quit( "crashed" ); } +#endif // !HAVE_EXECINFO + void Sys_SetupCrashHandler( void ) { struct sigaction act = { 0 }; diff --git a/engine/wscript b/engine/wscript index 7dd829f0..1099b39f 100644 --- a/engine/wscript +++ b/engine/wscript @@ -111,6 +111,8 @@ def configure(conf): if hasattr(conf.options, 'DLLEMU'): conf.define_cond('XASH_DLL_LOADER', conf.options.DLLEMU) + conf.check_cc(header_name='execinfo.h', mandatory=False, define_name='HAVE_EXECINFO') + conf.define('ENGINE_DLL', 1) conf.define_cond('XASH_ENGINE_TESTS', conf.options.ENGINE_TESTS) conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)