GDB多进程调试

在使用GDB(GNU Debugger)进行多进程调试时,你可以使用几种不同的方法来管理和调试多个进程。这里是一些基本的步骤和技巧:

1. 启动GDB

首先,你需要启动GDB。通常情况下,你可以通过命令行启动GDB并附加到一个正在运行的进程,或者启动一个新的进程。

gdb <程序名>

或者,附加到一个已经存在的进程:

gdb -p <进程ID>

2. 跟踪多个进程

当你的应用程序启动多个进程时,你可以使用 set follow-fork-mode 命令来控制GDB在fork时应该跟踪父进程还是子进程。

  • 跟踪父进程:
(gdb) set follow-fork-mode parent
  • 跟踪子进程:
(gdb) set follow-fork-mode child

3. 切换进程

如果需要在多个进程之间切换,可以使用 info inferiors 命令查看所有进程的列表,然后使用 inferior 命令选择一个进程。

查看进程列表:

(gdb) info inferiors

切换到特定进程(例如切换到编号为2的进程):

(gdb) inferior 2

4. 调试线程

如果在一个多线程的进程中调试,你还可以使用线程相关的命令。查看和切换线程:

  • 查看所有线程:
(gdb) info threads
  • 切换到特定线程:
(gdb) thread <线程号>

5. 继续和中断进程

在调试过程中,你可以控制进程的执行,使用 continue 命令继续执行,使用 interrupt 命令中断一个正在运行的进程。

6. 设置断点

你可以在代码中设置断点,以便在执行到特定的代码行时停下来:

(gdb) break <文件名>:<行号>

或者在函数入口处设置断点:

(gdb) break <函数名>

小技巧

  • 使用 detach 命令可以从当前进程中分离出来,让它继续运行。
detach inferiors id
  • 设置调试模式

    set detach-on-fork on/off
    

    默认为on,表示调试当前进程的时候其他进程被GDB挂起

  • 使用 kill 命令可以终止当前正在调试的进程。

通过这些步骤和命令,你可以有效地使用GDB进行多进程的调试。这对于开发涉及多个进程交互的复杂应用程序尤其有用。

GDB默认调试父进程

daic@daic:~/Linux/linuxwebserver/part02multiProgress/lesson19$ gdb hello
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...done.
(gdb) l
1	#include <stdio.h>
2	#include <unistd.h>
3	
4	int main() {
5	
6	    printf("begin\n");
7	
8	    if(fork() > 0) {
9	
10	        printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) l
11	
12	        int i; 
13	        for(i = 0; i < 10; i++) {
14	            printf("i = %d\n", i);
15	            sleep(1);
16	        }
17	
18	    } else {
19	
20	        printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) b 10
Breakpoint 1 at 0x7c8: file hello.c, line 10.
(gdb) b 20
Breakpoint 2 at 0x81e: file hello.c, line 20.
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000007c8 in main at hello.c:10
2       breakpoint     keep y   0x000000000000081e in main at hello.c:20
(gdb) r
Starting program: /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
begin
我是子进程:pid = 16447, ppid = 16443
j = 0

