如何在 SIGSEGV 处理程序中安全地转储内存。 C、Linux

How to safely dump memory near to a fall inside the SIGSEGV handler. C, Linux

我需要打印程序崩溃位置旁边的内存 (SIGSEGV),但事实是,当我尝试打印这段内存时,我会再次调用 SIGSEGV。

void handler_SIGSEGV(int signal, siginfo_t *data, void *extra_data) {

for (size_t* mem = (size_t*) (data->si_addr - 5); mem < (size_t*) (data->si_addr + 5); mem++){
    printf("%zx\n", *mem);   // call new SIGSEGV
   }

    exit(1);
}

据我了解在处理程序内部,我可以使用 volatile sig_atomic_t 变量来指示信号已经被触发。

volatile sig_atomic_t isRecall = 0;

void handler_SIGSEGV(int signal, siginfo_t *data, void *extra_data) {

    if (isRecall == 1){
        //second call
    }

    printf("Call - %d\n", isRecall);
    isRecall = 1;
....

但是当再次调用SIGSEGV信号时,我的函数handler_SIGSEGV不知为何没有被调用。

为什么会这样?我该如何实现这样的内存输出?

si_addr是产生错误的内存地址。如果地址超出范围或进程没有读取权限,则可能无法读取内容。例如,如果取消引用空指针,它可能为 0。

默认情况下,在处理信号时,它会被阻止,从而防止嵌套调用。在被阻止时生成 SIGSEGV 会导致未定义的行为(通常是崩溃)。来自 sigprocmask:

If SIGBUS, SIGFPE, SIGILL, or SIGSEGV are generated while they are blocked, the result is undefined, unless the signal was generated by kill(2), sigqueue(3), or raise(3).

您可以通过设置 sigsetjmp/siglongjmp 对或修改错误指令使用的寄存器 (context->uc_mcontext.gregs) 的状态来继续执行。