第一章:GDB入门——从零开始认识调试器
说实话,我刚开始做嵌入式开发那会儿,调试代码全靠printf。那时候觉得,打印大法好,哪里不对打哪里。直到有一次,一个内存越界的问题让我整整排查了三天...后来同事看不下去了,丢给我一句:「你试试GDB吧。」
嗯,从那以后,我再也没离开过GDB。
GDB是什么?
GDB,全称GNU Debugger。说白了,就是一个让你能「看」到程序内部运行状态的工具。
你想想看,平时我们写代码,编译完直接跑。程序崩了,就给你一个Segmentation fault,然后呢?没了。你根本不知道它崩在哪一行,变量值是什么,调用栈长什么样。
GDB就是来解决这个问题的。它让你可以:
- 让程序在任意一行停下来
- 查看那一刻所有变量的值
- 一步步跟踪代码执行
- 查看函数调用链
- 甚至修改内存里的数据
我个人习惯把GDB比作「程序的CT机」。它能给运行中的程序做全身扫描,哪里有问题,一目了然。
GDB能做什么?
我整理了一下,GDB的核心能力其实就这几大类:
| 功能类别 | 具体能力 | 实际场景 |
|---|---|---|
| 断点调试 | 在指定行、函数、条件处暂停 | 定位崩溃位置、检查逻辑错误 |
| 变量查看 | 查看/修改变量值、内存内容 | 确认变量是否如预期变化 |
| 调用栈分析 | 查看函数调用链、回溯崩溃路径 | 排查段错误、空指针 |
| 单步执行 | 逐行、逐函数执行代码 | 理解复杂逻辑、追踪数据流 |
| 多线程/多进程 | 切换线程、查看线程状态 | 调试并发问题、死锁 |
我在项目中遇到过最典型的一个场景:一个服务跑着跑着就挂了,没有任何日志。用GDB挂上去,等它再崩溃时,backtrace一看,发现是一个野指针在作祟。这种问题,printf根本查不出来。
GDB的安装与启动
安装GDB其实很简单。不同系统下命令略有不同:
# Ubuntu/Debian
sudo apt-get install gdb
# CentOS/RHEL
sudo yum install gdb
# macOS (通过Homebrew)
brew install gdb
# 验证安装
gdb --version
嗯,这里要注意:macOS上安装GDB后,还需要做代码签名,否则没法调试。我第一次在Mac上折腾这个,花了大半天...后来发现直接装lldb反而省事。不过咱们课程还是以GDB为主,毕竟Linux下它是标配。
基本调试流程
GDB的调试流程,说白了就四步。我带你走一遍:
第一步:编译带-g选项
这是最关键的一步。没有-g,GDB就不知道源代码长什么样,你看到的全是汇编指令。
// 示例代码:bug.c
#include <stdio.h>
void crash_me() {
int *p = NULL;
*p = 42; // 这里会崩溃
}
int main() {
printf("Hello, GDB!\n");
crash_me();
printf("This won't print\n");
return 0;
}
# 编译时一定要加-g
gcc -g -o bug bug.c
第二步:启动GDB
启动方式有两种:
# 方式一:直接调试可执行文件
gdb ./bug
# 方式二:先启动,再加载文件
gdb
(gdb) file ./bug
我个人习惯用第一种,一步到位。
第三步:运行程序
进入GDB后,用run命令启动程序:
(gdb) run
Starting program: /home/user/bug
Hello, GDB!
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555149 in crash_me () at bug.c:5
5 *p = 42; // 这里会崩溃
看到了吗?GDB直接告诉你在哪一行崩了。这就是-g的威力。
第四步:查看崩溃信息
崩溃后,我们最关心的就是三件事:
- 在哪里崩的 — 用backtrace(简写bt)
- 变量值是什么 — 用print(简写p)
- 调用链是怎样的 — 用frame(简写f)
(gdb) bt
#0 0x0000555555555149 in crash_me () at bug.c:5
#1 0x0000555555555172 in main () at bug.c:10
(gdb) info locals
p = 0x0
(gdb) p *p
Cannot access memory at address 0x0
信息很明确:crash_me函数里,p是空指针,然后试图往空地址写数据,崩了。
知识体系总览
下面这张图,是我梳理的GDB入门知识结构。你可以把它当作学习地图:
核心要点总结:
- GDB是源码级调试器,不是反汇编工具
- -g选项是GDB工作的前提,忘了它GDB就废了一半
- 调试流程就四步:编译带-g → 启动GDB → run运行 → bt/p分析
- 崩溃信息看三个地方:bt看调用链,info locals看变量,list看源码
好了,第一章的内容就到这里。GDB入门其实不难,难的是养成用GDB的习惯。我见过太多人,明明装了GDB,遇到问题还是下意识地加printf。嗯,慢慢来,后面几章我会带你深入每个功能,让你真正爱上这个工具。
可可精品资料库