gdb是linux操作系统中常见的调试工具,在这篇文章中主要介绍gdb调试多进程的几种方法。
其实在Linux系统中并没有对多进程提供直接支持。例如,用gdb调试一个进程,如果该进程fork/vfork了子进程,gdb会继续调试该进程,子进程并不受任何影响。如果我们在子进程的代码处设置断点,子进程会收到SIGTRAP(5号信号,可以在linux系统中使用kill -l查询信号量)并终止,无法通过设置断点的方式调试子进程,那仫该如何调试子进程呢?在我的这篇文章中只介绍下面几种调试子进程的方法:follow-fork-mode,attach子进程方法。
1.follow-fork-mode
set follow-fork-mode [parent|child]
parent:gdb默认调试的是父进程,如果参数是parent则fork之后继续调试父进程,子进程不受影响
child:如果想调试子进程,则修改参数为child,set follow-fork-mode child之后调试子进程,父进程不受影响。
show follow-fork-mode,查看当前调试的fork进程的模式
2.detach-on-fork
该参数表明gdb在fork之后是否断开(detach)某个进程的调试,或者交给gdb控制.
set detach-on-fork [on|off]
on:断开调试follow-fork-mode调试的指定进程
off:gdb将控制父进程和子进程。follow-fork-mode指定的进程将被调试,另一个进程置于暂停(suspended)状态。
show detach-on-fork,查看detach-on-fork模式
gdb将每一个被调试进程的执行状态记录在一个名为inferior的结构中。一般情况下一个inferior对应一个进程,每个不同的inferior有不同的地址空间。inferior有时候会在进程没有启动的时候就存在。
3.info inferiors
查询正在调试的进程,gdb会为他们分配唯一的Num号,其中前面带'*'号的就是正在调试的进程
4.inferior <inferior num>
切换调试的进程为inferior num的进程处
5. add-inferior [-copies n] [-exec executable]
添加n个新的调试进程,可以用file executable来分配给inferior可执行文件。如果不指定n,则只增加一个inferior;如果不指定executable,则执行程序留空,增加后可使用file命令重新指定执行程序;这时候创建的inferior其关联的进程并没启动。
6.clone-inferior [-copies n] [infno]
复制n个编号是infno的inferior。如果不指定n的话,就只复制一个inferior;如果不指定infno,则就复制正在调试的inferior。
7. detach inferior infno
断开(detach)掉编号是infno的inferior。值得注意的是这个inferior还存在,可以再次用run命令执行它。
8.kill inferior infno
kill掉infno号inferior。值得注意的是这个inferior仍然存在,可以再次用run等命令执行它。
9.remove-inferior infno
删除一个infno号的inferior。删除前需要先kill或者detach这个inferior,因为当一个inferior正在运行时不能被删除.
10.set schedule-multiple [on|off]
off:只有当前inferior会执行。
on:全部是执行状态的inferior都会执行。
show schedule-multiple,查看schedule-multiple的状态。
11.set follow-exec-mode [new|same]
same:当发生exec的时候,在执行exec的inferior上控制子进程。
new:新建一个inferior给执行起来的子进程。而父进程的inferior仍然保留,当前保留的inferior的程序状态是没有执行。
show follow-exec-mode,查看follow-exec-mode设置的模式。
12.set print inferior-events [on|off],用来打开和关闭inferior状态的提示信息。
show print inferior-events ,查看print inferior-events设置的状态。
13.maint info program-spaces,用来显示当前gdb管理的地址空间的数目。
除了follow-fork-mode方法还有没有其他的方法调试多进程呢?我们知道gdb有附着(attach)到正在运行的进程的功能,即attach <pid>命令。因此我们可以利用该命令attach到子进程然后进行调试。attach命令能够应付各种各样复杂的进程系统,比如孙子/曾孙进程,比如守护进程(精灵进程).
好了学了这仫多的gdb调试多进程的命令,那仫如何使用它呢?让我们以一个简单的栗子来说明gdb调试多进程的使用吧!
#include<stdio.h> #include<stdlib.h> #include<unistd.h> int main() { pid_t id=fork(); if(id == 0) { printf("i am child,pid=%d,ppid=%d\n",getpid(),getppid()); exit(1); } else { sleep(1); printf("i am parent,pid=%d,ppid=%d\n",getpid(),getppid()); if(wait(NULL) != -1) { printf("wait success\n"); } } return 0; } makefile testgdb:testgdb.c gcc -o $@ $^ -g //因为要使用gdb调试,所以要在gcc后面添加-g选项 .PHONY:clean clean: rm -f testgdb
1.测试follow-fork-mode和detach-on-fork命令
2.进程间的查询和切换