4. 断点设置与管理
断点,说白了就是让程序在指定位置停下来的标记。没有断点,调试就像闭着眼睛找 bug——全靠运气。我个人习惯把断点比作“手术刀”,切得准,问题才能看得清。
GDB 的断点系统非常强大,从最简单的 break 到硬件断点、观察点,再到条件断点,每一种都有它的用武之地。今天我们就来逐一拆解。
1. break 命令:最基础的断点
break(简写 b)是最常用的命令。你可以指定行号、函数名、甚至偏移地址。
(gdb) break main # 在 main 函数入口停
(gdb) break 42 # 在当前文件的第 42 行停
(gdb) break foo.c:100 # 在 foo.c 的第 100 行停
(gdb) break *0x400520 # 在指定地址停(汇编级)
我在项目中遇到过一个问题:某个函数被调用了上千次,但只在第 500 次左右才崩溃。如果每次都手动停,手都按酸了。这时候就需要条件断点。
2. 条件断点:精准打击
条件断点就是“满足条件才停”。语法很简单:break [位置] if [条件]。
(gdb) break foo.c:100 if count == 500
(gdb) break my_func if ptr == NULL
(gdb) break 88 if i > 10 && i < 20
嗯,这里要注意:条件表达式必须是 C 语言合法的表达式。GDB 会每次经过断点时求值,如果条件为真就停下。
3. 临时断点:用完即走
临时断点用 tbreak 命令。它和 break 一样,但只生效一次。停住之后,断点自动删除。
(gdb) tbreak main
(gdb) tbreak 42 if flag == 1
什么时候用?比如你想让程序停在某个位置,但只停一次。我经常在调试初始化流程时用:只想看第一次进入某个函数时的状态,后面就不需要了。
4. 硬件断点:对付“写坏内存”的利器
硬件断点(hbreak)依赖 CPU 的调试寄存器。它和软件断点的区别在于:软件断点是在指令码里插入 0xCC(int 3),而硬件断点是用硬件机制来触发。
(gdb) hbreak main
(gdb) hbreak *0x400520
硬件断点数量有限(通常 4 个),但好处是不会修改代码段。对于 ROM 中的代码、或者自修改代码(self-modifying code),软件断点没法用,硬件断点就是唯一选择。
5. 观察点:盯着变量不放
观察点(watch)不是停在某行代码,而是停在某个变量被修改的时刻。它本质上是硬件断点的一种应用。
(gdb) watch my_var # 变量被写时停
(gdb) watch my_var == 100 # 变量变成 100 时停(条件观察点)
(gdb) rwatch my_var # 变量被读时停(只读观察点)
(gdb) awatch my_var # 变量被读或写时停(读写观察点)
观察点特别适合追踪“谁改了我的变量”。我遇到过最经典的一个 bug:一个全局变量莫名其妙变成了 0xDEADBEEF,用 watch 一查,发现是一个野指针写越界了。
不过要注意:观察点会严重拖慢程序。因为 GDB 要单步执行每条指令,检查变量是否变化。对于大循环,慎用。
6. 断点的启用、禁用与删除
调试过程中,断点多了会乱。GDB 提供了管理命令:
(gdb) info breakpoints # 查看所有断点(带编号)
(gdb) disable 2 # 禁用编号为 2 的断点
(gdb) enable 2 # 启用编号为 2 的断点
(gdb) delete 2 # 删除编号为 2 的断点
(gdb) delete # 删除所有断点
每个断点都有一个编号。你可以禁用暂时不需要的断点,而不是删除。这样下次想用时直接 enable 就行。
| 命令 | 作用 | 示例 |
|---|---|---|
| break / b | 设置断点 | b main |
| tbreak | 设置临时断点 | tbreak 42 |
| hbreak | 设置硬件断点 | hbreak *0x4000 |
| watch | 设置写观察点 | watch var |
| rwatch | 设置读观察点 | rwatch var |
| awatch | 设置读写观察点 | awatch var |
| info break | 列出所有断点 | info break |
| disable | 禁用断点 | disable 1 |
| enable | 启用断点 | enable 1 |
| delete | 删除断点 | delete 1 |
知识体系图
下面这张图帮你理清断点的分类和关系:
- break:最常用,适合大多数场景
- tbreak:一次性断点,用完自动删除
- 条件断点:精准定位,避免无效中断
- hbreak:硬件断点,用于 ROM/Flash 调试
- watch:观察变量变化,追踪“谁改了我的数据”
- 管理命令:info/disable/enable/delete,让断点井井有条
断点管理是调试的基本功。我个人建议:调试前先想清楚“我要在哪里停”、“停几次”、“什么条件下停”。想清楚了再动手,效率会高很多。我曾经见过有人一口气设了 20 个断点,结果跑起来到处停,反而找不到问题——断点不是越多越好,精准才是关键。
可可精品资料库