debugging 在崩溃的C程序中添加代码以记录回跟踪[重复]

3yhwsihp  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(115)

此问题已在此处有答案

How to get proper backtrace in process signal handler (armv7-uclibc)?(3个答案)
昨天关门了。
我正在写一个基础结构代码,它应该像gdb一样记录我崩溃的C程序的回溯,但没有特别使用gdb。为此,我编写了一个崩溃信号处理程序,以便在退出之前记录。

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void crash_signal_handler(int sig) 
{
    void* backtrace_array[10];
    size_t size;
    char** symbols;

    size = backtrace(backtrace_array, 10);
    symbols = backtrace_symbols(backtrace_array, size);

    int fd = fileno(stdout);  // Use stdout file descriptor

    fprintf(stderr, "Program crashed. Backtrace:\n");
    backtrace_symbols_fd(backtrace_array, size, fd);

    free(symbols);
    exit(1);
}

int main() {
    signal(SIGSEGV, crash_signal_handler);
    //Intentionally trigger a segmentation fault for testing
    int* ptr = NULL;
    *ptr = 42;
}

然而,它的回溯与我们在GDB中看到的程序崩溃时的情况完全不同,我们运行bt命令。

/home/ravi#  ./a.out 
Program crashed. Backtrace:
./a.out(crash_signal_handler+0x35)[0x55931304e27e]
/lib/x86_64-linux-gnu/libc.so.6(+0x43090)[0x7fbf3155f090]
./a.out(main+0x3a)[0x55931304e335]    -----> no line number shown, file name is also a.out it should be source file name where it crashed
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7fbf31540083]
./a.out(_start+0x2e)[0x55931304e18e]
/home/ravi#

理想情况下,它应该显示行号和源文件的名称,如下所示

(gdb) r
Starting program: /home/root# a.out 

**Program received signal SIGSEGV, Segmentation fault.
0x000055555555513d in main () at sample.c:7
7       *ptr = 42;
(gdb) bt
#0  0x000055555555513d in main () at sample.c:7
(gdb)** q
A debugging session is active.

    Inferior 1 [process 1567493] will be killed.

Quit anyway? (y or n) y
/home/root#

有没有办法更新代码并实现这一点?这将有助于调试大型源代码的C程序,如果它在生产环境中崩溃。
此外,是否可以编写一个信号处理程序来记录回溯并在生产代码中添加该功能?我知道我们不能在生产代码中永久保留符号,但在测试阶段可以确定。或者有更好的办法吗?任何建议都欢迎。

rkkpypqq

rkkpypqq1#

如果你想要源代码行信息(和源代码信息),你需要在回溯中获取地址,并在可执行文件的调试符号中查找它们。这并不容易做到,通常需要调用addr2line这样的外部程序来完成繁重的工作。
您可以找到一个开源示例here

8hhllhi2

8hhllhi22#

为此,我编写了一个崩溃信号处理程序,以便在退出之前记录。
请注意,backtracebacktrace_symbols都不是异步信号安全的。
SIGSEGV处理程序调用它们,一旦你因为堆损坏而崩溃,就注定会以眼泪告终。
你可能会更好地使用libunwind,它至少旨在异步信号安全。
然后,您必须使用async-signal-safe符号化器将地址转换为符号名称,并使用async-signal-safe debuginfo解码器将这些地址转换为文件/行信息。
写这两篇文章都不是一件小事。

相关问题