Loading

GDB调试多进程的命令介绍和演示

命令汇总

命令 作用
info inferiors 查看所有进程
inferiors 2 切换到编号为2的进程
detach inferiors 2 detach掉编号为2的进程
kill inferiors 2 kill掉编号为2的进程
set follow-fork-mode parent 只调试父进程(GDB默认)
set follow-fork-mode child 只调试子进程
show follow-fork-mode 查看follow-fork-mode当前值
set detach-on-fork on 只调试一个进程,父进程或子进程(GDB默认)
set detach-on-fork off 同时调试父子进程,另一个进程阻塞在fork位置
show detach-on-fork 查看detach-on-fork当前值
set schedule-multiple off 只有当前进程会执行,其他进程挂起(GDB默认)
set schedule-multiple on 所有的进程都会正常执行
show schedule-multiple 查看schedule-multiple当前值

测试用例

/*================================================================
*  Author: LiuHanxu
*  Date: 2022-12-23
*  Description: how to debug multi-process by gdb
================================================================*/
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
    pid_t pid = fork();
    if(pid == 0) { // 子进程
        printf("I am child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
    } else if(pid > 0) { // 父进程
        printf("I am parent, my pid = %d, my child pid = %d\n", getpid(), pid);
        wait(NULL); // 等待子进程退出
    } else {
       perror("fork error!\n");
       return -1;
    }
    return 0;
}

测试用例中一个是父进程,另一个是通过系统调用fork()创建的子进程。当fork()返回值为0说明当前在子进程里;返回值大于0说明在父进程里,此时返回值表示子进程的pid;返回值小于0说明fork时发生错误。

在默认情况下,在多进程程序中,GDB只调试主进程,也就是说无论程序调用了多少次fork()函数创建了多少个子进程,GDB在默认情况下,只调试父进程。

lhx@ubuntu:~/paopao-notes/code$ gdb ./test_multi_process 
Reading symbols from ./test_multi_process...
(gdb) run
Starting program: /home/lhx/paopao-notes/code/test_multi_process 
[Detaching after fork from child process 92666]
I am parent, my pid = 92663, my child pid = 92666
I am child, my pid = 92666, my parent pid = 92663
[Inferior 1 (process 92663) exited normally]
(gdb)

其中[Detaching after fork from child process xxx]则说明在fork出子进程后就释放了,只跟踪父进程。

进程操作命令inferiors

info inferiors查看所有进程,带*号表示当前进程。
inferiors 2切换到编号为2的进程。
detach inferiors 2detach掉编号为2的进程,注意这个进程还存在,可以再次用run命令执行它。
kill inferiors 2kill掉编号为2的进程,注意这个进程还存在,可以再次用run命令执行它。

Thread 1.1 "test_multi_proc" hit Breakpoint 1, main () at test_multi_process.c:16
16	        printf("I am parent, my pid = %d, my child pid = %d\n", getpid(), pid);
(gdb) i inferiors 
  Num  Description       Connection           Executable        
* 1    process 92828     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
  2    process 92831     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
