当Android应用程序崩溃时,我可以获得C ++堆栈跟踪吗?

时间:2012-06-25 18:18:01

标签: android c++ debugging

我的C ++代码中出现的大多数错误导致应用程序只是退出,没有任何LogCat输出,并且设备上没有消息。空指针和错误使用JNI通常会产生这种结果,不用说,它使调试非常困难。

目前我可以在ndk-gdb中使用'bt'命令获取堆栈跟踪,但是如果崩溃发生在启动的前2秒内则不会,因为ndk-gdb启动进程并在启动后附加到它。另外,ndk-gdb是不可靠的,经常说它找不到任何符号,或抱怨非致命的“SIGILL”错误,例如。

有没有办法在应用程序崩溃时捕获错误并打印堆栈跟踪或其他信息?例如,如果有SIGSEGV,我想知道该应用尝试访问的地址。

3 个答案:

答案 0 :(得分:4)

trace.txt文件给出了什么?我不记得他的位置是:/data/anr/trace.txt还是/data/data/{pkg}/trace.txt

答案 1 :(得分:1)

您需要首先捕获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之前你不会得到堆栈跟踪。如果您以前想要它们,可以从全局对象的构造函数中调用此函数。但不能保证它将成为第一个被称为构造函数的东西。有办法确保它尽早被调用。例如,重载运算符new - 在调试版本中 - 首先在第一次分配时初始化堆栈跟踪,然后调用真实运算符new。这将为您提供从第一次分配开始的堆栈跟踪。

打印堆栈跟踪:

void printStackTrace( unsigned int max_frames = 63 )
{
   void* addrlist[max_frames+1];

   // retrieve current stack addresses
   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链接。

答案 2 :(得分:-2)

是的,'execinfo.h'在那里不存在,但CallStack确实:

#include <utils/CallStack.h>
..
CallStack cs;
cs.dump();

希望它可以帮助这样的信号处理程序。