engine: platform: posix: remove old crashhandler as libbacktrace supports much more targets, remove duplicated code around execinfo and libbacktrace-based crashhandlers

Update copyright headers.
This commit is contained in:
Alibek Omarov
2025-07-29 08:09:03 +05:00
parent b3d3a15c3d
commit 25e206f5ae
4 changed files with 74 additions and 239 deletions

View File

@@ -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 );

View File

@@ -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 <signal.h>
#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

View File

@@ -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 )

View File

@@ -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 <sys/mman.h>
#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 );