(gdb) inferior 2
[Switching to inferior 2 [process 92831] (/home/lhx/paopao-notes/code/test_multi_process)]
[Switching to thread 2.1 (process 92831)]
#0  0x00007ffff7e9cf3f in fork () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) n
Single stepping until exit from function fork,
which has no line number information.
main () at test_multi_process.c:13
13	    if(pid == 0) { // 子进程
(gdb) n
14	        printf("I am child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
(gdb) i inferiors 
  Num  Description       Connection           Executable        
  1    process 92828     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
* 2    process 92831     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
(gdb) kill inferiors 1
(gdb) i inferiors 
  Num  Description       Connection           Executable        
  1    <null>                                 /home/lhx/paopao-notes/code/test_multi_process 
* 2    process 92831     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
(gdb) detach inferiors 2
Detaching from program: /home/lhx/paopao-notes/code/test_multi_process, process 92831
[Inferior 2 (process 92831) detached]
I am child, my pid = 92831, my parent pid = 1
(gdb) i inferiors 
  Num  Description       Connection           Executable        
  1    <null>                                 /home/lhx/paopao-notes/code/test_multi_process 
* 2    <null>                                 /home/lhx/paopao-notes/code/test_multi_process 
(gdb) 

只调试子进程set follow-fork-mode child

set follow-fork-mode parent只调试父进程,子进程继续运行(GDB默认)。

set follow-fork-mode child只调试子进程,父进程继续运行。

show follow-fork-mode查看follow-fork-mode当前值

lhx@ubuntu:~/paopao-notes/code$ gdb ./test_multi_process 
Reading symbols from ./test_multi_process...
(gdb) show follow-fork-mode 
Debugger response to a program call of fork or vfork is "parent".
(gdb) list 14
9	
10	int main()
11	{
12	    pid_t pid = fork();
13	    if(pid == 0) { // 子进程
14	        printf("I am child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
15	    } else if(pid > 0) { // 父进程
16	        printf("I am parent, my pid = %d, my child pid = %d\n", getpid(), pid);
17	        wait(NULL); // 等待子进程退出
18	    } else {
(gdb) b 14
Breakpoint 1 at 0x1204: file test_multi_process.c, line 14.
(gdb) r
Starting program: /home/lhx/paopao-notes/code/test_multi_process 
[Detaching after fork from child process 92674]
I am parent, my pid = 92671, my child pid = 92674
I am child, my pid = 92674, my parent pid = 92671
[Inferior 1 (process 92671) exited normally]
(gdb) 
(gdb) set follow-fork-mode child 
(gdb) r
Starting program: /home/lhx/paopao-notes/code/test_multi_process 
[Attaching after process 92675 fork to child process 92676]
[New inferior 2 (process 92676)]
[Detaching after fork from parent process 92675]
[Inferior 1 (process 92675) detached]
I am parent, my pid = 92675, my child pid = 92676
[Switching to process 92676]

Thread 2.1 "test_multi_proc" hit Breakpoint 1, main () at test_multi_process.c:14
14	        printf("I am child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
(gdb) n
I am child, my pid = 92676, my parent pid = 92675
22	    return 0;
(gdb) 

通过上面测试发现,当保持gdb默认值时,只调试父进程。当在14行子进程里设断点后,发现程序不会停住。将follow-fork-mode设为child后,父进程继续执行,而此时子进程能够停在断点处。

同时调试父子进程set detach-on-fork off

set detach-on-fork on只调试一个进程,可以是父进程或子进程(GDB默认)。

set detach-on-fork off同时调试父子进程,如果follow-fork-mode是parent,则gdb跟踪父进程,子进程阻塞在fork位置。如果follow-fork-mode是child,则gdb跟踪子进程,父进程阻塞在fork位置。此时用户可以根据调试情况在父进程和子进程之间来回切换调试。

show detach-on-fork查看detach-on-fork当前值。


lhx@ubuntu:~/paopao-notes/code$ gdb ./test_multi_process 
Reading symbols from ./test_multi_process...
(gdb) set follow-fork-mode child 
(gdb) set detach-on-fork off
(gdb) b 14
Breakpoint 1 at 0x1204: file test_multi_process.c, line 14.
(gdb) b 16
Breakpoint 2 at 0x122d: file test_multi_process.c, line 16.
(gdb) r
Starting program: /home/lhx/paopao-notes/code/test_multi_process 
[Attaching after process 92736 fork to child process 92739]
[New inferior 2 (process 92739)]
[Switching to process 92739]

Thread 2.1 "test_multi_proc" hit Breakpoint 1, main () at test_multi_process.c:14
14	        printf("I am child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
(gdb) n
I am child, my pid = 92739, my parent pid = 92736
22	    return 0;
(gdb) i inferiors 
  Num  Description       Connection           Executable        
  1    process 92736     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
* 2    process 92739     1 (native)           /home/lhx/paopao-notes/code/test_multi_process 
(gdb) inferior 1
[Switching to inferior 1 [process 92736] (/home/lhx/paopao-notes/code/test_multi_process)]
[Switching to thread 1.1 (process 92736)]
#0  0x00007ffff7e9cf3f in fork () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) c
Continuing.

Thread 1.1 "test_multi_proc" hit Breakpoint 2, main () at test_multi_process.c:16
16	        printf("I am parent, my pid = %d, my child pid = %d\n", getpid(), pid);
(gdb) n
I am parent, my pid = 92736, my child pid = 92739
17	        wait(NULL); // 等待子进程退出
(gdb)

上面测试用例中,通过set follow-fork-mode childset detach-on-fork off设置为gdb跟踪子进程,父进程阻塞在fork位置。然后切换到父进程,继续运行父进程。

所有进程同步执行set schedule-multiple on

在调试多进程时,默认情况下,除了当前调试的进程,其他进程都处于挂起状态,所以,如果需要在调试当前进程的时候,其他进程也能正常执行,那么通过设置set schedule-multiple on即可。

set schedule-multiple offgdb发出执行命令后,只有当前进程会执行,其他进程挂起(GDB默认)。

set schedule-multiple on当gdb发出执行命令后,所有的进程都会正常执行。

show schedule-multiple查看schedule-multiple当前值。

调试截图演示

image-20221223220628497

image-20221223220654378

image-20221223220731646

posted @ 2022-12-29 09:48  刘跑跑  阅读(1143)  评论(0编辑  收藏  举报