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

您需要将信号处理程序重置为前一个函数,然后再次崩溃——最好是在最初抛出信号的地方。您可以通过将 astruct sigaction作为第三个参数传递给 来做到这一点sigaction(),并使用保存的值来恢复信号处理程序中的原始行为。

这可能有点棘手,因为 debuggerd 的工作方式(并且因为它的工作方式随着时间的推移而变化)。对于像分段错误这样的“硬”故障,从信号处理程序返回只会导致重新抛出相同的信号。Android 崩溃处理程序通过联系 debuggerd,等待它与 ptrace 连接,然后恢复来利用这一点。然后 debuggerd 开始观察进程崩溃(第二次)。

这不适用于“软”故障,例如有人手动发送您的进程 aSIGABRTSIGPIPE从 a 获取 a write()。如果信号处理程序联系 debuggerd 并恢复,则该进程只是清除信号并继续,让 debuggerd 无限期地等待第二次从未发生过的崩溃。这部分修复了几个版本;现在调试代码重新发出信号本身(在信号处理程序返回之前它实际上不会做任何事情,因为在处理程序运行时信号被阻塞)。这通常有效,如果无效,调试器将超时并断开连接。

所以。如果您收到分段错误或总线错误,您可以恢复原始信号处理程序,然后从您的返回,当进程再次崩溃时,调试器处理程序将处理它。如果有人给你发了一个SIGHUP,你应该完全自己处理,因为调试器根本不关心那个信号。

事情变得很奇怪SIGFPE。这是一个“软”故障,因为大多数 ARM CPU 没有硬件整数除法指令,信号实际上是从 libgcc__div0函数显式发送的。您可以恢复信号处理程序,然后自己重​​新发送信号;但根据您运行的 Android 版本,您可能需要发送两次。理想情况下,您希望从遇到算术问题的代码而不是信号处理程序中执行此操作,但这很棘手,除非您可以替换__div0. 您需要使用tgkill(), not发送信号kill(),因为后者将导致信号被发送到进程的主线程,这将导致调试器为错误的线程转储堆栈。

您可能很想将处理程序从 中复制出来bionic/linker/debugger.cpp,但这是个坏主意——用于在仿生和调试器之间进行通信的协议过去已更改,并且可能会再次更改。

于 2013-06-24T17:35:18.393 回答
-2

你需要oldPsa像这样手动调用

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