2. GDB 基础入门:安装、启动与核心命令

GDB(GNU Debugger)是 Linux 系统下最经典的符号级调试器,也是缺陷定位工具链的前端核心。本章从零开始搭建 GDB 环境,并掌握调试会话中最常用的 7 个命令,为后续与 Valgrind 联合分析打下基础。

2.1 安装与版本确认

GDB 几乎包含在所有主流发行版的官方源中,安装方式因包管理器而异:

发行版 安装命令 验证命令
Ubuntu / Debian sudo apt install gdb gdb --version
CentOS / RHEL / Fedora sudo yum install gdb 或 sudo dnf install gdb gdb --version
Arch Linux sudo pacman -S gdb gdb --version
macOS (Homebrew) brew install gdb(需额外代码签名) gdb --version
调试符号提示: 使用 GDB 调试前,编译目标程序时必须添加 -g 选项,否则无法查看源码行号和变量名。推荐同时关闭优化 -O0,避免调试时变量被优化掉。
# 编译带调试符号的可执行文件
gcc -g -O0 -o example example.c

2.2 启动 GDB 的三种方式

GDB 提供了灵活的启动入口,适应不同的调试场景:

  1. 直接加载可执行文件:gdb ./example —— 最常用方式,启动后进入交互式命令行。
  2. 附加到正在运行的进程:gdb -p <PID> —— 用于调试已经启动的服务或卡死进程。
  3. 分析 core dump 文件:gdb ./example core —— 事后分析崩溃现场,无需复现。
实战建议: 课程后续章节将大量使用第一种方式。附加进程和 core dump 分析会在“崩溃现场还原”部分深入讲解。

2.3 核心命令速览

以下 7 个命令覆盖了 90% 的日常调试操作,按“启动→设置断点→单步执行→观察变量→退出”的流程组织:

命令 缩写 功能说明 常用示例
run r 启动程序,可带命令行参数 run arg1 arg2
break b 设置断点(行号/函数/条件) b main、b 42、b foo if x > 5
next n 单步执行,不进入函数内部 n 或 n 3(执行 3 步)
step s 单步执行,进入函数内部 s
continue c 恢复执行直到下一个断点 c
print p 打印变量或表达式的值 p x、p &y、p array[3]
quit q 退出 GDB q

2.4 典型调试流程(内联 SVG)

下图展示了一次标准 GDB 调试会话的完整步骤,从启动到退出,箭头表示命令触发的事件流转:

GDB 典型调试流程 GDB 典型调试流程 启动 GDB 设置断点 (break) 运行 (run) 命中断点,暂停执行 单步 (next/step) 继续 (continue) 打印变量 (print) 退出 (quit) 说明:单步执行后可继续观察变量或继续运行,直到程序结束或再次命中断点。

2.5 命令组合实战示例

以下是一个完整的调试会话,演示如何定位一个简单的除零错误:

# 1. 编译带调试符号的程序
gcc -g -O0 -o divide divide.c

# 2. 启动 GDB
gdb ./divide

# 3. 在 main 函数入口设置断点
(gdb) break main
Breakpoint 1 at 0x4004f6: file divide.c, line 8.

# 4. 运行程序
(gdb) run
Starting program: /home/user/divide 
Breakpoint 1, main () at divide.c:8
8           int a = 10, b = 0, result;

# 5. 单步执行到除法操作
(gdb) next
9           result = a / b;

# 6. 打印变量确认
(gdb) print a
$1 = 10
(gdb) print b
$2 = 0

# 7. 继续执行,程序崩溃
(gdb) continue
Program received signal SIGFPE, Arithmetic exception.
0x00000000004004fc in main () at divide.c:9
9           result = a / b;

# 8. 退出 GDB
(gdb) quit
常见误区: 初学者容易混淆 next 和 step。当调试到函数调用时,next 会直接执行完整个函数并停在下一行,而 step 会跳入函数内部逐行执行。如果希望观察函数内部逻辑,必须使用 step。

2.6 命令对比速查表

为了帮助快速区分容易混淆的命令对,下表总结了关键差异:

命令对 行为差异 适用场景
next vs step next 不进入函数;step 进入函数 确认函数返回值时用 next;排查函数内部缺陷时用 step
continue vs run continue 从暂停点恢复;run 从头启动 调试循环或多次触发时用 continue;需要重置状态时用 run
print vs break 条件 print 手动查看;条件断点自动暂停 少量变量用 print;大量循环中监控特定值用条件断点

2.7 本章小结