engine: platform: posix: use glibc-based backtrace implementation for crash handling, if execinfo.h can be found
This commit is contained in:
parent
c3ebb84b97
commit
d0464ef602
3 changed files with 92 additions and 3 deletions
82
engine/platform/posix/crash_glibc.c
Normal file
82
engine/platform/posix/crash_glibc.c
Normal file
|
@ -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 <execinfo.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
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
|
|
@ -26,6 +26,11 @@ GNU General Public License for more details.
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include "library.h"
|
#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_BACKTRACE_STR "Stack backtrace:\n"
|
||||||
#define STACK_DUMP_STR "Stack dump:\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 STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
|
||||||
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 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 )
|
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
|
||||||
{
|
{
|
||||||
Dl_info dlinfo;
|
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
|
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!
|
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
|
||||||
char message[8192];
|
char message[8192];
|
||||||
|
@ -200,6 +203,8 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||||
Sys_Quit( "crashed" );
|
Sys_Quit( "crashed" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !HAVE_EXECINFO
|
||||||
|
|
||||||
void Sys_SetupCrashHandler( void )
|
void Sys_SetupCrashHandler( void )
|
||||||
{
|
{
|
||||||
struct sigaction act = { 0 };
|
struct sigaction act = { 0 };
|
||||||
|
|
|
@ -111,6 +111,8 @@ def configure(conf):
|
||||||
if hasattr(conf.options, 'DLLEMU'):
|
if hasattr(conf.options, 'DLLEMU'):
|
||||||
conf.define_cond('XASH_DLL_LOADER', 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('ENGINE_DLL', 1)
|
||||||
conf.define_cond('XASH_ENGINE_TESTS', conf.options.ENGINE_TESTS)
|
conf.define_cond('XASH_ENGINE_TESTS', conf.options.ENGINE_TESTS)
|
||||||
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
|
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
|
||||||
|
|
Loading…
Add table
Reference in a new issue