c - 如何在 gdb 中调试带有信号处理程序的 C 程序?

标签 c linux process gdb

我编写了一个简单的程序来理解信号处理程序的控制流传输。下面的程序会让 child 重复写入 .text 区域并触发处理程序。

#include "csapp.h" // just include standard headers                             

extern char etext;                                                              

void handler() {                                                                
  printf("pid = %d, in handler\n", getpid());                                   
  return;                                                                       
}                                                                               

int main(int argc, char **argv) {                                               
  if (signal(SIGSEGV, handler) == SIG_ERR) {                                    
    perror("signal error");                                                     
  }                                                                             

  if (fork() == 0) {                                                            
    printf("from Child before\n");                                              
    etext = 'a';                                                                
    printf("from Child after\n");                                               
  }                                                                             

  return EXIT_SUCCESS;                                                          
}             

但是,我想使用 gdb 验证这一点。拆卸主体给出了下面的组件。我使用下面的命令创建了一个断点,这样 gdb 就可以在写入 .text 区域之前的那个点中断。

(gdb) b *0x00000000004006fb

然后我在 gdb 中运行程序。但是 gdb 不会停止并继续执行信号处理程序。

   0x00000000004006ba <+0>: push   %rbp
   0x00000000004006bb <+1>: mov    %rsp,%rbp
   0x00000000004006be <+4>: sub    $0x10,%rsp
   0x00000000004006c2 <+8>: mov    %edi,-0x4(%rbp)
   0x00000000004006c5 <+11>:    mov    %rsi,-0x10(%rbp)
   0x00000000004006c9 <+15>:    mov    $0x40069d,%esi
   0x00000000004006ce <+20>:    mov    $0xb,%edi
   0x00000000004006d3 <+25>:    callq  0x400570 <signal@plt>
   0x00000000004006d8 <+30>:    cmp    $0xffffffffffffffff,%rax
   0x00000000004006dc <+34>:    jne    0x4006e8 <main+46>
   0x00000000004006de <+36>:    mov    $0x4007ba,%edi
   0x00000000004006e3 <+41>:    callq  0x400590 <perror@plt>
   0x00000000004006e8 <+46>:    callq  0x4005a0 <fork@plt>
   0x00000000004006ed <+51>:    test   %eax,%eax
   0x00000000004006ef <+53>:    jne    0x40070c <main+82>
   0x00000000004006f1 <+55>:    mov    $0x4007c7,%edi
   0x00000000004006f6 <+60>:    callq  0x400530 <puts@plt>
   0x00000000004006fb <+65>:    movb   $0x61,0x9b(%rip)        # 0x40079d
   0x0000000000400702 <+72>:    mov    $0x4007d9,%edi
   0x0000000000400707 <+77>:    callq  0x400530 <puts@plt>
   0x000000000040070c <+82>:    mov    $0x0,%eax
   0x0000000000400711 <+87>:    leaveq 
   0x0000000000400712 <+88>:    retq   

问题: 1.为什么gdb不会在我指定的地址中断?

2.如何使用 gdb 以便知道指令指针从信号处理程序返回时指向的确切地址?

最佳答案

Why gdb wont break at the address I specify?

因为您正在调试错误的(父)进程。

你想停止的指令只在 child 身上执行,你不是在调试 child 。

要调试 child ,请使用set follow-fork-mode child

How can I use gdb so that I know the exact address the instruction pointer points to when it returns from the signal handler?

在信号处理程序中的 ret 指令上放置一个断点,并在命中该断点时执行 x/a $rsp

关于c - 如何在 gdb 中调试带有信号处理程序的 C 程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44356298/

相关文章:

c - 编写Linux shell

c - 为什么这个 C 程序不会导致字母数字值的段错误?

linux - 使用 awk 在 Shell 中过滤掉 [..] 中的子字符串列

java - 如何在它被杀死后检查进程状态,或者这甚至可能吗?

swift - 如何处理 Process.run 抛出的异常

c++ - 在 C/C++ 中,如何确定库是否为静态链接

c - 递归scanf死循环

linux - 如何在 linux 中运行外部程序后返回 bash 脚本菜单?

linux - 是否有 VNC 服务器监听 Unix 域套接字而不是标准端口 (5900)?

Linux 上的 Java 无法读取进程输入流