2012-06-25 50 views
10

我的C++代码中发生的大多数错误都会导致应用程序退出,并且没有任何LogCat输出,并且设备上也没有消息。空指针和JNI的不正确使用通常会产生这样的结果,不用说,它会使调试非常困难。当Android应用程序崩溃时,我可以获得C++堆栈跟踪吗?

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

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

+1

检查答案。这是专门为Android http://stackoverflow.com/a/28858941/365229 –

回答

4

trace.txt file give something?我不记得他的位置是:/data/anr/trace.txt/data/data/{pkg}/trace.txt

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才会获得堆栈跟踪。如果你以前想要它们,你可以从全局对象的构造函数中调用这个函数。但是不能保证它是第一个被调用的构造函数。有办法确保它被提前调用。例如,重载运算符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链接。

+0

谢谢。我修正了我正在寻找的错误,但下次我肯定会给出这个错误。我不确定我是否理解'-rdynamic',尽管我查了文档:“将标志-export-dynamic传递给ELF链接器,支持它的目标。这指示链接器添加所有符号,不仅用于到动态符号表,这个选项是dlopen的一些用途所必需的,或者允许从程序中获取回溯。“ ('-g',同时,“打开目标的首选格式的调试信息”)。 – Qwertie

+9

废话!回溯应该在execinfo.h中,但它在Android上不存在! (execinfo.h:没有这样的文件或目录) – Qwertie

+3

是的,Android上没有'backtrace'。 –

-2

是的,“execinfo.h”不存在那里,但调用堆栈的作用:

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

希望能在这样的信号处理提供帮助。

+0

我必须缺少一些东西:致命错误:utils/CallStack.h:没有这样的文件或目录#include ---也许还有其他需要进入Android.mk的东西? –

+3

NDK文件夹中没有文件'CallStack.h'! –

+0

https://android.googlesource.com/platform/system/core.git/+/master/include/utils/CallStack.h https://android.googlesource.com/platform/frameworks/native/+/jb- dev/include/utils/CallStack.h –

相关问题