gdb是Linux下的一款调试工具。我们的进程需要调试的话,那么在编译的时候需要加上-g选项,这个选项是增加调试信息。如果不加,则无法调试。如果有core文件的话,可以用core文件与进程一起调试。
下面我们先来介绍一下gdb下的基本指令
- list(l)行号:显示源代码。一次显示10行
- list(l)函数名:列出某个函数的源代码
- r或run:运行程序
- s或step:进入函数调用
- breaktrace(bt):查看函数调用栈
- info(i) locals:查看当前栈帧局部变量的值
- info break :查看断点信息
- finish:执行到当前函数返回,然后停下来等待命令
- print(p):打印表达式的值
- set var:修改变量的值
- quit(q):退出gdb
- break(b) 行号:在某一行设置断点
- break 函数名:在某个函数开头设置断点
- continue(c):从当前位置开始连续而非单步执行程序
- run(r):从开始连续而非单步执行程序
- delete(d)break:删除所有断点
- delete(d)break n:删除序号为n的断点
- disable break:禁用断点
- enable break:启用断点
- info(i) break:参看当前设置了断点
- next(n):单条执行
调试多进程
gdb下默认调试的时候只调试主进程。但是在gdb下只要对follow-fork-mode与detach-on-fork这两个选项进行设置,这时候就可以对多进程进行调试。首先我们先写一个多进程代码,作为测试用例。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if(pid < 0) {
printf("fork erro\n");
}
if(pid == 0) { // child
printf("i am child, my pid is %d, my father pid is %d!\n",getpid(), getppid());
} else {//father
printf("i am father, my pid is %d!\n",getpid());
wait(NULL);
}
return 0;
}
gcc编译的时候需要加上-g选项。
接下来,我们打开gdb进行调试。
利用指令list来查看代码。一次只能显示10行,按下回车则可以显示后面的。我们这时候可以利用show指令先看一下刚才说的follow-fork-mode与detach-on-fork的默认选项是什么。
我们发现,默认的follow-fork-mode与detach-on-fork选项分别设置为parent与on,这样的意思为调试时不分离进程,只调试主进程。
follow-fork-mode | detach-on-fork | 所起到的效果 |
---|---|---|
parent | on | 只调试主进程 |
child | on | 只调试子进程 |
parent | off | 同时调试两个进程,gdb跟主进程,子进程阻塞在fork位置 |
child | off | 同时调试两个进程,gdb跟子进程,主进程阻塞在fork位置 |
接下来我们利用set将follow-fork-mode与detach-on-fork的选项分别设置为child与off,这样设置的话就可以对子进程调试了。
接下来分别在父子进程处用break(b)打下两个断点,然后run(r)运行代码。这时候代码会在第一个断点处停下。我们这里选择在第九行打一个断点,也就是fork之后。fork完毕后,会创建一个子进程。此时我们用info inferiors这个指令,可以查看现在程序中的多个进程,其中gdb会默认给它们编号,这个编号便于我们在调试的时候对进程进行切换。由于我们follow-fork-mode与detach-on-fork选项分别设置的是child与off,所以这个时候gdb在调试的时候跟随子进程。如果gdb跟随某个进程,那么info inferiors查看的时候,这个进程编号前会有*
这表示gdb跟子进程。
此时,我们可以看到在这个时候*
在编号为2的进程旁边, 也就是说编号2是子进程。其实说通俗点,就是*
在谁前面,现在gdb调试的就是谁。可以利用inferiors
加编号,来切换要调试的进程。
我们发现,这个时候*
到了编号为1的进程旁边,也就是说现在调试的是主进程。如果能够切换进程了,那么这个时候利用我们前面gdb的基本操作就可以随心所欲的调试进程了。(本人表示还是有点难度的。。。。一般调试都用printf大法!!!)
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!