【C/C++】无符号调试:GDB解栈实战指南
文章目录
- 无符号调试:GDB解栈实战指南
- 1 生成并加载 Core Dump
- 2 查看原始堆栈信息(地址形式)
- 3 确认加载的共享库地址范围
- 4 手动转换地址为函数名
- 5 反汇编关键代码段
- 6 加载外部符号文件(如有)
- 7 结合系统库文档分析
- 8 示例:定位空指针崩溃
- 9 工具链补充
- 10 总结
无符号调试:GDB解栈实战指南
当可执行文件或共享库(.so)缺乏调试符号时,GDB 无法直接显示函数名和源代码行号。
1 生成并加载 Core Dump
-
允许生成 Core Dump
ulimit -c unlimited # 解除 core 文件大小限制
-
运行程序并触发崩溃
./your_program # 程序崩溃后生成 core 文件(如 core.1234)
-
启动 GDB 并加载 Core 文件
gdb ./your_program core.1234
2 查看原始堆栈信息(地址形式)
- 获取崩溃时的堆栈
(gdb) bt # 示例输出: #0 0x00007ffff7e6a1a5 in ?? () #1 0x000055555555517d in ?? () #2 0x00007ffff7de9083 in ?? () #3 0x0000000000000000 in ?? ()
- 显示的是内存地址而非函数名。
3 确认加载的共享库地址范围
- 列出所有加载的共享库及其地址
(gdb) info sharedlibrary # 示例输出: From To Syms Read Shared Object Library 0x00007ffff7fd0100 0x00007ffff7ff26a4 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7e00000 0x00007ffff7e8d5d0 No /lib/x86_64-linux-gnu/libc.so.6
No
表示该库未加载符号。
4 手动转换地址为函数名
-
使用
info symbol
命令(gdb) info symbol 0x00007ffff7e6a1a5 # 示例输出: _dl_signal_exception + 21 in section .text of /lib64/ld-linux-x86-64.so.2
- 若地址属于系统库(如
libc
、ld
),可能自动解析为符号。
- 若地址属于系统库(如
-
使用
addr2line
工具(需对应带符号的二进制)addr2line -e ./your_program 0x55555555517d # 转换程序内地址 addr2line -e /lib/x86_64-linux-gnu/libc.so.6 0x7ffff7e6a1a5 # 转换库地址
- 输出示例:
/path/to/source.c:42
(需有符号文件)。
- 输出示例:
5 反汇编关键代码段
- 反汇编崩溃点附近的代码
(gdb) disassemble 0x000055555555517d # 示例输出: Dump of assembler code for function _start:0x000055555555517d: mov %rsp,%rdi0x0000555555555180: callq 0x555555555040
- 通过汇编指令推测代码逻辑(如
callq
调用函数)。
- 通过汇编指令推测代码逻辑(如
6 加载外部符号文件(如有)
- 手动加载符号文件到 GDB
(gdb) add-symbol-file /path/to/with_symbols/your_program 0x555555555000 # 0x555555555000 为程序基地址(通过 `info file` 获取)
- 加载系统库的调试符号
- 安装调试符号包(如 Ubuntu):
sudo apt install libc6-dbg
- GDB 会自动加载符号。
- 安装调试符号包(如 Ubuntu):
7 结合系统库文档分析
- 识别常见系统函数
- 如
0x7ffff7e6a1a5
属于libc
,可能是malloc
、free
等函数。
- 如
- 查阅库函数的行为
- 例如,
malloc
失败可能返回NULL
,解引用导致崩溃。
- 例如,
8 示例:定位空指针崩溃
-
崩溃堆栈
#0 0x00007ffff7e6a1a5 in ?? () #1 0x000055555555517d in ?? ()
-
分析地址归属
0x000055555555517d
属于可执行文件。0x00007ffff7e6a1a5
属于libc.so.6
。
-
反汇编可执行文件地址
(gdb) disassemble 0x000055555555517d # 输出: 0x000055555555517d: callq 0x555555555040 # 调用某个函数
- 假设
0x555555555040
是malloc
,需检查返回值是否为NULL
。
- 假设
-
检查
libc
函数(gdb) info symbol 0x00007ffff7e6a1a5 # 输出: malloc + 123 in section .text of /lib/x86_64-linux-gnu/libc.so.6
- 确认
malloc
是否返回NULL
。
- 确认
9 工具链补充
-
使用
objdump
反汇编二进制objdump -d ./your_program > disassembly.txt
- 全文反汇编,搜索关键地址。
-
结合
nm
查看符号表nm -D ./your_program # 显示动态符号表(需未剥离)
10 总结
- 核心思路:通过地址归属分析、反汇编和外部工具转换,结合系统库文档推断问题。
- 关键步骤:
- 生成并分析 Core Dump。
- 使用
info sharedlibrary
确认库地址。 - 利用
addr2line
或objdump
转换地址。 - 反汇编代码段,结合系统函数行为分析。
- 适用场景:生产环境调试、第三方库问题追踪。