断点基础:什么是断点、设置第一个断点(break)、查看断点列表(info breakpoints)、删除与禁用断点
调试嵌入式程序,说白了就是跟代码的「运行时行为」打交道。你写了一个逻辑,但跑起来对不对?数据流没断?中断触发时机准不准?这些问题,光靠看源码是看不出来的。这时候,断点就是你手里最趁手的工具。
我个人习惯,拿到一个新固件,第一件事不是单步跑,而是先下几个关键断点。为什么?因为断点能让你「冻结」现场,看清楚每一刻的状态。今天我们就从最基础的东西聊起。
什么是断点?
断点,就是你在程序里埋的一个「暂停标记」。当CPU执行到这一行时,GDB会把它停下来。你可以趁机查看变量、寄存器、堆栈——说白了,就是让程序「定格」在你关心的那一帧。
我在项目中遇到过一种情况:一个电机控制算法,跑起来总在特定角度下抖动。看代码逻辑没问题,但就是找不到原因。后来我在PWM更新函数入口下了个断点,每次停下来看角度值,才发现是浮点精度截断导致的累积误差。没有断点,这种问题你盯一天也盯不出来。
设置第一个断点:break 命令
设置断点,用 break 命令。简写是 b。用法很灵活,我列几种最常见的:
(gdb) break main # 在 main 函数入口停
(gdb) break 42 # 在当前文件的第42行停
(gdb) break file.c:100 # 在 file.c 的第100行停
(gdb) break func_name # 在某个函数入口停
(gdb) break *0x08001234 # 在绝对地址停(裸机调试常用)
嗯,这里要注意:如果你在中断服务函数里下断点,要小心。中断频率高的话,程序可能一直停在断点里,根本跑不出去。我曾经在UART接收中断里下了个断点,结果串口直接卡死,还以为硬件坏了——其实就是断点触发的次数太多,CPU根本没机会处理后续数据。
查看断点列表:info breakpoints
断点下多了,你总得知道当前有哪些断点、都在哪、状态如何。用 info breakpoints,简写 i b。
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x08000100 main
2 breakpoint keep y 0x08000234 timer_isr
3 breakpoint keep n 0x08000348 uart_send
这张表里,每一列都有用:
| 列名 | 含义 | 我常用的场景 |
|---|---|---|
| Num | 断点编号 | 删除或禁用时用这个编号 |
| Type | 断点类型 | breakpoint 是普通断点,watchpoint 是观察点 |
| Disp | 触发后的行为 | keep 表示保留,del 表示触发一次后自动删除 |
| Enb | 启用状态 | y 启用,n 禁用 |
| Address | 断点地址 | 裸机调试时,我经常对照反汇编确认地址对不对 |
| What | 断点位置描述 | 函数名、文件名+行号 |
你想想看,如果调试一个多任务系统,你下了七八个断点,不查列表根本记不住哪个是哪个。我每次开始调试前,都会先跑一遍 i b,确认当前断点状态。这就像上战场前检查弹药——省得打到一半才发现不对劲。
删除与禁用断点
断点不是越多越好。下多了,程序跑几步就停,调试效率反而低。所以你得学会「管理」断点。
删除断点:clear 和 delete
两个命令都能删断点,但用法不同:
(gdb) clear main # 删除 main 函数处的断点
(gdb) clear file.c:100 # 删除 file.c 第100行的断点
(gdb) delete 2 # 删除编号为2的断点
(gdb) delete # 删除所有断点(慎用!)
clear 是按位置删,delete 是按编号删。我个人更习惯用 delete,因为编号更精确,不会误删。有一次我手快,在调试一个I2C驱动时用了 clear,结果把另一个文件里同名的函数断点也删了——嗯,从那以后我就只用编号删了。
禁用与启用:disable 和 enable
禁用断点,就是让它暂时失效,但保留在列表里。以后想用,再启用就行。
(gdb) disable 3 # 禁用编号为3的断点
(gdb) disable 1 2 4 # 禁用多个断点
(gdb) enable 3 # 启用编号为3的断点
(gdb) enable 1 2 4 # 启用多个断点
禁用断点的好处是什么?举个例子:你在调试一个状态机,有5个状态,每个状态入口都下了断点。现在你只想关注状态3和状态5,那就把其他3个禁用掉。等状态3和5调完了,再启用剩下的。这样不用重新下断点,省事。
我曾经调试一个Bootloader升级流程,下了十几个断点。每次只启用当前关注的2-3个,调完一段就切换。整个流程调下来,断点列表一直保留着,只是不断切换启用状态。效率很高。
知识体系图
下面这张图,把断点的基础操作串起来了。你可以把它当成一个「调试地图」:
这张图把断点的四个核心操作串在了一起。你从「设置断点」开始,然后通过「查看断点」确认状态,最后根据需求选择「删除」或「禁用/启用」。说白了,这就是一个闭环管理流程。
好了,断点的基础操作就这些。你可以在自己的开发板上试试:先下一个断点,跑一下,看看程序停在哪。然后用 i b 查看列表,再用 disable 禁用一个,看看效果。最后用 delete 清理掉。多练几次,这些命令就会变成你的肌肉记忆。
可可精品资料库