您需要通过捕获SIGSEGV来执行代码,以便在出现segv时执行。这是posix代码,因此类似的代码应该也适用于Android:
void abortHandler( int signum, siginfo_t* si, void* unused )
{
const char* name = NULL;
switch( signum )
{
case SIGABRT: name = "SIGABRT"; break;
case SIGSEGV: name = "SIGSEGV"; break;
case SIGBUS: name = "SIGBUS"; break;
case SIGILL: name = "SIGILL"; break;
case SIGFPE: name = "SIGFPE"; break;
case SIGPIPE: name = "SIGPIPE"; break;
}
if ( name )
printf( stderr, "Caught signal %d (%s)\n", signum, name );
else
printf( stderr, "Caught signal %d\n", signum );
printStackTrace( stderr );
exit( signum );
}
void handleCrashes()
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = abortHandler;
sigemptyset( &sa.sa_mask );
sigaction( SIGABRT, &sa, NULL );
sigaction( SIGSEGV, &sa, NULL );
sigaction( SIGBUS, &sa, NULL );
sigaction( SIGILL, &sa, NULL );
sigaction( SIGFPE, &sa, NULL );
sigaction( SIGPIPE, &sa, NULL );
}
下一步是调用该函数来注册信号处理程序。您可以在main函数中的第一件事情就这样做,但是那样的话,直到main函数才能获得堆栈跟踪。如果您想在此之前获得堆栈跟踪,可以从全局对象的构造函数中调用此函数。但是不能保证它将是第一个被调用的构造函数。有方法可以确保它早期被调用。例如,在调试版本中重载operator new,以便在第一次分配时首先初始化堆栈跟踪,然后调用真正的operator new。这将为您提供从第一次分配开始的堆栈跟踪。
要打印堆栈跟踪:
void printStackTrace( unsigned int max_frames = 63 )
{
void* addrlist[max_frames+1];
u32 addrlen = backtrace( addrlist, sizeof( addrlist ) / sizeof( void* ));
if ( addrlen == 0 )
{
printf( stderr, " <empty, possibly corrupt>\n" );
return;
}
char** symbollist = backtrace_symbols( addrlist, addrlen );
for ( u32 i = 3; i < addrlen; i++ )
printf( stderr, "%s\n", symbollist[i] ):
}
您需要做更多的工作来解开符号以使它们可读。尝试使用abi::__cxa_demangle。当然,要使用-g进行构建,并使用-rdynamic进行链接。