GDB 全称“GNU symbolic debugger”是 Linux 下常用的程序调试器,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。
01 GDB 基础调试
1.1 基础使用
- 安装工具
# 安装 gcc
sudo yum install gcc
# 安装 g++
sudo yum install gcc-c++
# 安装 gdb
sudo yum install gdb
- 编译程序
gcc -g basic.c -o basic
使用GDB调试程序,编译程序的过程中需要注意以下两点:
🅰️ 要使用GDB调试某个程序,该程序编译时需要加上编译选项 -g
,否则编译生成的程序是不包含调试信息的;
🅱️ GCC编译器支持 -O
和 -g
一起参与编译,关闭编译器的程序优化选项。GCC编译过程对进行优化的程度分为5个等级:-O/O0, -O1, -O2, -O3, -Os,调试时一般选择默认选项 -O 不做任何优化。
调试信息:reference: GDB调试信息与调试原理 - 知乎 (zhihu.com)
如果编译命令中不加 -g 选项,在编译后的程序中不会保留调试符号信息。
加不加该选项在启用 GDB 调试时存在明显区别
gdb basic
(1)不加 -g 选项,尾行打印内容为
Reading symbols from basic...(No debugging symbols found in basic)
(2)加 -g 选项,尾行打印内容为
Reading symbols from basic...
可以看到,不加 -g 选项会直接提示程序不包含调试信息
No debugging symbols found in basic
- 启动 GDB 调试
GDB调试主要有三种方式:
-
直接调试目标程序:gdb ./basic
-
附加进程id:gdb attach pid
-
调试core文件:gdb filename corename
- 退出 GDB 调试
-
可以用命令:q(quit的缩写)或者 Ctr + d 退出 GDB。
-
如果GDB attach某个进程,退出GDB之前要用命令 detach 解除附加进程。
1.2 常用命令
本节内容转自:GDB使用详解 - 知乎 (zhihu.com)
命令名称 | 命令缩写 | 命令说明 |
---|---|---|
run | r | 运行一个待调试的程序 |
continue | c | 让暂停的程序继续运行 |
next | n | 运行到下一行 |
step | s | 单步执行,遇到函数会进入 |
until | u | 运行到指定行停下来 |
finish | fi | 结束当前调用函数,回到上一层调用函数处 |
return | return | 结束当前调用函数并返回指定值,到上一层函数调用处 |
jump | j | 将当前程序执行流跳转到指定行或地址 |
p | 打印变量或寄存器值 | |
backtrace | bt | 查看当前线程的调用堆栈 |
frame | f | 切换到当前调用线程的指定堆栈 |
thread | thread | 切换到指定线程 |
break | b | 添加断点 |
tbreak | tb | 添加临时断点 |
delete | d | 删除断点 |
enable | enable | 启用某个断点 |
disable | disable | 禁用某个断点 |
watch | watch | 监视某一个变量或内存地址的值是否发生变化 |
list | l | 显示源码 |
info | i | 查看断点 / 线程等信息 |
ptype | ptype | 查看变量类型 |
disassemble | dis | 查看汇编代码 |
set args | set args | 设置程序启动命令行参数 |
show args | show args | 查看设置的命令行参数 |
一般调试中最为常用的命令,gdb 语法糖直接回车重复执行上一条命令。
命令名称 | 命令缩写 | 命令说明 |
---|---|---|
break | b | 添加断点 |
run | r | 运行一个待调试的程序 |
next | n | 运行到下一行(步过) |
step | s | 单步执行,遇到函数会进入(步入) |
p | 打印变量或寄存器值 | |
list | l | 显示当前正在执行代码位置附近的代码 |
- break 打断点
- break FunctionName,在函数的入口处添加一个断点;
- break LineNo,在当前文件行号为LineNo处添加断点;
- break FileName:LineNo,在FileName文件行号为LineNo处添加一个断点;
- break FileName:FunctionName,在FileName文件的FunctionName函数的入口处添加断点;
- break -/+offset,在当前程序暂停位置的前/后 offset 行处下断点;
- break … if cond,下条件断点;
- run 运行程序
启用GDB调试只是附加了一个调试文件,并没有启动这个程序,需要输入run命令(简写为r)启动这个程序
- next/step 步过/步入
next 是 单步步过(step over),即遇到函数直接跳过,不进入函数内部。
step 是 单步步入(step into),即遇到函数会进入函数内部。
- print 查看变量值
- print param,用于在调试过程中查看变量的值;
- print param=value,用于在调试过程中修改变量的值;
- print a+b+c,可以进行一定的表达式计算,这里是计算a、b、c三个变量之和;
- print func(),输出
func
函数执行的结果,常见的用途是打印系统函数执行失败原因:print strerror(errno)
;- *print this,在c++对象中,可以输出当前对象的各成员变量的值;
- print arrname@arrlen,输出数组 arrname
- list 显示源码上下文
list,输出上一次list命令显示的代码后面的代码,如果是第一次执行list命令,则会显示当前正在执行代码位置附近的代码;
list -,带一个减号,显示上一次list命令显示的代码前面的代码;
list LineNo,显示当前代码文件第 LineNo 行附近的代码;
list FileName:LineNo,显示 FileName 文件第 LineNo 行附近的代码;
list FunctionName,显示当前文件的 FunctionName 函数附近的代码;
list FileName:FunctionName,显示 FileName 文件的 FunctionName 函数附件的代码;
list from,to,其中from和to是具体的代码位置,显示这之间的代码;
list命令默认只会输出 10 行源代码,也可以使用如下命令修改:
- show listsize,查看 list 命令显示的代码行数;
- set listsize count,设置 list 命令显示的代码行数为 count;
1.3 GDB 基础调试实例
下面结合一个例子熟悉常用的 gdb 调试命令,例子如下:
代码定义了一个静态整型变量param
,并初始化为1。
然后定义了两个分别名为func1
和func2
的函数,它接收两个参数 var
和val
,并试图在 将 var
的值修改为val
。但是func1
中形参是值传递,函数外部无法实现参数值的修改;func2
中形参是引用传递,能够完成参数值修改。
最后定义了主函数main
,调用func
函数,将i
的值改为1,并将param
加上i
的值。
#include<stdio.h>
static int param = 1;
void func1(int var, int val){
var = val;
printf("function func1 has been called!");
}
void func2(int *var, int val){
*var = val;
printf("function func2 has been called!");
}
int main(){
int i = 0;
func1(i, 1);
func2(&i, 1);
param += i;
printf("function main has been called!");
return 0;
}
首先编译该程序并启用 GDB 调试
$ gcc -g basic.c -o basic
$ gdb basic
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 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-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 basic...
使用 b 命令将断点打在 main
函数入口,并使用 r 命令运行程序
(gdb) b main
Breakpoint 1 at 0x11d7: file basic.c, line 15.
(gdb) r
Starting program: /home/randy/study/dev-tool/gdb/basic
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at basic.c:15
15 int main(){
使用 n 命令执行下一行语句,遇到函数直接跳过不进入;使用 s 命令步入函数 func1(i,1);
,并使用 l 命令查看当前语句在源码中的上下文。
(gdb) n
17 int i = 0;
(gdb)
18 func1(i, 1);
(gdb) s
func1 (var=0, val=1) at basic.c:6
6 var = val;
(gdb) l
1 #include<stdio.h>
2
3 static int param = 1;
4
5 void func1(int var, int val){
6 var = val;
7 printf("function func1 has been called!");
8 }
9
10 void func2(int *var, int val){
使用 p 命令查看 func1(var, val)
中 var 在修改前后的值,并查看在 func1
函数执行完成之后,传入的实参 i
的值未完成修改,仍为 0;
(gdb) p var
$1 = 0
(gdb) n
7 printf("function func1 has been called!");
(gdb) p var
$2 = 1
(gdb) n
8 }
(gdb)
main () at basic.c:19
19 func2(&i, 1);
(gdb) p i
$3 = 0
使用 n 命令步过可以完成 i
值修改的函数 func2
,并查看修改之后的值为 1
(gdb)
main () at basic.c:19
19 func2(&i, 1);
(gdb) p i
$3 = 0
(gdb) n
20 param += i;
(gdb) p i
$4 = 1
(gdb) p param
$5 = 1
(gdb) n
21 printf("function main has been called!");
(gdb) p param
$6 = 2
(gdb) n
23 return 0;
(gdb) n
24 }
上述完整 gdb 调试过程如下:
$ gdb gcc -g basic.c -o basic
$ gdb gdb basic
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 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-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:
--Type <RET> for more, q to quit, c to continue without paging--
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from basic...
(gdb) b main
Breakpoint 1 at 0x11d7: file basic.c, line 15.
(gdb) r
Starting program: /home/randy/study/dev-tool/gdb/basic
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at basic.c:15
15 int main(){
(gdb) n
17 int i = 0;
(gdb)
18 func1(i, 1);
(gdb) s
func1 (var=0, val=1) at basic.c:6
6 var = val;
(gdb) l
1 #include<stdio.h>
2
3 static int param = 1;
4
5 void func1(int var, int val){
6 var = val;
7 printf("function func1 has been called!");
8 }
9
10 void func2(int *var, int val){
(gdb) p var
$1 = 0
(gdb) n
7 printf("function func1 has been called!");
(gdb) p var
$2 = 1
(gdb) n
8 }
(gdb)
main () at basic.c:19
19 func2(&i, 1);
(gdb) p i
$3 = 0
(gdb) n
20 param += i;
(gdb) p i
$4 = 1
(gdb) p param
$5 = 1
(gdb) n
21 printf("function main has been called!");
(gdb) p param
$6 = 2
(gdb) n
23 return 0;
(gdb) n
24 }
(gdb) n
02 GDB 调试多进程程序
2.1 多进程调试中常用的 GDB 命令
命令名称 | 命令缩写 | 命令说明 |
---|---|---|
set follow-fork-mode | 设置需要跟踪的子进程 | |
set detach-on-fork | 设置在程序运行时是否将调试器与进程分离 | |
attach | 附加到正在运行的进程进行调试 | |
detach | 从正在调试的进程中分离gdb调试器 | |
inferior | 切换到另一个进程上下文进行调试 | |
continue | c | 继续执行程序,直到下一个断点或程序结束 |
backtrace | bt | 显示函数调用栈 |
frame | f | 切换到指定堆栈 |
set args | 设置程序启动命令行参数 | |
show args | 查看设置的命令行参数 |
- set follow-fork-mode [parent/child] 指定需要跟踪的子进程
set follow-fork-mode
命令必须在程序开始执行前设置才能生效。如果在程序启动后再设置该命令,则不会影响当前正在进行的调试会话。该命令set follow-fork-mode MODE
可以指定以下三种模式:
parent
:只跟踪父进程,fork 之后继续调试父进程,子进程不受影响child
:只跟踪子进程,fork之后调试子进程,父进程不受影响ask
:每次 fork 时询问用户选择
- set detach-on-fork [on/off]是否将调试器与进程分离
on, 调试器将与新进程分离,以便在进程创建新进程时能够安全地停止和调试新进程,原进程会继续执行,直到调试器与新进程分离为止
off,调试器将与新进程紧密关联,一直跟随新进程的执行,原进程不会等待新进程完成复制执行环境后才会重新启动
- attach/detach 附加/分离指定进程
attach [PID], 让 gdb 附加到已经在运行的进程上进行调试
detach [PID],从正在调试的进程中分离gdb调试器
- inferior 切换到不同的进程上下文进行调试
inferior [PID | PNAME],其中
PID
为进程编号,PNAME
为进程名称。
- continue 终端程序后继续执行
当GDB触发断点或者使用 Ctrl + C 命令中断下来后,想让程序继续运行,只要输入 continue(简写为c)命令即可
- bt/f 显示/切换函数调用栈
- backtrace,也可简写为 bt,用于查看当前调用堆栈
- frame 堆栈编号,也可简写为 f 堆栈编号,用于切换到其他堆栈处
- set/show args 设置/查看命令行参数
- set args args1,设置单个启动参数 args1;
- set args “-p” “password”,如果单个参数之间有空格,可以使用引号将参数包裹起来;
- set args args1 args2 args3,设置多个启动参数,参数之间用空格隔开;
- set args,不带参数,则清除之前设置的参数;
2.2 GDB 多进程调试实例
下面结合一个例子介绍 gdb 调试多进程程序,例子如下:
程序首先创建了一个管道,然后通过fork()
函数创建了两个子进程。
在第一个子进程中,它向管道的写端写入了一条消息,然后退出;在第二个子进程中,它从管道的读端读取了这条消息,并将其打印出来,然后退出。
父进程在创建完子进程后,关闭了管道的读端和写端,并分别等待两个子进程结束。
当两个子进程都结束时,父进程才会继续执行,并打印一条消息表示所有子进程都已完成。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int pipefd[2]; // 管道描述符数组
pid_t pid1, pid2; // 子进程ID变量
if (pipe(pipefd) == -1) { // 创建管道
perror("pipe");
exit(EXIT_FAILURE);
}
pid1 = fork(); // 创建第一个子进程
if (pid1 == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid1 == 0) { // 在第一个子进程中
close(pipefd[0]); // 关闭读端
char msg[] = "Hello, I'm child process 1!";
write(pipefd[1], msg, strlen(msg)); // 向写端写入消息
close(pipefd[1]); // 关闭写端
exit(EXIT_SUCCESS);
}
pid2 = fork(); // 创建第二个子进程
if (pid2 == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid2 == 0) { // 在第二个子进程中
close(pipefd[1]); // 关闭写端
char buf[1024];
read(pipefd[0], buf, sizeof(buf)); // 从读端读取消息
printf("This is child process 2. Received message from child process 1: %s\n", buf);
close(pipefd[0]); // 关闭读端
exit(EXIT_SUCCESS);
}
// 父进程中
close(pipefd[0]); // 关闭读端
close(pipefd[1]); // 关闭写端
waitpid(pid1, NULL, 0); // 等待第一个子进程结束
waitpid(pid2, NULL, 0); // 等待第二个子进程结束
printf("All child processes have completed.\n");
return 0;
}
2.2.1 调试父进程
首先编译该程序并启用 GDB 调试
$ gdb gcc -g multi_process.c -o multi_process
$ gdb gdb multi_process
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 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-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 multi_process...
set follow-fork-mode parent 设置仅跟踪父进程(也可以直接跳过这个步骤,默认 parent);使用 b 命令将断点打在 main
函数入口;并使用 r 命令运行程序。
(gdb) set follow-fork-mode parent
(gdb) b main
Breakpoint 1 at 0x4007f8: file multi_process.c, line 11.
(gdb) r
Starting program: /home/randy/study/dev-tool/gdb/multi_process
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at multi_process.c:7
7 int main() {
使用 n 命令单步执行,查看程序执行情况,可以看到第一个子进程在被 fork 成功之后就从 gdb 调试中分离并继续执行了 [Detaching after fork from child process 20228]
(gdb) n
16 pid1 = fork(); // 创建第一个子进程
(gdb) p pid1
$1 = 0
(gdb) n
[Detaching after fork from child process 20228]
17 if (pid1 == -1) {
(gdb)
22 if (pid1 == 0) { // 在第一个子进程中
同样的继续使用 n 命令单步执行,可以看到第二个子进程在被 fork 成功之后也从 gdb 调试中分离 [Detaching after fork from child process 20415]
(gdb)
30 pid2 = fork(); // 创建第二个子进程
(gdb) p pid2
$2 = 0
(gdb) n
[Detaching after fork from child process 20415]
# 第二个子进程执行完成读取第一个子进程发送的消息并打印如下输出
This is child process 2. Received message from child process 1: Hello, I'm child process 1!
31 if (pid2 == -1) {
(gdb)
36 if (pid2 == 0) { // 在第二个子进程中
(gdb)
46 close(pipefd[0]); // 关闭读端
(gdb)
47 close(pipefd[1]); // 关闭写端
(gdb)
48 waitpid(pid1, NULL, 0); // 等待第一个子进程结束
(gdb)
49 waitpid(pid2, NULL, 0); // 等待第二个子进程结束
(gdb)
50 printf("All child processes have completed.\n");
(gdb)
All child processes have completed.
52 return 0;
2.2.2 调试第一个子进程
首先编译该程序并启用 GDB 调试
$ gdb gcc -g multi_process.c -o multi_process
$ gdb gdb multi_process
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 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-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 multi_process...
set follow-fork-mode child 设置跟踪子进程,使用 b 命令将断点打在 main
函数入口,并使用 r 命令运行程序
(gdb) set follow-fork-mode child
(gdb) b main
Breakpoint 1 at 0x12b8: file multi_process.c, line 7.
(gdb) r
Starting program: /home/randy/study/dev-tool/gdb/multi_process
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at multi_process.c:7
7 int main() {
n 单步执行程序,直到第一个子进程 pid1=0
(gdb) n
11 if (pipe(pipefd) == -1) { // 创建管道
(gdb)
16 pid1 = fork(); // 创建第一个子进程
(gdb) p pid1
$1 = 0
(gdb) n
[Attaching after Thread 0x7ffff7d8c740 (LWP 5001) fork to child process 5166] # 表示gdb正在附加到一个已经fork出子进程的父进程中
[New inferior 2 (process 5166)] # 表示gdb创建了一个新的被调试进程,并将其编号设置为2,该进程的PID为5166
[Detaching after fork from parent process 5001] # 表示gdb从父进程中分离出子进程,将其作为独立的被调试进程进行调试
[Inferior 1 (process 5001) detached] # 表示gdb已经从原始的父进程中分离出来,成为一个独立的进程(或线程)控制器。由于该进程的编号为1,因此显示为Inferior 1
[Thread debugging using libthread_db enabled] # 表示gdb使用libthread_db库来进行线程调试
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Switching to Thread 0x7ffff7d8c740 (LWP 5166)] # 表示gdb正在切换到子进程的线程上进行调试
main () at multi_process.c:17
17 if (pid1 == -1) {
在子进程中 使用 n 命令单步执行并观察变量值,由于 set follow-fork-mode child 只跟踪子进程,在上一步中 [Inferior 1 (process 5001) detached]
表示 gdb 已经将父进程分离并继续执行,所以在下面的内容中第一个子进程写完消息之后,第二个子进程就收到了消息并在打印后退出了。
(gdb) n
22 if (pid1 == 0) { // 在第一个子进程中
(gdb)
23 close(pipefd[0]); // 关闭读端
(gdb)
24 char msg[] = "Hello, I'm child process 1!";
(gdb) p msg
$1 = "`\317\377\367\377\177\000\000\330J\374\367\377\177\000\000\000\000\000\000\000\000\000\000\060\334\377\377"
(gdb) n
25 write(pipefd[1], msg, strlen(msg)); // 向写端写入消息
(gdb)
This is child process 2. Received message from child process 1: Hello, I'm child process 1!
26 close(pipefd[1]); // 关闭写端
(gdb)
27 exit(EXIT_SUCCESS);
(gdb)
[Inferior 2 (process 6971) exited normally]
All child processes have completed.
2.2.3 调试第二个子进程
首先编译该程序并启用 GDB 调试
$ gdb gcc -g multi_process.c -o multi_process
$ gdb gdb multi_process
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 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-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 multi_process...
先设置跟踪父进程 set follow-fork-mode parent 来跳过第一个子进程的 fork 操作;使用 b 命令将断点打在创建第二个子进程的 fork 函数之前;并使用 r 命令运行程序。
(gdb) set follow-fork-mode parent
(gdb) b multi_process.c:22
Breakpoint 1 at 0x40083f: file multi_process.c, line 22.
(gdb) r
Starting program: /home/randy/study/dev-tool/gdb/multi_process
[Detaching after fork from child process 25249] # 分离第一个子进程
Breakpoint 1, main () at multi_process.c:22
22 if (pid1 == 0) { // 在第一个子进程中
在继续执行程序前 set follow-fork-mode child 设置 gdb 调试跟踪子进程,然后再使用 n 命令单步执行 fork 创建第二个子进程,可以看到第二个子进程在被 fork 成功之后,gdb 调试就分离的父进程,并切换到第二个子进程中。
(gdb) set follow-fork-mode child
(gdb) n
30 pid2 = fork(); // 创建第二个子进程
(gdb) n
[Attaching after process 25358 fork to child process 25358]
[New inferior 2 (process 25358)]
[Detaching after fork from parent process 25245]
[Inferior 1 (process 25245) detached] # 已经分离父进程
[Switching to process 25358] # 切换到第二个子进程
31 if (pid2 == -1) {
进入第二个子进程后,就可以使用 n 命令单步执行程序,使用 p 命令查看变量值。
(gdb) n
36 if (pid2 == 0) { // 在第二个子进程中
(gdb) p pid2
$1 = 0
(gdb) n
37 close(pipefd[1]); // 关闭写端
(gdb) n
39 read(pipefd[0], buf, sizeof(buf)); // 从读端读取消息
(gdb) n
40 printf("This is child process 2. Received message from child process 1: %s\n", buf);
(gdb) p buf
$2 = "Hello, I'm child process 1!", '\000' <repeats 477 times>...
(gdb) n
This is child process 2. Received message from child process 1: Hello, I'm child process 1!
41 close(pipefd[0]); // 关闭读端
(gdb) n
42 exit(EXIT_SUCCESS);
(gdb)
[Inferior 2 (process 25358) exited normally]
All child processes have completed.
如果文章对你有帮助,欢迎一键三连 👍 ⭐️ 💬 。如果还能够点击关注,那真的是对我最大的鼓励 🔥 🔥 🔥 。
参考资料
GDB Documentation
学习使用 GDB 调试代码 | Linux 中国 - 知乎 (zhihu.com)
GDB使用详解 - 知乎 (zhihu.com)
使用 GDB 调试多进程程序 - 简书