2012-06-25 10 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ファイルは何ですか?彼の所在が覚えていない:/data/anr/trace.txtまたは/data/data/{pkg}/trace.txt

1

segvを取得するときにコードを実行するには、まずSIGSEGVをトラップする必要があります。これはposixコードなので、類似のものがアンドロイドで動作するはずです:

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でリンクします。

+0

ありがとうございます。私が探していたバグを修正しましたが、次回はこのショットを間違いなく与えます。私は '-rdynamic'を理解していませんが、ドキュメントを参照しています:" ELFリンカにフラグ-export-dynamicを渡すと、それをサポートするターゲットに渡します。これはリンカにすべてのシンボルを追加するよう指示しますこのオプションは、dlopenのある用途やプログラム内からバックトレースを得るために必要です。 ( '-g'、一方、"ターゲットのための好ましいフォーマットでデバッグ情報を有効にする ") – Qwertie

+9

クラップ! backtraceはexecinfo.hにあるはずですが、Androidには存在しません! (execinfo.h:そのようなファイルやディレクトリはありません) – Qwertie

+3

ええ、Android上にはバックトレースはありません。 –

-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 –

関連する問題