gdb调试原理

这篇文章介绍了GDB调试的原理:

用图文带你彻底弄懂GDB调试原理 - 腾讯云开发者社区-腾讯云 (tencent.com)

用 set follow-fork-mode child即可。这是一个 gdb 命令,其目的是告诉 gdb 在目标应用调用fork之后接着调试子进程而不是父进程,因为在 Linux 中fork系统调用成功会返回两次,一次在父进程,一次在子进程 - pycod - 博客园 (cnblogs.com)

Gdb调试多进程程序 - zhenjing - 博客园 (cnblogs.com)

这篇文章以test.c程序为例:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    int c = a + b;
    printf("c = %d \n", c);
    return 0;
}

输入gcc -g test.c -o test 通过编译命令生成 test可执行程序,然后输入gdb ./test 进入GDB

 作者给出如下流程图:

在执行gdb ./test命令时,操作系统会启用GDB进程,这个GDB进程fork出子进程,这个子进程做两件事:① 调用ptrace函数;② 通过execv加载test程序;

这里的ptrace函数的作用是让GDB父进程可以读写子进程的指令空间,数据空间,堆栈和寄存器,操作系统向test进程发送的信号都会被GDB进程截获。

作者然后以断点调试为例说明调试过程:

上面说到,在执行gdb ./test之后,gdb就会fork出一个子进程,这个子进程首先调用ptrace然后执test程序,这样就准备好调试环境了。

我们把源码和汇编代码放在一起,方便理解:

在调试窗口输入设置断点指令“break 5”,此时gdb做2件事情:

  1. 对第5行源码所对应的第10行汇编代码存储到断点链表中。
  2. 在汇编代码的第10行,插入中断指令INT3,也就是说:汇编代码中的第10行被替换为INT3。

然后,在调试窗口继续输入执行指令“run”(一直执行,直到遇到断点就暂停),汇编代码中PC指针(一个内部指针,指向即将执行的那行代码)执行第10行时,发现是INT3指令,于是操作系统就发送一个SIGTRAP信号给test进程。

此刻,第10行汇编代码被执行过了,PC指针就指向第11行了。

上面已经说过,操作系统发给test的任何信号,都被gdb接管了,也就是说gdb会首先接收到这SIGTRAP个信号,gdb发现当前汇编代码执行的是第10行,于是到断点链表中查找,发现链表中存储了第10行的代码,说明第10行被设置了断点。于是gdb又做了2个操作:

  1. 把汇编代码中的第10行"INT3"替换为断点链表中原来的代码。
  2. 把 PC 指针回退一步,也即是设置为指向第10 行。

然后,gdb继续等待用户的调试指令。

此刻,就相当于下一条执行的指令是汇编代码中的第10行,也就是源码中的第5行。从我们调试者角度看,就是被调试程序在第5行断点处暂停了下来,此时我们可以继续输入其他调试指令来debug,比如:查看变量值、查看堆栈信息、修改局部变量的值等等。

posted @ 2023-01-13 11:29  轩邈、  阅读(130)  评论(0编辑  收藏  举报