2

C++ シグナルをキャッチしているので、デバッグ情報を出力します。しかし、そうすると、クラッシュしたときに NDK が出力するクラッシュ ダンプを取得できません。

クラッシュ ダンプを手動で印刷できますか。私は debuggerd.c ( http://kobablog.wordpress.com/2011/05/12/debuggerd-of-android/ ) が機能することを確認しましたが、どのように使用するかはわかりません。それ以外の場合は、シグナルハンドラーがシグナルをキャッチせずにシグナルを再スローして、クラッシュダンプを取得する方法があります。

これが私が現在行っていることです:

struct sigaction psa, oldPsa;

void CESignalHandler::init() {
    CELogI("Crash handler started");

    psa.sa_sigaction = handleCrash;
    psa.sa_flags = SA_SIGINFO;

    //sigaction(SIGBUS, &psa, &oldPsa);
    sigaction(SIGSEGV, &psa, &oldPsa);
    //sigaction(SIGSYS, &psa, &oldPsa);
    //sigaction(SIGFPE, &psa, &oldPsa);
    //sigaction(SIGILL, &psa, &oldPsa);
    //sigaction(SIGHUP, &psa, &oldPsa);
}

void CESignalHandler::handleCrash(int signalNumber, siginfo_t *sigInfo, void *context) {
    static volatile sig_atomic_t fatal_error_in_progress = 0;
    if (fatal_error_in_progress) //Stop a signal loop.
        _exit(1);
    fatal_error_in_progress = 1;

    char* j;
    asprintf(&j, "Crash Signal: %d, crashed on: %x, UID: %ld\n", signalNumber, (long) sigInfo->si_addr, (long) sigInfo->si_uid);  //%x prints out the faulty memory address in hex
    CELogE(j);

    CESignalHandler::getStackTrace();
    sigaction(signalNumber, &oldPsa, NULL); 
}
4

2 に答える 2

4

シグナル ハンドラーを前の関数にリセットしてから、再度クラッシュする必要があります。理想的には、シグナルが最初にスローされたポイントでクラッシュします。struct sigactionこれを行うには、 の 3 番目の引数としてa in を渡しsigaction()、保存された値を使用してシグナル ハンドラで元の動作を復元します。

これは、debuggerd の動作方法 (およびその動作方法が時間の経過とともに変化したため) のために、少し注意が必要な場合があります。セグメンテーション違反のような「ハード」な障害の場合、シグナル ハンドラから戻ると、同じシグナルが再スローされるだけです。Android のクラッシュ ハンドラは、debuggerd に接続し、ptrace でアタッチされるのを待ってから再開することで、これを利用します。debuggerd は、プロセスがクラッシュするのを監視します (2 回目)。

これは、「ソフト」な障害では機能しません。たとえば、誰かが手動でプロセスを送信したり、から をSIGABRT取得したりします。シグナル ハンドラーが debuggerd に接続して再開すると、プロセスはシグナルをクリアして処理を続行し、debuggerd は 2 回目のクラッシュが発生するまで無期限に待機します。これは、数リリース前に部分的に修正されました。ここで、デバッグ コードはシグナル自体を再発行します (ハンドラーの実行中にシグナルがブロックされるため、シグナル ハンドラーが戻るまで実際には何もしません)。これは通常は機能しますが、機能しない場合、debuggerd はタイムアウトして接続を切断します。SIGPIPEwrite()

そう。セグメンテーション フォールトまたはバス エラーが発生した場合は、元のシグナル ハンドラを復元して、元のシグナル ハンドラから戻ることができます。プロセスが再びクラッシュすると、debuggerd ハンドラが対処します。SIGHUPdebuggerd はそのシグナルをまったく気にしないため、誰かが.

で事態は奇妙になりSIGFPEます。__div0ほとんどの ARM CPU にはハードウェア整数除算命令がなく、シグナルは実際には libgcc関数から明示的に送信されているため、これは「ソフト」な失敗です。シグナル ハンドラーを復元してから、自分でシグナルを再送信できます。ただし、実行している Android のバージョンによっては、2 回送信する必要がある場合があります。理想的には、シグナル ハンドラではなく、算術問題が発生したコードからこれを実行したいのですが、__div0. 後者はプロセスのメイン スレッドにシグナルが送信され、debuggerd が間違ったスレッドのスタックをダンプする原因となるため、tgkill()ではなくを使用してシグナルを送信する必要があります。kill()

ハンドラーを からコピーしたくなるかもしれませんがbionic/linker/debugger.cpp、それは悪い考えです。bionic と debuggerd の間の通信に使用されるプロトコルは過去に変更されており、今後も変更される可能性があります。

于 2013-06-24T17:35:18.393 に答える
-2

oldPsaこのように手動で呼び出す必要があります

oldPsa(signalNumber, sigInfo, context)
于 2013-12-02T13:46:37.083 に答える