GDB 调试与 Core Dump(段错误)排查指南(Linux/C/C++)
GDB 调试与 Core Dump(段错误)排查指南(Linux/C/C++)
目录(大纲)
- 1. GDB 是什么?能解决什么问题?
- 2. 编译准备:一定要带调试信息
- 3. GDB 常用命令速查(高频)
- 4. 实战:用 GDB 定位段错误(SIGSEGV)
- 5. Core Dump:程序崩了也能“回放现场”
- 6. 段错误(Segmentation fault)常见原因总结
- 7. 高效排查套路(建议你照着做)
- 8. 进阶小技巧(可选但很实用)
- 9. 总结
- 参考资料(可扩展阅读)
1. GDB 是什么?能解决什么问题?
GDB(GNU Debugger)是 Linux 平台最常用的程序调试器之一,主要用来:
- 断点调试:在指定代码行/函数处暂停,观察程序状态。
- 单步执行:一行一行执行,定位逻辑错误。
- 查看/修改变量:实时查看局部变量、参数、全局变量,必要时可临时修改变量值验证思路。
- 调用栈回溯:程序崩溃后查看调用链(
bt/where),快速定位问题入口。 - Core Dump 事后分析:程序崩溃生成 core 文件后,用 GDB 还原“事故现场”。
适用场景:段错误(SIGSEGV)、非法访问、野指针、栈溢出、数组越界、use-after-free 等。
2. 编译准备:一定要带调试信息
调试/分析崩溃时,可执行文件与崩溃现场必须匹配(同版本、同编译产物)。建议:
# 推荐:关闭过度优化,保留调试信息 gcc -g -O0 main.c -o app # 或者 C++ g++ -g -O0 main.cpp -o app -g:生成调试符号(行号、变量名、函数名)-O0/-Og:降低优化程度,避免变量被优化掉导致<value optimized out>
3. GDB 常用命令速查(高频)
3.1 启动与加载
# 方式1:直接调试可执行文件 gdb ./app # 方式2:带参数启动(也可在 gdb 内 set args) gdb --args ./app arg1 arg2 # 方式3:调试 core 文件(事后分析) gdb ./app /path/to/core # 或 gdb -c /path/to/core ./app 3.2 断点/运行控制
| 命令 | 缩写 | 作用 |
|---|---|---|
break <位置> | b | 设置断点(行号/函数名/文件:行号) |
info breakpoints | i b | 查看断点列表 |
delete <编号> | d | 删除断点 |
run | r | 启动程序(命中断点会停住) |
continue | c | 继续运行到下一个断点/结束 |
next | n | 单步执行(不进入函数) |
step | s | 单步执行(进入函数) |
finish | 跑完当前函数并返回到上一层 | |
until | u | 运行到指定行/跳出循环场景常用 |
quit | q | 退出 gdb |
常见断点位置写法:
(gdb) b main (gdb) b 20 (gdb) b main.c:20 (gdb) b foo if x > 10 3.3 查看代码/栈/变量
| 命令 | 缩写 | 作用 |
|---|---|---|
list | l | 显示源代码(可 l 1 从第1行) |
where / backtrace | bt | 查看调用栈 |
bt full | 调用栈 + 每帧局部变量(core 分析很有用) | |
frame <n> | f | 切换到第 n 层栈帧 |
up / down | 在栈帧之间上下移动 | |
print <表达式> | p | 打印变量/表达式值 |
display <表达式> | 每次停住自动打印 | |
info locals | 打印当前栈帧所有局部变量 | |
info args | 打印当前函数参数 | |
info registers | 查看寄存器 |
3.4 内存查看(定位越界/野指针很关键)
x(examine)用于按格式查看内存:
# x/<数量><格式><单位> <地址> (gdb) x/16xb ptr # 16字节,按16进制byte显示 (gdb) x/8xw ptr # 8个word(4字节),按16进制显示 (gdb) x/s ptr # 按字符串显示 (gdb) x/i $pc # 反汇编当前指令 4. 实战:用 GDB 定位段错误(SIGSEGV)
4.1 构造一个会崩溃的例子
main.c:
#include<stdio.h>#include<stdlib.h>intmain(){int*p =NULL;*p =123;// 对 NULL 解引用,触发段错误return0;}编译运行:
gcc -g -O0 main.c -o app ./app 4.2 用 GDB 运行并定位
gdb ./app 在 gdb 中:
(gdb) run Program received signal SIGSEGV, Segmentation fault. (gdb) bt #0 main () at main.c:7 (gdb) list (gdb) info locals (gdb) p p $1 = (int *) 0x0 这类问题的定位套路:
- 先
bt看栈:崩溃点在哪个函数、哪一行。 - 再
frame/list看上下文:看崩溃行附近逻辑。 - 最后
p/info locals/info args:确认关键指针、数组下标、长度参数是否异常。
5. Core Dump:程序崩了也能“回放现场”
当程序崩溃时,系统可把当时的内存映射、寄存器、栈等信息写入 core 文件,用于事后分析。
5.1 开启 core 文件生成(Linux)
# 查看当前限制(0 表示不生成)ulimit -c # 临时开启(当前 shell 生效)ulimit -c unlimited core 文件路径与命名常由内核参数控制:
cat /proc/sys/kernel/core_pattern 注意:线上环境经常被 systemd 接管 core,core 可能不落在当前目录。需要结合发行版策略确认落盘位置。
5.2 使用 GDB 分析 core
假设生成了 core 文件:
gdb ./app core 高频排查命令:
(gdb) bt (gdb) bt full (gdb) info threads (gdb) thread apply all bt (gdb) frame 0 (gdb) info locals (gdb) info args (gdb) p some_ptr (gdb) x/32xb some_ptr 如果看到类似提示:
no debugging symbols found:二进制没有-g调试符号warning: core file may not match specified executable file:core 与可执行文件版本不匹配
6. 段错误(Segmentation fault)常见原因总结
段错误本质:访问了不允许访问的内存区域(地址不存在或受保护)。典型原因:
- 空指针/野指针解引用:
char *p = NULL; *p = 'x'; - 已释放内存再次使用(use-after-free)
- 数组越界/指针越界:写穿栈/堆,导致随机崩溃
- 返回局部变量地址:函数返回后栈帧销毁,地址失效
- 栈溢出:递归太深、局部数组过大
- 字符串处理长度错误:如
sprintf等导致溢出(建议snprintf)
7. 高效排查套路(建议你照着做)
7.1 现场调试(可复现崩溃)
- 先断点:
b main或b 可疑函数 - 单步逼近:
n/s - 观察关键数据:
p、info locals、info args
7.2 事后分析(只有 core)
gdb ./app corebt full一步到位获取:崩溃行 + 参数 + 局部变量x/查看指针指向内存是否合理- 多线程程序:
info threads+thread apply all bt
7.3 变量被优化掉怎么办?
如果出现:<value optimized out>
- 编译时用
-O0或-Og - 确保带
-g
8. 进阶小技巧(可选但很实用)
# 让长数组/长字符串完整打印(默认可能截断) (gdb) set print elements 0 # 打印结构体更友好 (gdb) set print pretty on # 查看动态库与映射 (gdb) info sharedlibrary (gdb) info proc mappings 9. 总结
- GDB = 运行时调试 + 崩溃现场还原 的核心工具。
- 带
-g、尽量-O0/-Og,能显著提升定位效率。 - 段错误优先用:
bt→list→info locals/args→p/x的套路。 - Core Dump 是线上排查的关键:可执行文件必须与 core 匹配。
参考资料(可扩展阅读)
- https://stackoverflow.com/questions/5115613/core-dump-file-analysis
- https://askubuntu.com/questions/1349047/where-do-i-find-core-dump-files-and-how-do-i-view-and-analyze-the-backtrace-st
- https://cgi.cse.unsw.edu.au/~learn/debugging/modules/gdb_coredumps/