gpt4 book ai didi

android - 在 Android NDK 中捕获 C++ 信号并仍然打印故障转储

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:50:07 28 4
gpt4 key购买 nike

我正在捕获 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);
}

最佳答案

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

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

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

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

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

您可能想从 bionic/linker/debugger.cpp 中复制处理程序,但这是个坏主意——用于在 bionic 和 debuggerd 之间进行通信的协议(protocol)在过去发生了变化,并且很可能会再次发生变化。

关于android - 在 Android NDK 中捕获 C++ 信号并仍然打印故障转储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17266379/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com