2012-06-25 54 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 –

相關問題