DWARF 是标准化调试信息格式,GDB 依赖其解析变量、调用栈和源码映射;它独立于编译器和语言,嵌入在目标文件中,与符号表(.symtab)功能不同。

什么是 DWARF,它和 GDB 有什么关系?
DWARF 是一种标准化的调试信息格式,不是 C++ 语言特性,也不是编译器私有产物。GDB 能识别变量名、调用栈、源码行号、结构体内存布局,全靠目标文件(.o)或可执行文件里嵌入的 DWARF 数据。GCC/Clang 默认在 -g 下生成 DWARF v4/v5,GDB 依赖这些数据做符号解析和内存映射。
怎么确认你的二进制里真有 DWARF?
常见错误是以为加了 -g 就万事大吉,但链接时可能被 strip 掉,或用了 -s。验证方法很简单:
readelf -w ./a.out | head -20 # 或更直接: file ./a.out # 输出含 "with debug_info" 才算有效 # 若看到 "stripped",说明 DWARF 已丢失,GDB 将无法显示变量、无法步进源码
-
objdump -g可看简化版调试条目,适合快速扫一眼是否有DW_TAG_subprogram(函数)或DW_TAG_variable - 如果用
gcc -g -O2编译,DWARF 仍在,但变量可能被优化掉(optimized out),这不是 DWARF 缺失,而是编译器没给它留寄存器/栈位置
为什么 GDB 有时显示不出局部变量或内联函数?
这通常不是 GDB 的 bug,而是 DWARF 描述和实际代码不匹配:
- 内联函数默认不生成独立
DW_TAG_subprogram,除非加__attribute__((used))或编译时用-ginline-points(GCC)让 DWARF 记录内联点 - 局部变量若被分配到寄存器且未 spill 到栈,DWARF 可能只写
DW_OP_regX;GDB 在某些架构(如 ARM64 中断上下文)可能读不到该寄存器当前值 - 使用
-frecord-gcc-switches可让 DWARF 存编译参数,有助于排查“为什么这个 struct 成员 offset 不对”之类问题
DWARF 和符号表(.symtab)是两套东西
很多人混淆 nm ./a.out 能看到的符号和 GDB 能用的变量。关键区别:
立即学习“C++免费学习笔记(深入)”;
-
.symtab只存函数/全局变量的地址和名字(比如main、global_counter),没有类型、作用域、行号信息 - DWARF 提供
main的参数类型、每行对应哪段机器码、std::vector的size()成员函数在哪——这些.symtab完全不记录 -
strip --strip-unneeded会删.symtab但保留 DWARF;strip --strip-debug才删 DWARF——别用错命令
真正卡住调试的,往往不是“找不到符号”,而是 DWARF 描述的变量生命周期和实际寄存器分配对不上,这时候得看 info registers 和 maint info dwarf 对比验证。











