🧭 说明
GDB(GNU Debugger)是Linux下功能强大的命令行调试工具,主要用于C、C++等由GNU编译器集合(GCC)编译的程序。它允许开发者在程序运行时检查其内部状态,帮助定位和修复错误。
下面是一个GDB核心功能的快速参考表,帮助建立整体印象。
| 功能类别 | 常用命令 | 简写 | 作用 |
|---|---|---|---|
| 启动与退出 | gdb [可执行文件] | - | 启动GDB并加载程序 |
run [参数] | r | 开始运行程序 | |
quit | q | 退出GDB | |
| 断点管理 | break [行号/函数名] | b | 设置断点 |
info breakpoints | i b | 查看所有断点信息 | |
delete [断点编号] | d | 删除断点 | |
enable/disable [编号] | - | 启用/禁用断点 | |
| 执行控制 | next | n | 逐过程执行,不进入函数内部 |
step | s | 逐语句执行,会进入函数内部 | |
continue | c | 继续运行直至下一个断点 | |
finish | fi | 执行完当前函数并跳出 | |
| 查看信息 | print [表达式] | p | 打印变量或表达式的值 |
backtrace | bt | 显示函数调用堆栈(非常有用于定位崩溃点) | |
list | l | 列出源代码 | |
info locals | i locals | 显示当前栈帧的局部变量 | |
| 高级功能 | watch [表达式] | - | 设置观察点,当表达式值改变时暂停 |
thread [线程ID] | thr | 切换到指定线程 | |
x/[数量][格式][单元] [地址] | x | 检查指定内存地址的内容 |
💡 调试准备与核心步骤
编译程序:使用GDB调试的前提是,在编译程序时必须加上
-g选项,以便在可执行文件中嵌入调试信息。gcc -g -o myprogram myprogram.c核心调试流程:一个典型的调试会话遵循以下步骤:
- 启动:使用
gdb ./myprogram启动调试器。 - 设断:在关键代码行或函数入口设置断点,例如
b main或b 15。 - 运行:输入
run开始执行程序,它会在遇到的第一个断点处暂停。 - 检查:程序暂停后,使用
print、backtrace、info locals等命令检查程序状态。 - 单步:使用
next(逐过程)或step(逐语句)来逐步执行代码,观察程序行为。
- 启动:使用
🛠️ 实用进阶技巧
掌握基础命令后,以下技巧可以更高效地解决复杂问题。
- 条件断点:可以设置只在特定条件下触发的断点。例如,
break 10 if i==5表示仅当变量i等于5时,才在第10行触发断点。这在调试循环或特定场景时非常有用。 - 监视点:使用
watch variable_name命令,当指定的变量被修改时,程序会自动暂停。这对于追踪难以发现的意外数据改变至关重要。 - 多线程调试:使用
info threads查看所有线程,使用thread [线程ID]切换当前调试的线程。还可以通过set scheduler-locking on命令在单步调试时只让当前线程执行,避免其他线程干扰。 - 调试已运行的程序:可以使用
gdb -p <进程号>或gdb attach <进程号>命令直接调试一个正在运行的进程,无需重启程序。 - 查看内存:
x命令可以按指定格式检查内存内容。例如,x/10i $pc会显示从当前程序计数器位置开始的10条汇编指令。
🧪 一个简单的调试示例
假设有一个简单的C程序hello.c,它意外崩溃了。
// hello.c#include<stdio.h>intmain(){char*str=NULL;printf("%s\n",str);// 这里会引发段错误return0;}调试过程可能如下:
# 1. 带调试信息编译gcc -g -o hello hello.c# 2. 启动GDBgdb ./hello# 3. 直接运行,程序会崩溃(gdb)run Program received signal SIGSEGV, Segmentation fault.# 4. 查看崩溃时的调用堆栈(gdb)bt#0 0x00007ffff7e56155 in __strlen_avx2 () from /lib/x86_64-linux-gnu/libc.so.6#1 0x00007ffff7e2e2f3 in __printf() from /lib/x86_64-linux-gnu/libc.so.6#2 0x000055555555515d in main () at hello.c:4# 5. 堆栈显示问题出在main函数的第4行,打印变量str的值(gdb)p str$1=0x0# 6. 发现str是NULL,这就是导致崩溃的原因💎 总结
GDB的功能非常丰富,以上介绍的是最常用和核心的部分。最好的学习方式就是边用边学,在实际调试中结合help [命令名]来探索更多功能。