Breakpoint 1, main () at hello.c:10
10	        printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) j = 1
j = 2
j = 3
j = 4
j = 5
j = 6
j = 7
j = 8
j = 9
n
我是父进程:pid = 16443, ppid = 16428
13	        for(i = 0; i < 10; i++) {
(gdb) n
14	            printf("i = %d\n", i);
(gdb) n
i = 0
15	            sleep(1);
(gdb) n
13	        for(i = 0; i < 10; i++) {
(gdb) n
14	            printf("i = %d\n", i);
(gdb) n
i = 1
15	            sleep(1);
(gdb) c
Continuing.
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
[Inferior 1 (process 16443) exited normally]

(gdb)  show follow-fork-mode 
Debugger response to a program call of fork or vfork is "parent".
(gdb) set follow-fork-mode child
(gdb) show follow-fork-mode 
Debugger response to a program call of fork or vfork is "child".
(gdb)  i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00005555555547c8 in main at hello.c:10
	breakpoint already hit 2 times
2       breakpoint     keep y   0x000055555555481e in main at hello.c:20
(gdb) r
Starting program: /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
begin
[New process 16465]
我是父进程:pid = 16464, ppid = 16428
i = 0
[Switching to process 16465]

Thread 2.1 "hello" hit Breakpoint 2, main () at hello.c:20
20	        printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
n
我是子进程:pid = 16465, ppid = 1
23	        for(j = 0; j < 10; j++) {
(gdb) n
24	            printf("j = %d\n", j);
(gdb) n
j = 0
25	            sleep(1);
(gdb) n
23	        for(j = 0; j < 10; j++) {
(gdb) n
24	            printf("j = %d\n", j);

因为gdb8.1版本存在多进程调试bug,故升级到gdb12.1

升级gdb版本步骤

要将GDB(GNU Debugger)从8.1.1版本升级到12.1版本,你可以按照以下步骤操作。这些步骤适用于大多数Linux发行版,但具体命令可能会根据你的操作系统有所不同。请确保按照适用于你的操作系统的指南进行操作。

步骤1: 卸载旧版本的GDB

在安装新版本之前,建议先卸载旧版本的GDB,以避免版本冲突。你可以使用包管理器来执行此操作,例如在Debian或Ubuntu系统上:

sudo apt-get remove gdb

在Red Hat、CentOS或Fedora上:

sudo yum remove gdb

步骤2: 获取最新版本的GDB

有几种方法可以获取最新版本的GDB:

  1. 通过包管理器安装

如果你的Linux发行版的软件源已经包含了新版本的GDB,你可以直接通过包管理器安装。例如,在Debian或Ubuntu上:

sudo apt-get update
sudo apt-get install gdb

在Red Hat、CentOS或Fedora上:

sudo yum install gdb
  1. 从源代码编译

如果包管理器提供的不是最新版本,或者你需要一个具有特定配置的GDB版本,你可以从源代码编译安装。首先,需要从GNU项目的网站或镜像下载最新的GDB源代码:

  1. 访问 GNU官方网站GDB的FTP镜像 下载最新的源代码包。
  2. 解压下载的源码包:
tar -xvf gdb-12.1.tar.xz
  1. 进入解压后的目录,配置并编译源代码:
cd gdb-12.1
./configure
make
  1. 安装编译后的GDB:
sudo make install

步骤3: 验证安装

安装完成后,你可以通过运行以下命令来验证新版本的GDB是否安装成功:

gdb --version

这条命令应该显示出新安装的GDB版本号,例如“GNU gdb (GDB) 12.1”。

注意事项

  • 在编译GDB之前,确保你的系统已安装了所有必需的依赖项,如gcc, make 和开发工具包。
  • 如果你在使用的系统中遇到权限问题或依赖性错误,确保按照你的系统的具体要求解决这些问题。

这样,你就可以从GDB 8.1.1升级到GDB 12.1了。如果你在升级过程中遇到任何问题,可以查看GDB的官方文档或在相应的社区论坛中寻求帮助。

daic@daic:~/Linux/linuxwebserver/part02multiProgress/lesson19$ gdb hello
GNU gdb (GDB) 12.1
Copyright (C) 2022 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 "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...
(gdb) l
1	#include <stdio.h>
2	#include <unistd.h>
3	
4	int main() {
5	
6	    printf("begin\n");
7	
8	    if(fork() > 0) {
9	
10	        printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) l
11	
12	        int i; 
13	        for(i = 0; i < 10; i++) {
14	            printf("i = %d\n", i);
15	            sleep(1);
16	        }
17	
18	    } else {
19	
20	        printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) set detach-on-fork off
(gdb) b 10
Breakpoint 1 at 0x7c8: file hello.c, line 10.
(gdb) b 20
Breakpoint 2 at 0x81e: file hello.c, line 20.
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000007c8 in main at hello.c:10
2       breakpoint     keep y   0x000000000000081e in main at hello.c:20
(gdb) r
Starting program: /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
begin
[New inferior 2 (process 67145)]

Thread 1.1 "hello" hit Breakpoint 1, main () at hello.c:10
10	        printf("我是父进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) n
我是父进程:pid = 67142, ppid = 67133
13	        for(i = 0; i < 10; i++) {
(gdb) n
14	            printf("i = %d\n", i);
(gdb) n
i = 0
15	            sleep(1);
(gdb) info inferiors 
  Num  Description       Connection           Executable        
* 1    process 67142     1 (native)           /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
  2    process 67145     1 (native)           /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
(gdb) inferior 2
[Switching to inferior 2 [process 67145] (/home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello)]
[Switching to thread 2.1 (process 67145)]
#0  0x00007ffff7ac67cc in fork () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) info inferiors 
  Num  Description       Connection           Executable        
  1    process 67142     1 (native)           /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
* 2    process 67145     1 (native)           /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
(gdb) c
Continuing.

Thread 2.1 "hello" hit Breakpoint 2, main () at hello.c:20
20	        printf("我是子进程:pid = %d, ppid = %d\n", getpid(), getppid());
(gdb) n
我是子进程:pid = 67145, ppid = 67142
23	        for(j = 0; j < 10; j++) {
(gdb) n
24	            printf("j = %d\n", j);
(gdb) n
j = 0
25	            sleep(1);
(gdb) inferior 1
[Switching to inferior 1 [process 67142] (/home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello)]
[Switching to thread 1.1 (process 67142)]
#0  main () at hello.c:15
15	            sleep(1);
(gdb) c
Continuing.
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
[Inferior 1 (process 67142) exited normally]
[Switching to process 67145]
(gdb) info inferiors 
  Num  Description       Connection           Executable        
  1    <null>                                 /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
* 2    process 67145     1 (native)           /home/daic/Linux/linuxwebserver/part02multiProgress/lesson19/hello 
(gdb) n
23	        for(j = 0; j < 10; j++) {
(gdb) n
24	            printf("j = %d\n", j);
(gdb) c
Continuing.
j = 1
j = 2
j = 3
j = 4
j = 5
j = 6
j = 7
j = 8
j = 9
[Inferior 2 (process 67145) exited normally]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值