1. 使用GDB进行断点调试
任务目标
在嵌入式Linux目标板上,使用GDB对一段C程序进行断点调试,掌握设置断点、单步执行、查看变量值三项核心操作。本案例以ARM Cortex-A系列开发板(或QEMU模拟的ARM环境)为运行平台,通过远程GDB调试方式完成一次完整的调试闭环。
环境与依赖
- 目标板:ARM Linux开发板(或QEMU + arm-linux-gnueabihf环境)
- 交叉编译器:arm-linux-gnueabihf-gcc
- 调试器:gdb-multiarch(主机侧),gdbserver(目标板侧)
- 网络:目标板与主机可互相访问(本例使用TCP :2345)
被测程序(target.c)
#include <stdio.h>
int calculate(int a, int b) {
int sum = a + b;
int product = a * b;
return product - sum;
}
int main() {
int x = 7;
int y = 3;
int result = 0;
for (int i = 0; i < 3; i++) {
result += calculate(x + i, y);
}
printf("Final result: %d\n", result);
return 0;
}
编译与部署
# 目标板侧:交叉编译(含调试信息)
arm-linux-gnueabihf-gcc -g -O0 -o target target.c
# 将target复制到目标板,目标板上启动gdbserver
# 假设目标板IP为192.168.1.100
gdbserver 0.0.0.0:2345 ./target
# 主机侧启动gdb-multiarch并连接
gdb-multiarch ./target
(gdb) target remote 192.168.1.100:2345
GDB调试操作
# 在calculate函数入口设置断点
(gdb) break calculate
Breakpoint 1 at 0x1040c: file target.c, line 4.
# 在main函数第12行(for循环内)设置第二个断点
(gdb) break target.c:12
Breakpoint 2 at 0x10454: file target.c, line 12.
# 查看当前断点列表
(gdb) info breakpoints
# 继续执行,应停在第一个断点(calculate入口)
(gdb) continue
Breakpoint 1, calculate (a=7, b=3) at target.c:4
4 int sum = a + b;
# 单步执行(进入函数内部逐行)
(gdb) step
5 int product = a * b;
# 查看当前变量值
(gdb) print a
$1 = 7
(gdb) print b
$2 = 3
(gdb) print sum
$3 = 10
# 继续单步
(gdb) step
6 return product - sum;
# 查看product值
(gdb) print product
$4 = 21
# 执行当前行并停在return处
(gdb) step
7 }
# 查看返回值表达式
(gdb) print product - sum
$5 = 11
# 继续运行,应停在第二个断点(for循环内)
(gdb) continue
Breakpoint 2, main () at target.c:12
12 result += calculate(x + i, y);
# 查看循环变量
(gdb) print i
$6 = 0
(gdb) print x
$7 = 7
(gdb) print y
$8 = 3
# 单步跳过函数调用(不进入calculate)
(gdb) next
13 }
# 查看result累加结果
(gdb) print result
$9 = 11
# 继续执行至程序结束
(gdb) continue
[Inferior 1 (process 1234) exited normally]
验证方法与通过标准
- 程序最终输出
Final result: 33(由代码逻辑可唯一推出:i=0时calculate(7,3)=11,i=1时calculate(8,3)=13,i=2时calculate(9,3)=15,累加得33) - 调试过程中,断点均能准确命中,
print显示的变量值与代码逻辑一致 step进入函数内部逐行执行,next跳过函数调用,两者行为差异可明确观察- 退出GDB后目标板程序正常结束,无段错误或异常退出
常见问题
- 连接失败:确认目标板gdbserver已启动且端口未被占用,主机与目标板网络互通(可ping测试)
- 断点无法命中:检查编译时是否带
-g选项,且未使用-O2以上优化(优化会改变代码行与指令映射) - print显示"optimized out":使用
-O0重新编译
关键点说明
step会进入被调函数内部逐行执行;next将函数调用视为单条语句直接跳过,两者是嵌入式调试中最常用的单步方式- 断点命中后程序完全暂停,此时可安全查看全局变量、局部变量、寄存器值,不会影响目标板外设状态
- 嵌入式远程调试中,
print操作通过RSP协议从目标板读取实时数据,与本地调试行为一致