gdb 多进程调试

    技术2022-05-19  19

    我们先看看我们的测试程序:/* in eg1.c */int wib(int no1, int no2){        int result, diff;        diff = no1 - no2;        result = no1 / diff;        return result;}int main(){        pid_t   pid;        pid = fork();        if (pid <0) {                printf("fork err/n");                exit(-1);        } else if (pid == 0) {                /* in child process */                sleep(60); ------------------ (!)                int     value   = 10;                int     div     = 6;                int     total   = 0;                int     i       = 0;                int     result = 0;                for (i = 0; i < 10; i++) {                        result = wib(value, div);                        total += result;                        div++;                        value--;                }                printf("%d wibed by %d equals %d/n", value, div, total);                exit(0);        } else {                /* in parent process */                sleep(4);                wait(-1);                exit(0);        }}该测试程序中子进程运行过程中会在wib函数中出现一个'除0'异常。现在我们就要调试该子进程。[调试原理]不知道大家发现没有,在(!)处在我们的测试程序在父进程fork后,子进程调用sleep睡了60秒。这就是关键,这个sleep本来是不该存在于子进程代码中的,而是而了使用GDB调试后加入的,它是我们调试的一个关键点。为什么要让子进程刚刚运行就开始sleep呢?因为我们要在子进程睡眠期间,利用 shell命令获取其process id,然后再利用gdb调试外部进程的方法attach到该process id上,调试该进程。[调试过程]我觉上面的调试原理的思路已经很清晰了,剩下的就是如何操作的问题了。我们来实践一次吧!我所使用的环境Solaris OS 9.0/GCC 3.2/GDB 6.1。GDB 调试程序的前提条件就是你编译程序时必须加入调试符号信息,即使用'-g'编译选项。首先编译我们的源程序'gcc -g -o eg1 eg1.c'。编译好之后,我们就有了我们的调试目标eg1。由于我们在调试过程中需要多个工具配合,所以你最好多打开几个终端窗口,另外一点需要注意的是最好在eg1的working directory下执行gdb程序,否则gdb回提示'No symbol table is loaded'。你还得手工load symbol table。好了,下面我们就'按部就班'的开始调试我们的eg1。执行eg1:eg1 &   --- 让eg1后台运行吧。查找进程id:ps -fu YOUR_USER_NAME运行gdb:gdb(gdb) attach xxxxx --- xxxxx为利用ps命令获得的子进程process id(gdb) stop --- 这点很重要,你需要先暂停那个子进程,然后设置一些断点和一些Watch(gdb) break 37 -- 在result = wib(value, div);这行设置一个断点,可以使用list命令察看源代码Breakpoint 1 at 0x10808: file eg1.c, line 37.(gdb) continueContinuing.Breakpoint 1, main () at eg1.c:3737                              result = wib(value, div);(gdb) stepwib (no1=10, no2=6) at eg1.c:1313              diff = no1 - no2;(gdb) continueContinuing.Breakpoint 1, main () at eg1.c:3737                              result = wib(value, div);(gdb) stepwib (no1=9, no2=7) at eg1.c:1313              diff = no1 - no2;(gdb) continueContinuing.Breakpoint 1, main () at eg1.c:3737                              result = wib(value, div);(gdb) stepwib (no1=8, no2=8) at eg1.c:1313              diff = no1 - no2;(gdb) next14              result = no1 / diff;(gdb) print diff$6 = 0        ------- 除数为0,我们找到罪魁祸首了。(gdb) nextProgram received signal SIGFPE, Arithmetic exception.0xff29d830 in .div () from /usr/lib/libc.so.1至此,我们调试完毕。

     

    上面的方法适用于父子进程同时进行调试。

    另外还有一种方法

    只跟踪某个进程(父或子)

     

    用gdb调试多进程的程序会遇到困难,gdb只能跟踪一个进程(默认是跟踪父进程),而不能同时跟踪多个进程,但可以设置gdb在fork之后跟踪父进程还是子进程。以下面的程序为例:

    2 #include <unistd.h>3 #include <stdio.h>4 #include <stdlib.h>5 6 int main(void)7 {8 pid_t pid;9 char *message;10 int n;11 pid = fork();(gdb) 12 if(pid<0) {13 perror("fork failed");14 exit(1);15 }16 if(pid==0) {17 message = "This is the child/n";18 n = 6;19 } else {20 message = "This is the parent/n";21 n = 3;set follow-fork-mode child命令设置gdb在fork之后跟踪子进程(set follow-fork-mode parent则是跟踪父进程),然后用run命令,看到的现象是父进程一直在运行,在(gdb)提示符下打印消息,而子进程被先前设的断点打断了

    gdb) b 17Breakpoint 1 at 0x8048481: file main.c, line 17.(gdb) set follow-fork-mode child(gdb) rStarting program: /home/djkings/a.out This is the parent[Switching to process 30725]Breakpoint 1, main () at main.c:1717 message = "This is the child/n";(gdb) This is the parentThis is the parent

     

     


    最新回复(0)