From 25e206f5aea6472d2acb1acf62067c0f39d30aaa Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Tue, 29 Jul 2025 08:09:03 +0500 Subject: [PATCH] engine: platform: posix: remove old crashhandler as libbacktrace supports much more targets, remove duplicated code around execinfo and libbacktrace-based crashhandlers Update copyright headers. --- engine/platform/posix/crash.h | 25 +++ engine/platform/posix/crash_glibc.c | 56 ++----- engine/platform/posix/crash_libbacktrace.c | 56 ++----- engine/platform/posix/crash_posix.c | 176 ++++----------------- 4 files changed, 74 insertions(+), 239 deletions(-) create mode 100644 engine/platform/posix/crash.h diff --git a/engine/platform/posix/crash.h b/engine/platform/posix/crash.h new file mode 100644 index 00000000..69f86f19 --- /dev/null +++ b/engine/platform/posix/crash.h @@ -0,0 +1,25 @@ +/* +crash.h - 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. +*/ + +// +// crash_libbacktrace.c +// +int Sys_CrashDetailsLibbacktrace( int logfd, char *message, int len, size_t max_len ); +qboolean Sys_SetupLibbacktrace( const char *argv0 ); + +// +// crash_glibc.c +// +int Sys_CrashDetailsExecinfo( int logfd, char *message, int len, size_t max_len ); diff --git a/engine/platform/posix/crash_glibc.c b/engine/platform/posix/crash_glibc.c index c950056a..6805caf4 100644 --- a/engine/platform/posix/crash_glibc.c +++ b/engine/platform/posix/crash_glibc.c @@ -1,6 +1,7 @@ /* -crashhandler.c - advanced crashhandler +crash_glibc.c - advanced crashhandler based on glibc's execinfo API Copyright (C) 2016 Mittorn +Copyright (C) 2025 Alibek Omarov 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 @@ -21,41 +22,15 @@ GNU General Public License for more details. #include #include "common.h" #include "input.h" +#include "crash.h" -void Sys_Crash( int signal, siginfo_t *si, void *context ) +int Sys_CrashDetailsExecinfo( int logfd, char *message, int len, size_t max_len ) { - char message[8192]; - int len, logfd, i = 0; - int size; void *addrs[16]; - char **syms; + int size = backtrace( addrs, sizeof( addrs ) / sizeof( addrs[0] )); + char **syms = backtrace_symbols( addrs, size ); - (void)context; - - // flush buffers before writing directly to descriptors - fflush( stdout ); - fflush( stderr ); - - // 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-%s)\n", - Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() ); - -#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD && !XASH_APPLE // they don't have si_ptr - 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 ); - - // 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++ ) + for( int i = 0; i < size && syms; i++ ) { size_t symlen = Q_strlen( syms[i] ); char ch = '\n'; @@ -66,22 +41,9 @@ void Sys_Crash( int signal, siginfo_t *si, void *context ) write( STDERR_FILENO, syms[i], symlen ); write( STDERR_FILENO, &ch, 1 ); - len += Q_snprintf( message + len, sizeof( message ) - len, "%2d: %s\n", i, syms[i] ); + len += Q_snprintf( message + len, max_len - len, "%2d: %s\n", i, syms[i] ); } - // put MessageBox as Sys_Error - Msg( "%s\n", message ); -#if !XASH_DEDICATED - IN_SetMouseGrab( false ); -#endif - host.status = HOST_CRASHED; - 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(); - - Sys_Quit( "crashed" ); + return len; } - #endif // HAVE_EXECINFO diff --git a/engine/platform/posix/crash_libbacktrace.c b/engine/platform/posix/crash_libbacktrace.c index f8ce6f82..d1a466f4 100644 --- a/engine/platform/posix/crash_libbacktrace.c +++ b/engine/platform/posix/crash_libbacktrace.c @@ -1,6 +1,7 @@ /* -crashhandler.c - advanced crashhandler +crash_libbacktrace.c - advanced crashhandler based on libbacktrace Copyright (C) 2016 Mittorn +Copyright (C) 2025 Alibek Omarov 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 @@ -18,6 +19,7 @@ GNU General Public License for more details. #include "common.h" #include "backtrace.h" #include "input.h" +#include "crash.h" static struct backtrace_state *g_bt_state; static qboolean enable_libbacktrace; @@ -128,53 +130,19 @@ static int Sys_BacktracePrintFull( void *data, uintptr_t pc, const char *filenam return 0; } -void Sys_CrashLibbacktrace( int signal, siginfo_t *si, void *context ) +int Sys_CrashDetailsLibbacktrace( int logfd, char *message, int len, size_t max_len ) { - char message[8192]; - int len, logfd; - struct print_data pd = { .idx = 0 }; - - (void)context; - - // flush buffers before writing directly to descriptors - fflush( stdout ); - fflush( stderr ); - - // 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-%s)\n", - Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() ); - -#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD && !XASH_APPLE // they don't have si_ptr - 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 ); - - // now get log fd and write trace directly to log - pd.logfd = logfd = Sys_LogFileNo(); - write( logfd, message, len ); - - pd.message = message + len; - pd.message_size = sizeof( message ) - len; - pd.len = 0; + struct print_data pd = + { + .message = message + len, + .message_size = sizeof( message ) - len, + .logfd = logfd, + .len = len, + }; backtrace_full( g_bt_state, 1, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd ); - // put MessageBox as Sys_Error - Msg( "%s\n", message ); -#if !XASH_DEDICATED - IN_SetMouseGrab( false ); -#endif - host.status = HOST_CRASHED; - 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(); - - Sys_Quit( "crashed" ); + return pd.len; } qboolean Sys_SetupLibbacktrace( const char *argv0 ) diff --git a/engine/platform/posix/crash_posix.c b/engine/platform/posix/crash_posix.c index b461dbf1..615f2bc2 100644 --- a/engine/platform/posix/crash_posix.c +++ b/engine/platform/posix/crash_posix.c @@ -1,5 +1,5 @@ /* -crashhandler.c - advanced crashhandler +crash_posix.c - advanced crashhandler Copyright (C) 2016 Mittorn This program is free software: you can redistribute it and/or modify @@ -27,101 +27,22 @@ GNU General Public License for more details. #include #include "library.h" #include "input.h" +#include "crash.h" + +static qboolean have_libbacktrace = false; -void Sys_Crash( int signal, siginfo_t *si, void *context ); -void Sys_CrashLibbacktrace( int signal, siginfo_t *si, void *context ); -qboolean Sys_SetupLibbacktrace( const char *argv0 ); static struct sigaction oldFilter; -#if !HAVE_EXECINFO - -#define STACK_BACKTRACE_STR "Stack backtrace:\n" -#define STACK_DUMP_STR "Stack dump:\n" - -#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 ) -#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 ) -#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 )) - -static int Sys_PrintFrame( char *buf, int len, int i, void *addr ) +static void Sys_Crash( int signal, siginfo_t *si, void *context ) { - Dl_info dlinfo; - if( len <= 0 ) - return 0; // overflow - - if( dladdr( addr, &dlinfo )) - { - if( dlinfo.dli_sname ) - return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname, - (unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address - - return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address - } - - return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address -} - -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]; int len, logfd, i = 0; - -#if XASH_OPENBSD - struct sigcontext *ucontext = (struct sigcontext*)context; -#else - ucontext_t *ucontext = (ucontext_t*)context; -#endif + qboolean detailed_message = false; // flush buffers before writing directly to descriptors fflush( stdout ); fflush( stderr ); -#if XASH_AMD64 -#if XASH_FREEBSD - pc = (void*)ucontext->uc_mcontext.mc_rip; - bp = (void**)ucontext->uc_mcontext.mc_rbp; - sp = (void**)ucontext->uc_mcontext.mc_rsp; -#elif XASH_NETBSD - pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP]; - bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP]; - sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP]; -#elif XASH_OPENBSD - pc = (void*)ucontext->sc_rip; - bp = (void**)ucontext->sc_rbp; - sp = (void**)ucontext->sc_rsp; -#else - pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; - bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; - sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP]; -#endif -#elif XASH_X86 -#if XASH_FREEBSD - pc = (void*)ucontext->uc_mcontext.mc_eip; - bp = (void**)ucontext->uc_mcontext.mc_ebp; - sp = (void**)ucontext->uc_mcontext.mc_esp; -#elif XASH_NETBSD - pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP]; - bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP]; - sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP]; -#elif XASH_OPENBSD - pc = (void*)ucontext->sc_eip; - bp = (void**)ucontext->sc_ebp; - sp = (void**)ucontext->sc_esp; -#else - pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; - bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; - sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP]; -#endif -#elif XASH_ARM && XASH_64BIT - pc = (void*)ucontext->uc_mcontext.pc; - bp = (void*)ucontext->uc_mcontext.regs[29]; - sp = (void*)ucontext->uc_mcontext.sp; -#elif XASH_ARM - pc = (void*)ucontext->uc_mcontext.arm_pc; - bp = (void*)ucontext->uc_mcontext.arm_fp; - sp = (void*)ucontext->uc_mcontext.arm_sp; -#endif - // 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-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() ); @@ -138,58 +59,21 @@ void Sys_Crash( int signal, siginfo_t *si, void *context ) logfd = Sys_LogFileNo(); write( logfd, message, len ); - if( pc && bp && sp ) +#if HAVE_LIBBACKTRACE + if( have_libbacktrace && !detailed_message ) { - size_t pagesize = sysconf( _SC_PAGESIZE ); - - // try to print backtrace - write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN ); - write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN ); - Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len ); - len += STACK_BACKTRACE_STR_LEN; - - // false on success, true on failure -#define try_allow_read(pointer, pagesize) \ - (( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1 ) && \ - ( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1 ) && \ - ( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1 ) && \ - ( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1 )) - - do - { - int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc); - write( STDERR_FILENO, message + len, line ); - write( logfd, message + len, line ); - len += line; - //if( !dladdr(bp,0) ) break; // only when bp is in module - if( try_allow_read( bp, pagesize ) ) - break; - if( try_allow_read( bp[0], pagesize ) ) - break; - pc = bp[1]; - bp = (void**)bp[0]; - } - while( bp && i < 128 ); - - // try to print stack - write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN ); - write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN ); - Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len ); - len += STACK_DUMP_STR_LEN; - - if( !try_allow_read( sp, pagesize ) ) - { - for( i = 0; i < 32; i++ ) - { - int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] ); - write( STDERR_FILENO, message + len, line ); - write( logfd, message + len, line ); - len += line; - } - } - -#undef try_allow_read + len = Sys_CrashDetailsLibbacktrace( logfd, message, len, sizeof( message )); + detailed_message = true; } +#endif // HAVE_LIBBACKTRACE + +#if HAVE_EXECINFO + if( !detailed_message ) + { + len = Sys_CrashDetailsExecinfo( logfd, message, len, sizeof( message )); + detailed_message = true; + } +#endif // HAVE_EXECINFO // put MessageBox as Sys_Error Msg( "%s\n", message ); @@ -206,22 +90,18 @@ void Sys_Crash( int signal, siginfo_t *si, void *context ) Sys_Quit( "crashed" ); } -#endif // !HAVE_EXECINFO - void Sys_SetupCrashHandler( const char *argv0 ) { - struct sigaction act = { 0 }; + struct sigaction act = + { + .sa_sigaction = Sys_Crash, + .sa_flags = SA_SIGINFO | SA_ONSTACK, + }; + #if HAVE_LIBBACKTRACE - if( Sys_SetupLibbacktrace( argv0 )) - { - act.sa_sigaction = Sys_CrashLibbacktrace; - } - else -#endif - { - act.sa_sigaction = Sys_Crash; - } - act.sa_flags = SA_SIGINFO | SA_ONSTACK; + have_libbacktrace = Sys_SetupLibbacktrace( argv0 ); +#endif // HAVE_LIBBACKTRACE + sigaction( SIGSEGV, &act, &oldFilter ); sigaction( SIGABRT, &act, &oldFilter ); sigaction( SIGBUS, &act, &oldFilter );