多進程調試


實際上,GDB 沒有對多進程程序調試提供直接支持。例如,使用GDB調試某個進程,如果該進程fork了子進程,GDB會繼續調試該進程,子進程會不受干擾地運行下去。如果你事先在子進程代碼里設定了斷點,子進程會收到SIGTRAP信號並終止。那么該如何調試子進程呢?其實我們可以利用GDB的特點或者其他一些輔助手段來達到目的。此外,GDB 也在較新內核上加入一些多進程調試支持。

本文介紹的方法能讓你把斷點設在子進程中,單步查看子進程的運行情況。但問題,如果我想在一次調試中同時在父子進程中設置斷點,單步執行該怎么做呢?

 1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 #include<sys/ipc.h>
6 #include<sys/shm.h>
7 #include<sys/types.h>
8 #include<fcntl.h>
9 #include<sys/stat.h>
10
11 main(){
12 int pause=1; //讓進程暫停,以便獲得pid
13 char *arr;
14 int shmid;
15 if((shmid=shmget(2012,4,IPC_CREAT|0666))==-1){ //父進程中創建共享內存
16 perror("shmget");
17 exit(1);
18 }
19 pid_t pid;
20 if((pid=fork())<0){
21 perror("fork");
22 exit(1);
23 }
24 if(pid==0){
25 while(pause) sleep(1);
26 if((arr=shmat(shmid,NULL,0))==(void*)-1){ //子進程中把共享內存映射到本,進行修改
27 perror("shmat");
28 exit(1);
29 }
30 arr[0]='a';arr[1]='b';arr[2]='c';arr[3]='\0';
31 if(shmdt(arr)==-1){
32 perror("shmdt");
33 exit(1);
34 }
35 }
36 else{
37 while(pause) sleep(1);
38 //sleep(1);
39 if((arr=shmat(shmid,NULL,0))==(void*)-1){ //子進程中把共享內存映射到本,讀取其內容
40 perror("shmat");
41 exit(1);
42 }
43 printf("%s\n",arr);
44 if(shmdt(arr)==-1){
45 perror("shmdt");
46 exit(1);
47 }
48 }
49 }

方法一:attach pid

ubuntu默認情況下你在gdb中使用attach id是權限不夠的,所以你需要:sudo chmod +s /usr/bin/gdb

  1. 在父子進程中加一句while(pause) sleep(1);,讓其暫停,然后后台運行程序,通過ps獲取子進程的PID。(如下所示,ps顯示的./fork有兩個,orisun是進程的有效用戶,第一個數字是進程ID,第二個數字是其父進程ID)
  2. 運行gdb,attach 子進程ID
orisun@zcypc:~$ ./fork &
[1] 13294
orisun@zcypc:~$ ps -ef|grep fork
102 790 1 0 09:00 ? 00:00:01 dbus-daemon --system --fork --activation=upstart
orisun 1546 1 0 09:00 ? 00:00:03 //bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
orisun 12584 1 0 20:23 ? 00:00:12 gedit /home/orisun/fork.c
orisun 13294 13239 0 20:53 pts/0 00:00:00 ./fork
orisun 13295 13294 0 20:53 pts/0 00:00:00 ./fork
orisun 13297 13239 0 20:54 pts/0 00:00:00 grep --color=auto fork
orisun@zcypc:~$ gdb
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) attach 13295
Attaching to process 13295
Reading symbols from /home/orisun/fork...done.
Reading symbols from /lib/i386-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug/lib/i386-linux-gnu/libc-2.13.so...done.
done.
Loaded symbols for /lib/i386-linux-gnu/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0x00bd8416 in __kernel_vsyscall ()
(gdb) backtrace
#0 0x00bd8416 in __kernel_vsyscall ()
#1 0x0049bfc0 in __nanosleep_nocancel ()
at ../sysdeps/unix/syscall-template.S:82
#2 0x0049bde2 in __sleep (seconds=<value optimized out>)
at ../sysdeps/unix/sysv/linux/sleep.c:138
#3 0x08048595 in main () at fork.c:25
(gdb) up 3
#3 0x08048595 in main () at fork.c:25
25 while(pause) sleep(1);
(gdb) list
20 if((pid=fork())<0){
21 perror("fork");
22 exit(1);
23 }
24 if(pid==0){
25 while(pause) sleep(1);
26 if((arr=shmat(shmid,NULL,0))==(void*)-1){ //子進程中把共享內存映射到本,進行修改
27 perror("shmat");
28 exit(1);
29 }
(gdb) break 31
Breakpoint 1 at 0x8048600: file fork.c, line 31.
(gdb) set pause=0
(gdb) continue
Continuing.

Breakpoint 1, main () at fork.c:31
31 if(shmdt(arr)==-1){
(gdb) p arr
$1 = 0xb77fb000 "abc"
(gdb)

方法二:follow-fork-mode

不需要專門加while(pause) sleep(1);這種代碼了。

follow-fork-mode的用法為:
set follow-fork-mode [parent|child] 
    * parent: fork之后繼續調試父進程,子進程不受影響。
    * child: fork之后調試子進程,父進程不受影響。 
因此如果需要調試子進程,在啟動gdb后:
(gdb) set follow-fork-mode child
並在子進程代碼設置斷點。 
此外還有detach-on-fork參數,指示GDB在fork之后是否斷開(detach)某個進程的調試,或者都交由GDB控制:
set detach-on-fork [on|off] 
    * on: 斷開調試follow-fork-mode指定的進程。
    * off: gdb將控制父進程和子進程。follow-fork-mode指定的進程將被調試,另一個進程置於暫停(suspended)狀態。

orisun@zcypc:~$ gdb ./fork
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/orisun/fork...done.
(gdb) set follow-fork-mode child
(gdb) set detach-on-fork off
(gdb) break 31
Breakpoint 1 at 0x80485e3: file fork.c, line 31.
(gdb) r
Starting program: /home/orisun/fork
[New process 13534]
[Switching to process 13534]

Breakpoint 1, main () at fork.c:31
31 if(shmdt(arr)==-1){
(gdb) p arr
$1 = 0xb7ffd000 "abc"
(gdb) c
Continuing.

Program exited normally.
(gdb)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM