
◆ 博主名称: 晓此方-CSDN博客 大家好,欢迎来到晓此方的博客。
⭐️Linux系列个人专栏: 【主题曲】Linux
⭐️ Re系列专栏:我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)

文章目录
- 概要&序論
- 一、 磨刀不误砍柴工:环境配置与模式切换
-
- 1.1 调试的前置条件:Debug vs Release
- 1.2 开启调试大门的钥匙:-g 选项
- 1.3 深度探究:如何证明文件可调试?
- 二、 GDB 核心指令:掌控程序的"生命周期"
-
- 2.1 启动与退出
- 2.2 源码查看(list)
- 2.3 断点管理(Breakpoint)
-
- 2.3.1 打断点的方法
- 2.3.2 查看、删除与使能
- 2.4.2 栈帧回溯
- 2.5 执行流控制:从逐语句到跨越式
- 2.6 变量监视与数据查看
-
- 2.6.1 基础打印与批量查看
- 2.6.2 实时监视(常显示)
- 2.7 进阶执行流控制:until 指令
- 三、 GDB/CGDB 调试高阶技巧
-
- 3.1 CGDB 的安装与高效使用
-
- 3.1.1 安装方式
- 3.1.2 窗口交互与模式切换
- 3.1.3 同步显示优势
- 3.2 变量监视:watch 指令
- 3.3 动态修改程序状态:set var
- 3.4 条件断点(Conditional Breakpoints)
-
- 3.4.1 方式一:新建断点时直接附加条件
- 3.4.2 方式二:为已有断点追加/修改条件
- 3.5 指令快捷操作补充
- 3.6完整速查:GDB 常用调试命令全汇总
概要&序論
Hello大家好我是此方 ,这是一份为开发者准备的 GDB 极简行动指南 。本文剔除冗长的理论,直接聚焦最常用、最有效的调试指令。从启动程序、附加进程到查看寄存器状态,以表格化和案例化的方式,助你快速建立起高效的调试工作流。好,我们开始。
一、 磨刀不误砍柴工:环境配置与模式切换
1.1 调试的前置条件:Debug vs Release
在 Linux 下,默认编译生成的二进制文件通常是 Release 模式 。这种模式下,编译器会对代码进行优化并剔除符号表,导致 GDB 无法关联到源代码。
- Release: 追求运行效率,不可调试。
- Debug: 包含调试信息,体积稍大,允许逐行跟踪。
1.2 开启调试大门的钥匙:-g 选项
使用 gcc 或 g++ 时,必须显式加上 -g 参数以包含调试信息。
- 如果你在命令行手动编译:
直接在编译指令中加入该选项即可。
bash
gcc -g main.c -o processbar
- 如果你在 Makefile 中自动化编译:
通常将 -g 定义在编译参数变量 CFLAGS 中,这样在执行 make 时,所有生成的目标文件都会自动携带调试符号。
bash
# Makefile 示例片段
CC = gcc
CFLAGS = -g -Wall # 在这里统一添加 -g
processbar: main.o
$(CC) $(CFLAGS) -o $@ $^

1.3 深度探究:如何证明文件可调试?
除了观察文件体积增大外,最专业的方法是使用 readelf 工具查看 ELF 文件格式中的调试段。
bash
# 若输出包含 .debug_info 等字段,说明具备调试条件
readelf -S processbar | grep -i debug

二、 GDB 核心指令:掌控程序的"生命周期"
2.1 启动与退出
- 进入:
gdb [bin_file](bin_file 为编译好的可执行程序)。 - 离开: 输入
quit或使用Ctrl + d。
2.2 源码查看(list)
在调试前,我们需要先看到代码。使用 list 指令可以查看源文件内容。
- l (list): 默认列出当前执行行附近的源码。
- l + 行号: 从指定的行号开始向上/向下打印代码。
- l + 文件名:行号: 在多文件工程中,查看指定文件的特定行。
- l + 函数名: 直接跳转到指定函数的起始位置。
技巧: 配合回车键使用,GDB 会自动翻页展示接下来的代码全貌。

2.3 断点管理(Breakpoint)
断点是调试的灵魂,它让程序在指定的时刻"定格"。
2.3.1 打断点的方法
- b 行号: 在当前文件的指定行设置断点(如:
b 10)。 - b 函数名: 在函数入口处设置断点(如:
b main或b Sum)。 - b 文件名:行号: 在多文件调试中,给指定文件打断点(如:
b mycode.c:20)。
避坑指南: 注意不要写成
b main:20这种错误格式。GDB 会将其识别为在main函数处打断点,并忽略后面的行号。




2.3.2 查看、删除与使能
- info b: 列出所有断点及其详细信息。
- Num (编号): 标识断点的 ID。
- Enb (Enable): 断点的"使能"状态(y 为启用,n 为禁用)。
- d 编号: 删除指定编号的断点(如:
d 2)。 - disable 编号: 禁用断点。断点位置保留,但程序运行到此处不会停止。
- enable 编号: 重新启用断点。(断点禁用,与不禁用的意义就是断点位置的意义)
核心逻辑: 在 GDB 中,只有打断点时需要行号 ;一旦断点生成,后续所有的操作(删除、禁用、使能)都必须使用断点编号。


注意: > 1. 断点编号在单次调试会话中是依次递增 的。如果你删除了 2 号断点再新建,新断点编号将是 4(假设之前已有 3)。
- 如果想让断点编号从 1 重新开始,需要退出重进 GDB。
2.4.2 栈帧回溯
- bt (backtrace): 查看当前调用堆栈的栈帧。这能让你清晰地看到当前函数是被哪个函数调用的,以及传递的参数值。这在处理递归程序或多层嵌套调用时极其有用。

2.5 执行流控制:从逐语句到跨越式
- r (run): 运行程序。停在第一个触发的断点处。
- n (next): 逐过程执行(F10)。
- s (step): 逐语句执行(F11)。
- c (continue): 继续运行。跳过当前停顿,跑向下一个断点。
- finish: 运行直至当前函数返回。
- 应用场景: 当你不小心
s进了一个无关紧要的库函数或工具函数时,使用finish可以直接执行完该函数并跳回调用处。(finish也可以触发断点) - 深层逻辑: 如图所示,
int n = Sum(start, end)包含了"调用函数"和"赋值给临时变量"两个动作。finish结束后会停在当前行,等待完成最后的赋值赋值动作。
- 应用场景: 当你不小心

2.6 变量监视与数据查看
在调试过程中,实时掌握变量的变化是定位 Bug 的关键。
2.6.1 基础打印与批量查看
-
p (print) 表达式/变量: 临时打印变量值或计算表达式结果,例如:
p n或p 1+1+2。


-
info locals: 一键查看当前函数栈帧内所有被定义的局部变量及其当前值,无需手动逐个打印。

2.6.2 实时监视(常显示)
- display 变量名: 开启常显示模式。设置后,每执行一步(n 或 s),GDB 都会在屏幕上固定打印该数据及其地址的实时信息,相当于"监视"功能。
- undisplay 编号: 关闭常显示。注意此处必须指定
display指令生成的对应标号 而非变量名。


2.7 进阶执行流控制:until 指令
当面对较长循环且不便设置断点时,until 是极佳的选择。
- until 行号: 直接跑完当前位置到目标行之间的所有代码(包括循环体),并跳转到指定的第 xx 行停止。它能实现"局部跨越式"跳转,极大提高调试效率。

三、 GDB/CGDB 调试高阶技巧
3.1 CGDB 的安装与高效使用
CGDB 是 GDB 的一个轻量级前端界面,它最大的优点是提供了一个代码实时显示窗口。它通过语法高亮和分屏设计,让我们能够像在 IDE 中一样直观地看到当前程序的运行位置。
3.1.1 安装方式
- Ubuntu:
sudo apt-get install -y cgdb - CentOS:
sudo yum install -y cgdb
3.1.2 窗口交互与模式切换
CGDB 将终端分为上下两部分:上方为代码窗口 ,下方为 GDB 指令窗口。
- Esc (进入代码模式): 焦点切换到上方代码窗口。
- 此时可使用 Vim 快捷键 (如
j、k、u、d)进行翻页和浏览。 - 支持
/进行关键字搜索代码。 - 支持空格键快捷打断点/取消断点。
- 此时可使用 Vim 快捷键 (如
- i (进入指令模式): 焦点切换到下方指令窗口,进行标准的 GDB 命令输入。
3.1.3 同步显示优势
- 高亮跟踪: 调试过程中,代码窗口会实时用箭头和高亮色显示当前执行到的行。
- 告别 list: 极大解决了原生 GDB 需要频繁使用
list指令来确认上下文的痛点,调试效率成倍提升。 - 多文件支持: 在跨文件调试时,CGDB 会根据执行流自动切换上方窗口显示的源文件,保持视图与逻辑一致。
3.2 变量监视:watch 指令
如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你.
- 用法:
watch [变量名/表达式]。 - 原理: 当被监视的变量值发生变化时,程序会自动暂停执行,并打印出"旧值"与"新值"。
- 区别: *
display是每走一步打印一次值。watch是只有值变了才停下来提醒你。

3.3 动态修改程序状态:set var
在调试时,如果你想跳过某个错误分支,或者测试特定数值下的程序反应,无需修改代码重新编译。
- 用法:
set var [变量名]=[值]。 - 应用场景: 当程序运行到
if(n == 0)处,你可以通过set var n=1强制程序进入else分支,从而验证不同逻辑路径的正确性。

3.4 条件断点(Conditional Breakpoints)
在处理大型循环或频繁调用的函数时,普通断点会让程序因停顿过于频繁而失去调试意义。条件断点允许我们设定一个过滤规则,仅当满足特定逻辑时,程序才会触发中断。
3.4.1 方式一:新建断点时直接附加条件
这是最常用的方式,在打断点的同时通过 if 关键字声明触发条件。
- 设置方法:
b [行号/函数名] if [条件表达式] - 示例:
b 15 if i == 50 - 效果: 当程序执行到第 15 行时,GDB 会自动计算变量
i的值。只有当i等于 50 时,程序才会停下来;否则直接跳过,极大地提高了在成千上万次循环中定位特定错误的能力。

3.4.2 方式二:为已有断点追加/修改条件
如果你已经设置了一个普通断点,但发现它停顿太频繁,可以使用 condition 指令将其转化为条件断点,或修改其现有条件。
- 设置方法:
condition [断点编号] [条件表达式] - 操作步骤:
- 通过
info b查看目标断点的编号(假设为 2 号)。 - 输入
condition 2 i == 100。
- 通过
- 效果: 2 号断点从此生效的前提变为了
i == 100。 - 取消条件: 如果只想恢复为普通断点,输入
condition [断点编号](不加任何条件)即可清除该断点的限制规则。

3.5 指令快捷操作补充
- Tab 自动补全: 在 GDB/CGDB 中输入指令前缀(如
dis)后按Tab键,可以快速列出所有匹配的指令(如disable,display),有效防止拼写错误。 - 回车记忆功能: 直接按下回车键会重复执行上一条指令,在进行连续的逐过程(
n)或源码翻页(l)时可以大幅减少输入工作量。
3.6完整速查:GDB 常用调试命令全汇总
| 命令 | 简写 | 含义及功能描述 |
|---|---|---|
| list | l | 显示源代码。默认列出 10 行,继续按回车可翻页查看后续代码 |
| list [n] | l [n] | 显示从第 n 行开始的源代码 |
| list [func] | l [func] | 显示函数名为 func 的源代码 |
| run | r | 开始运行程序(若有断点则停在第一个断点处) |
| next | n | 逐过程调试。单步执行,如果遇到函数调用,不进入函数内部 |
| step | s | 逐语句调试。单步执行,如果遇到函数调用,则进入函数内部 |
| break [n] | b [n] | 在第 n 行设置断点 |
| break [func] | b [func] | 在函数 func 的起始处设置断点 |
| break [file]:[n] | b [file]:[n] | 在指定源文件 file 的第 n 行设置断点 |
| info break | i b | 查看当前已设置的所有断点信息(包括编号、状态、地址等) |
| delete [num] | d [num] | 删除断点。num 为断点的编号(通过 info break 查看) |
| disable [num] | dis [num] | 禁用指定编号的断点,断点位置保留但不触发 |
| enable [num] | ena [num] | 启用指定编号的断点 |
| print [expr] | p [expr] | 打印表达式或变量的值 |
| display [var] | display | 常显示变量。设置后每一步执行都会自动打印该变量的值 |
| undisplay [id] | undisplay | 取消指定标号的追踪显示(注意:此处使用 display 产生的编号) |
| until [n] | u [n] | 运行程序直到指定的第 n 行停下(常用于跳出循环) |
| finish | finish | 执行直到当前函数返回。运行完当前函数,停在调用点之后 |
| continue | c | 继续执行程序,直到遇到下一个断点或程序结束 |
| set var [v]=[val] | set var | 在调试过程中动态修改变量 v 的值为 val |
| backtrace | bt | 查看当前的函数调用堆栈(栈帧回溯) |
| info locals | i locals | 查看当前函数栈帧中所有局部变量的值 |
| watch [var] | watch | 设置监视点。当变量 var 的值发生变化时,程序自动停下 |
| quit | q | 退出 GDB 调试 |
| (Enter) | - | 直接回车:重复执行上一条指令 |
| (Tab) | - | 连按两次 Tab 键:指令自动补全或列出候选指令 |
好的本期内容就到这里,如果对你有帮助,还不要忘记点赞三联支持。我是此方,我们下期再见。bye!
Linux第一阶段,正式结束
