@ -12,6 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
GNU General Public License for more details .
*/
*/
# define _GNU_SOURCE
# include "common.h"
# include "common.h"
@ -186,7 +187,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
long _stdcall Sys_Crash ( PEXCEPTION_POINTERS pInfo )
long _stdcall Sys_Crash ( PEXCEPTION_POINTERS pInfo )
{
{
// save config
// save config
if ( host . state ! = HOST_CRASHED )
if ( host . status ! = HOST_CRASHED )
{
{
// check to avoid recursive call
// check to avoid recursive call
host . crashed = true ;
host . crashed = true ;
@ -199,7 +200,7 @@ long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
if ( host . type = = HOST_NORMAL )
if ( host . type = = HOST_NORMAL )
CL_Crashed ( ) ; // tell client about crash
CL_Crashed ( ) ; // tell client about crash
else host . state = HOST_CRASHED ;
else host . status = HOST_CRASHED ;
if ( host . developer < = 0 )
if ( host . developer < = 0 )
{
{
@ -232,139 +233,187 @@ void Sys_RestoreCrashHandler( void )
# elif XASH_CRASHHANDLER == CRASHHANDLER_UCONTEXT
# elif XASH_CRASHHANDLER == CRASHHANDLER_UCONTEXT
// Posix signal handler
// Posix signal handler
# include "library.h"
# include "library.h"
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined __ANDROID__
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || defined(__linux__)
# define HAVE_UCONTEXT_H 1
# define HAVE_UCONTEXT_H 1
# endif
# endif
# ifdef HAVE_UCONTEXT_H
# ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
# include <ucontext.h>
# endif
# endif
# include <signal.h>
# include <sys/mman.h>
# include <sys/mman.h>
int printframe ( char * buf , int len , int i , void * addr )
int printframe ( char * buf , int len , int i , void * addr )
{
{
Dl_info dlinfo ;
Dl_info dlinfo ;
if ( len < = 0 ) return 0 ; // overflow
if ( len < = 0 )
return 0 ; // overflow
if ( dladdr ( addr , & dlinfo ) )
if ( dladdr ( addr , & dlinfo ) )
{
{
if ( dlinfo . dli_sname )
if ( dlinfo . dli_sname )
return Q_snprintf ( buf , len , " % 2d: %p <%s+%lu> (%s) \n " , i , addr , 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
( unsigned long ) addr - ( unsigned long ) dlinfo . dli_saddr , dlinfo . dli_fname ) ; // print symbol, module and address
else
else
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 (%s) \ n " , i, addr, dlinfo.dli_fname ) ; // print module and address
}
}
else
else
return Q_snprintf ( buf , len , " % 2d: %p \n " , i , addr ) ; // print only address
return Q_snprintf ( buf , len , " %2d: %p \n " , i , addr ) ; // print only address
}
}
struct sigaction oldFilter ;
struct sigaction oldFilter ;
# define STACK_BACKTRACE_STR_LEN 17
# define STACK_BACKTRACE_STR "Stack backtrace:\n"
# define STACK_DUMP_STR_LEN 12
# define STACK_DUMP_STR "Stack dump:\n"
# define ALIGN( x, y ) (((int) (x) + ((y)-1)) & ~((y)-1))
static void Sys_Crash ( int signal , siginfo_t * si , void * context )
static void Sys_Crash ( int signal , siginfo_t * si , void * context )
{
{
void * trace [ 32 ] ;
void * pc , * * bp , * * sp ; // this must be set for every OS!
char message [ 8192 ] ;
int len , logfd , i = 0 ;
size_t pagesize ;
char message [ 4096 ] , stackframe [ 256 ] ;
int len , stacklen , logfd , i = 0 ;
# if defined(__OpenBSD__)
# if defined(__OpenBSD__)
struct sigcontext * ucontext = ( struct sigcontext * ) context ;
struct sigcontext * ucontext = ( struct sigcontext * ) context ;
# else
# else
ucontext_t * ucontext = ( ucontext_t * ) context ;
ucontext_t * ucontext = ( ucontext_t * ) context ;
# endif
# endif
# if defined(__x86_64__)
# if defined(__x86_64__)
# if defined(__FreeBSD__)
# if defined(__FreeBSD__)
void * pc = ( void * ) ucontext - > uc_mcontext . mc_rip , * * bp = ( void * * ) ucontext - > uc_mcontext . mc_rbp , * * sp = ( void * * ) ucontext - > uc_mcontext . mc_rsp ;
pc = ( void * ) ucontext - > uc_mcontext . mc_rip ;
bp = ( void * * ) ucontext - > uc_mcontext . mc_rbp ;
sp = ( void * * ) ucontext - > uc_mcontext . mc_rsp ;
# elif defined(__NetBSD__)
# elif defined(__NetBSD__)
void * pc = ( void * ) ucontext - > uc_mcontext . __gregs [ REG_RIP ] , * * bp = ( void * * ) ucontext - > uc_mcontext . __gregs [ REG_RBP ] , * * sp = ( void * * ) ucontext - > uc_mcontext . __gregs [ REG_RSP ] ;
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 defined(__OpenBSD__)
# elif defined(__OpenBSD__)
void * pc = ( void * ) ucontext - > sc_rip , * * bp = ( void * * ) ucontext - > sc_rbp , * * sp = ( void * * ) ucontext - > sc_rsp ;
pc = ( void * ) ucontext - > sc_rip ;
bp = ( void * * ) ucontext - > sc_rbp ;
sp = ( void * * ) ucontext - > sc_rsp ;
# else
# else
void * pc = ( void * ) ucontext - > uc_mcontext . gregs [ REG_RIP ] , * * bp = ( void * * ) ucontext - > uc_mcontext . gregs [ REG_RBP ] , * * sp = ( void * * ) ucontext - > uc_mcontext . gregs [ REG_RSP ] ;
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
# endif
# elif defined(__i386__)
# elif defined(__i386__)
# if defined(__FreeBSD__)
# if defined(__FreeBSD__)
void * pc = ( void * ) ucontext - > uc_mcontext . mc_eip , * * bp = ( void * * ) ucontext - > uc_mcontext . mc_ebp , * * sp = ( void * * ) ucontext - > uc_mcontext . mc_esp ;
pc = ( void * ) ucontext - > uc_mcontext . mc_eip ;
bp = ( void * * ) ucontext - > uc_mcontext . mc_ebp ;
sp = ( void * * ) ucontext - > uc_mcontext . mc_esp ;
# elif defined(__NetBSD__)
# elif defined(__NetBSD__)
void * pc = ( void * ) ucontext - > uc_mcontext . __gregs [ REG_EIP ] , * * bp = ( void * * ) ucontext - > uc_mcontext . __gregs [ REG_EBP ] , * * sp = ( void * * ) ucontext - > uc_mcontext . __gregs [ REG_ESP ] ;
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 defined(__OpenBSD__)
# elif defined(__OpenBSD__)
void * pc = ( void * ) ucontext - > sc_eip , * * bp = ( void * * ) ucontext - > sc_ebp , * * sp = ( void * * ) ucontext - > sc_esp ;
pc = ( void * ) ucontext - > sc_eip ;
bp = ( void * * ) ucontext - > sc_ebp ;
sp = ( void * * ) ucontext - > sc_esp ;
# else
# else
void * pc = ( void * ) ucontext - > uc_mcontext . gregs [ REG_EIP ] , * * bp = ( void * * ) ucontext - > uc_mcontext . gregs [ REG_EBP ] , * * sp = ( void * * ) ucontext - > uc_mcontext . gregs [ REG_ESP ] ;
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
# endif
# elif defined(__aarch64__) // arm not tested
# elif defined(__aarch64__) // arm not tested
void * pc = ( void * ) ucontext - > uc_mcontext . pc , * * bp = ( void * ) ucontext - > uc_mcontext . regs [ 29 ] , * * sp = ( void * ) ucontext - > uc_mcontext . sp ;
pc = ( void * ) ucontext - > uc_mcontext . pc ;
bp = ( void * ) ucontext - > uc_mcontext . regs [ 29 ] ;
sp = ( void * ) ucontext - > uc_mcontext . sp ;
# elif defined(__arm__)
# elif defined(__arm__)
void * pc = ( void * ) ucontext - > uc_mcontext . arm_pc , * * bp = ( void * ) ucontext - > uc_mcontext . arm_fp , * * sp = ( void * ) ucontext - > uc_mcontext . arm_sp ;
pc = ( void * ) ucontext - > uc_mcontext . arm_pc ;
bp = ( void * ) ucontext - > uc_mcontext . arm_fp ;
sp = ( void * ) ucontext - > uc_mcontext . arm_sp ;
# else
# else
# error "Unknown arch!!!"
# error "Unknown arch!!!"
# endif
# endif
// Safe actions first, stack and memory may be corrupted
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
// safe actions first, stack and memory may be corrupted
len = Q_snprintf ( message , 4096 , " Sys_Crash: signal %d, err %d with code %d at %p \n " , signal , si - > si_errno , si - > si_code , si - > si_addr ) ;
len = Q_snprintf ( message , sizeof ( message ) , " Ver: %s %s (build %i-%s, %s-%s) \n " ,
# else
XASH_ENGINE_NAME , XASH_VERSION , Q_buildnum ( ) , Q_buildcommit ( ) , Q_buildos ( ) , Q_buildarch ( ) ) ;
len = Q_snprintf ( message , 4096 , " Sys_Crash: signal %d, err %d with code %d at %p %p \n " , signal , si - > si_errno , si - > si_code , si - > si_addr , si - > si_ptr ) ;
# endif
# if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
write ( 2 , message , len ) ;
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 ) ;
// Flush buffers before writing directly to descriptors
# 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 ( 2 , message , len ) ;
// flush buffers before writing directly to descriptors
fflush ( stdout ) ;
fflush ( stdout ) ;
fflush ( stderr ) ;
fflush ( stderr ) ;
// Now get log fd and write trace directly to log
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo ( ) ;
logfd = Sys_LogFileNo ( ) ;
write ( logfd , message , len ) ;
write ( logfd , message , len ) ;
write ( 2 , " Stack backtrace: \n " , 17 ) ;
write ( logfd , " Stack backtrace: \n " , 17 ) ;
// try to print backtrace
strncpy ( message + len , " Stack backtrace: \n " , 4096 - len ) ;
write ( 2 , STACK_BACKTRACE_STR , STACK_BACKTRACE_STR_LEN ) ;
len + = 17 ;
write ( logfd , STACK_BACKTRACE_STR , STACK_BACKTRACE_STR_LEN ) ;
size_t pagesize = sysconf ( _SC_PAGESIZE ) ;
strncpy ( message + len , STACK_BACKTRACE_STR , sizeof ( message ) - len ) ;
len + = STACK_BACKTRACE_STR_LEN ;
pagesize = sysconf ( _SC_PAGESIZE ) ;
do
do
{
{
int line = printframe ( message + len , 4096 - len , + + i , pc ) ;
int line = printframe ( message + len , sizeof ( message ) - len , + + i , pc ) ;
write ( 2 , message + len , line ) ;
write ( 2 , message + len , line ) ;
write ( logfd , message + len , line ) ;
write ( logfd , message + len , line ) ;
len + = line ;
len + = line ;
//if( !dladdr(bp,0) ) break; // O nly when bp is in module
//if( !dladdr(bp,0) ) break; // o nly when bp is in module
if ( ( mprotect ( ( char * ) ( ( ( int ) bp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) = = - 1 ) & &
if ( ( mprotect ( ( char * ) ALIGN ( bp , pagesize ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ALIGN ( bp , pagesize ) , pagesize , PROT_READ | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE ) = = - 1 ) & &
( mprotect ( ( char * ) ALIGN ( bp , pagesize ) , pagesize , PROT_READ | PROT_WRITE ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ ) = = - 1 ) )
( mprotect ( ( char * ) ALIGN ( bp , pagesize ) , pagesize , PROT_READ ) = = - 1 ) )
break ;
break ;
if ( ( mprotect ( ( char * ) ( ( ( int ) bp [ 0 ] + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) = = - 1 ) & &
if ( ( mprotect ( ( char * ) ALIGN ( bp [ 0 ] , pagesize ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp [ 0 ] + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ALIGN ( bp [ 0 ] , pagesize ) , pagesize , PROT_READ | PROT_EXEC ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp [ 0 ] + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE ) = = - 1 ) & &
( mprotect ( ( char * ) ALIGN ( bp [ 0 ] , pagesize ) , pagesize , PROT_READ | PROT_WRITE ) = = - 1 ) & &
( mprotect ( ( char * ) ( ( ( int ) bp [ 0 ] + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ ) = = - 1 ) )
( mprotect ( ( char * ) ALIGN ( bp [ 0 ] , pagesize ) , pagesize , PROT_READ ) = = - 1 ) )
break ;
break ;
pc = bp [ 1 ] ;
pc = bp [ 1 ] ;
bp = ( void * * ) bp [ 0 ] ;
bp = ( void * * ) bp [ 0 ] ;
}
}
while ( bp & & i < 128 ) ;
while ( bp & & i < 128 ) ;
// Try to print stack
write ( 2 , " Stack dump: \n " , 12 ) ;
// try to print stack
write ( logfd , " Stack dump: \n " , 12 ) ;
write ( 2 , STACK_DUMP_STR , STACK_DUMP_STR_LEN ) ;
strncpy ( message + len , " Stack dump: \n " , 4096 - len ) ;
write ( logfd , STACK_DUMP_STR , STACK_DUMP_STR_LEN ) ;
strncpy ( message + len , STACK_DUMP_STR , sizeof ( message ) - len ) ;
len + = 12 ;
len + = STACK_DUMP_STR_LEN ;
if ( ( mprotect ( ( char * ) ( ( ( int ) sp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) ! = - 1 ) | |
( mprotect ( ( char * ) ( ( ( int ) sp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_EXEC ) ! = - 1 ) | |
if ( ( mprotect ( ( char * ) ALIGN ( sp , pagesize ) , pagesize , PROT_READ | PROT_WRITE | PROT_EXEC ) ! = - 1 ) | |
( mprotect ( ( char * ) ( ( ( int ) sp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ | PROT_WRITE ) ! = - 1 ) | |
( mprotect ( ( char * ) ALIGN ( sp , pagesize ) , pagesize , PROT_READ | PROT_EXEC ) ! = - 1 ) | |
( mprotect ( ( char * ) ( ( ( int ) sp + ( pagesize - 1 ) ) & ~ ( pagesize - 1 ) ) , pagesize , PROT_READ ) ! = - 1 ) )
( mprotect ( ( char * ) ALIGN ( sp , pagesize ) , pagesize , PROT_READ | PROT_WRITE ) ! = - 1 ) | |
( mprotect ( ( char * ) ALIGN ( sp , pagesize ) , pagesize , PROT_READ ) ! = - 1 ) )
{
for ( i = 0 ; i < 32 ; i + + )
for ( i = 0 ; i < 32 ; i + + )
{
{
int line = printframe ( message + len , 4096 - len , i , sp [ i ] ) ;
int line = printframe ( message + len , sizeof ( message ) - len , i , sp [ i ] ) ;
write ( 2 , message + len , line ) ;
write ( 2 , message + len , line ) ;
write ( logfd , message + len , line ) ;
write ( logfd , message + len , line ) ;
len + = line ;
len + = line ;
}
}
// Put MessageBox as Sys_Error
}
// put MessageBox as Sys_Error
Msg ( " %s \n " , message ) ;
Msg ( " %s \n " , message ) ;
# ifdef XASH_SDL
# ifdef XASH_SDL
SDL_SetWindowGrab ( host . hWnd , SDL_FALSE ) ;
SDL_SetWindowGrab ( host . hWnd , SDL_FALSE ) ;
# endif
# endif
MSGBOX ( message ) ;
MSGBOX ( message ) ;
// L og saved, now we can try to save configs and close log correctly, it may crash
// l og saved, now we can try to save configs and close log correctly, it may crash
if ( host . type = = HOST_NORMAL )
if ( host . type = = HOST_NORMAL )
CL_Crashed ( ) ;
CL_Crashed ( ) ;
host . state = HOST_CRASHED ;
host . status = HOST_CRASHED ;
host . crashed = true ;
host . crashed = true ;
Sys_Quit ( ) ;
Sys_Quit ( ) ;
@ -375,18 +424,18 @@ void Sys_SetupCrashHandler( void )
struct sigaction act ;
struct sigaction act ;
act . sa_sigaction = Sys_Crash ;
act . sa_sigaction = Sys_Crash ;
act . sa_flags = SA_SIGINFO | SA_ONSTACK ;
act . sa_flags = SA_SIGINFO | SA_ONSTACK ;
sigaction ( SIGSEGV , & act , & oldFilter ) ;
sigaction ( SIGSEGV , & act , & oldFilter ) ;
sigaction ( SIGABRT , & act , & oldFilter ) ;
sigaction ( SIGABRT , & act , & oldFilter ) ;
sigaction ( SIGBUS , & act , & oldFilter ) ;
sigaction ( SIGBUS , & act , & oldFilter ) ;
sigaction ( SIGILL , & act , & oldFilter ) ;
sigaction ( SIGILL , & act , & oldFilter ) ;
}
}
void Sys_RestoreCrashHandler ( void )
void Sys_RestoreCrashHandler ( void )
{
{
sigaction ( SIGSEGV , & oldFilter , NULL ) ;
sigaction ( SIGSEGV , & oldFilter , NULL ) ;
sigaction ( SIGABRT , & oldFilter , NULL ) ;
sigaction ( SIGABRT , & oldFilter , NULL ) ;
sigaction ( SIGBUS , & oldFilter , NULL ) ;
sigaction ( SIGBUS , & oldFilter , NULL ) ;
sigaction ( SIGILL , & oldFilter , NULL ) ;
sigaction ( SIGILL , & oldFilter , NULL ) ;
}
}
# elif XASH_CRASHHANDLER == CRASHHANDLER_NULL
# elif XASH_CRASHHANDLER == CRASHHANDLER_NULL