GDB 基础使用与多进程调试

news/2025/1/15 21:46:14/

在这里插入图片描述

​ GDB 全称“GNU symbolic debugger”是 Linux 下常用的程序调试器,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。

01 GDB 基础调试


1.1 基础使用

  1. 安装工具
# 安装 gcc
sudo yum install gcc
# 安装 g++
sudo yum install gcc-c++ 
# 安装 gdb
sudo yum install gdb
  1. 编译程序
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

  1. 启动 GDB 调试

GDB调试主要有三种方式:

  • 直接调试目标程序:gdb ./basic

  • 附加进程id:gdb attach pid

  • 调试core文件:gdb filename corename

  1. 退出 GDB 调试
  • 可以用命令:q(quit的缩写)或者 Ctr + d 退出 GDB。

  • 如果GDB attach某个进程,退出GDB之前要用命令 detach 解除附加进程。

1.2 常用命令

本节内容转自:GDB使用详解 - 知乎 (zhihu.com)

命令名称命令缩写命令说明
runr运行一个待调试的程序
continuec让暂停的程序继续运行
nextn运行到下一行
steps单步执行,遇到函数会进入
untilu运行到指定行停下来
finishfi结束当前调用函数,回到上一层调用函数处
returnreturn结束当前调用函数并返回指定值,到上一层函数调用处
jumpj将当前程序执行流跳转到指定行或地址
printp打印变量或寄存器值
backtracebt查看当前线程的调用堆栈
framef切换到当前调用线程的指定堆栈
threadthread切换到指定线程
breakb添加断点
tbreaktb添加临时断点
deleted删除断点
enableenable启用某个断点
disabledisable禁用某个断点
watchwatch监视某一个变量或内存地址的值是否发生变化
listl显示源码
infoi查看断点 / 线程等信息
ptypeptype查看变量类型
disassembledis查看汇编代码
set argsset args设置程序启动命令行参数
show argsshow args查看设置的命令行参数

一般调试中最为常用的命令,gdb 语法糖直接回车重复执行上一条命令。

命令名称命令缩写命令说明
breakb添加断点
runr运行一个待调试的程序
nextn运行到下一行(步过)
steps单步执行,遇到函数会进入(步入)
printp打印变量或寄存器值
listl显示当前正在执行代码位置附近的代码
  1. break 打断点
  • break FunctionName,在函数的入口处添加一个断点;
  • break LineNo,在当前文件行号为LineNo处添加断点;
  • break FileName:LineNo,在FileName文件行号为LineNo处添加一个断点;
  • break FileName:FunctionName,在FileName文件的FunctionName函数的入口处添加断点;
  • break -/+offset,在当前程序暂停位置的前/后 offset 行处下断点;
  • break … if cond,下条件断点;
  1. run 运行程序

启用GDB调试只是附加了一个调试文件,并没有启动这个程序,需要输入run命令(简写为r)启动这个程序

  1. next/step 步过/步入
  • next 是 单步步过(step over),即遇到函数直接跳过,不进入函数内部。

  • step 是 单步步入(step into),即遇到函数会进入函数内部。

  1. 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
  1. 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,其中fromto是具体的代码位置,显示这之间的代码;

list命令默认只会输出 10 行源代码,也可以使用如下命令修改:

  • show listsize,查看 list 命令显示的代码行数;
  • set listsize count,设置 list 命令显示的代码行数为 count;

1.3 GDB 基础调试实例

下面结合一个例子熟悉常用的 gdb 调试命令,例子如下:

代码定义了一个静态整型变量param,并初始化为1。

然后定义了两个分别名为func1func2的函数,它接收两个参数 varval,并试图在 将 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切换到另一个进程上下文进行调试
continuec继续执行程序,直到下一个断点或程序结束
backtracebt显示函数调用栈
framef切换到指定堆栈
set args设置程序启动命令行参数
show args查看设置的命令行参数
  1. set follow-fork-mode [parent/child] 指定需要跟踪的子进程

set follow-fork-mode命令必须在程序开始执行前设置才能生效。如果在程序启动后再设置该命令,则不会影响当前正在进行的调试会话。该命令 set follow-fork-mode MODE 可以指定以下三种模式:

  • parent:只跟踪父进程,fork 之后继续调试父进程,子进程不受影响
  • child:只跟踪子进程,fork之后调试子进程,父进程不受影响
  • ask:每次 fork 时询问用户选择
  1. set detach-on-fork [on/off]是否将调试器与进程分离
  • on, 调试器将与新进程分离,以便在进程创建新进程时能够安全地停止和调试新进程,原进程会继续执行,直到调试器与新进程分离为止

  • off,调试器将与新进程紧密关联,一直跟随新进程的执行,原进程不会等待新进程完成复制执行环境后才会重新启动

  1. attach/detach 附加/分离指定进程
  • attach [PID], 让 gdb 附加到已经在运行的进程上进行调试

  • detach [PID],从正在调试的进程中分离gdb调试器

  1. inferior 切换到不同的进程上下文进行调试

inferior [PID | PNAME],其中PID为进程编号,PNAME为进程名称。

  1. continue 终端程序后继续执行

当GDB触发断点或者使用 Ctrl + C 命令中断下来后,想让程序继续运行,只要输入 continue(简写为c)命令即可

  1. bt/f 显示/切换函数调用栈
  • backtrace,也可简写为 bt,用于查看当前调用堆栈
  • frame 堆栈编号,也可简写为 f 堆栈编号,用于切换到其他堆栈处
  1. 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 调试多进程程序 - 简书


http://www.ppmy.cn/news/97095.html

相关文章

如何在华为OD机试中获得满分?Java实现【不爱施肥的小布】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1、题目描述2、输入描述3、输出描述…

如何从宏观层面构建优秀的大语言模型

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

软考A计划-试题模拟含答案解析-卷五

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

ChatGPT原理简介

承接上文GPT前2代版本简介 GPT3的基本思想 GPT2没有引起多大轰动&#xff0c;真正改变NLP格局的是第三代版本。 GPT3训练的数据包罗万象&#xff0c;上通天文下知地理&#xff0c;所以它会胡说八道,会说的贼离谱&#xff0c;比如让你穿越到唐代跟李白对诗&#xff0c;不在一…

17个新手常见的Python运行错误

当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂。这里列出了常见的的一些让你程序 crash 的运行时错误。 1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加 :(导致 “SyntaxError :invalid syntax”) 2)使用 = 而不是 ==(导致“Sy…

Git remote 及 提交操作步骤

Git remote 及 社区提交操作 git remote 本地仓库和远程仓库 repositorygit remote -vtgit remote addgit remote add local [本地仓库路径]git remote rm [远程仓库名] git fetchgit fetchgit fetch [remote_repository]git fetch [remote_repository] [remote_branch_name]FE…

考研C语言第五章

5.2 数组基础知识 注意要点&#xff1a; 1.下标0开始 2.没有定义的地方是0 5.3 数组访问越界与数组传递 访问越界&#xff0c;定义超过前面定义的数组长度&#xff0c;占据了后面定义数据的地方 非常危险&#xff01; 在循环里面往往容易造成越界 数组传递 1.函数引用时…

HDFS基础架构以及部署

HDFS基础架构以及部署 一、HDFS基础简介 什么是HDFS HDFS全称&#xff1a;Hadoop Distributed File System是Hadoop三大组件&#xff08;HDFS,MapReduce,YARN&#xff09;之一可在多台服务器上构建集群&#xff0c;提供分布式数据存储能力 HDFS中的架构角色有哪些 NameNode&a…