所有线程崩溃 运行 SIGSEGV 处理程序

Crash with all threads running SIGSEGV handler

我们在嵌入式 MIPS 系统中的 Linux 3.4.11 上开发了一个用户-space 进程 运行。该进程使用 pthreads 创建多个 (>10) 线程。该进程有一个 SIGSEGV 信号处理程序,除其他外,它会生成一条日志消息,该消息将进入我们的日志文件。作为这个流程的一部分,它获得了一个信号量(不好,我知道......)。

在我们的测试过程中,该进程似乎挂起。我们目前无法为目标平台构建 gdb,因此我编写了一个 CLI 工具,它使用 ptrace 使用 PTRACE_PEEKUSR.

提取寄存器值和用户数据

令我惊讶的是,我们所有的线程都在内部我们的崩溃处理程序中,试图获取信号量。这(显然?)表明信号量出现死锁,这意味着线程在持有它时死亡。当我挖掘堆栈时,似乎几乎所有线程(除了一个线程)在信号处理程序启动时都处于阻塞调用(recv、poll、sleep)运行。在 MIPS 上手动重建堆栈很痛苦,所以我们还没有完全完成它。一个线程似乎正在调用 malloc,这对我来说表明它因堆损坏而崩溃。

有几件事还不清楚:

1) 假设一个线程在 malloc 中崩溃,为什么所有其他线程都是 运行 SIGSEGV 处理程序?据我了解,一个 SIGSEGV 信号被传送到故障线程,不是吗?这是否意味着我们的每一个线程都崩溃了?

2) 查看 MIPS 的 sigcontext 结构,它似乎不包含被访问的内存地址 (badaddr)。还有其他地方有吗?我在任何地方都找不到它,但它不可用对我来说似乎很奇怪。

当然,如果有人能提出继续分析的方法,我们将不胜感激!

是的,假设您已正确捕获线程状态,很可能您的所有线程依次崩溃。

siginfo_t有一个si_addr成员,应该给你错误的地址。你的内核是否填充它是另一回事。

进程内崩溃处理程序总是不可靠的。您应该使用进程外处理程序,并设置 kernel.core_pattern 来调用它。在当前的内核中,没有必要将核心文件写入磁盘;你可以从标准输入读取核心文件,或者只映射僵尸进程的进程内存(当内核调用崩溃处理程序时它仍然可用)。