-g的作用是使可执行文件包含调试信息,供GDB定位函数、变量、行号等;必须带-g编译且不可strip,否则调用栈(bt)将显示为??。

必须带 -g 编译,且不能 strip,否则 bt 里全是 ??
编译时加 -g 是硬性前提
没有这一步,后续所有调试都失去意义。GDB 依赖符号表定位函数、变量、行号,而 -g 才把它们写进二进制。
-
gcc -g -O0 -o program program.c:推荐组合,-O0避免优化打乱代码执行顺序和变量生命周期 -
g++ -g -O0 -o program program.cpp:C++ 同理,别用-O2或-O3调试,info locals可能显示<optimized out></optimized> - 验证是否生效:
file program | grep debug应输出with debug_info;readelf -S program | grep debug应看到多个.debug_*段
生产环境不能直接发带符号的二进制?用 objcopy --only-keep-debug
体积敏感或安全要求高的场景,得剥离符号,但必须保留调试能力——关键不是“不带符号”,而是“符号可找回”。
- 分离符号:
objcopy --only-keep-debug program program.debug - 剥离主程序:
strip -g program(此时file program会显示stripped) - 关联符号文件:
objcopy --add-gnu-debuglink=program.debug program(让 GDB 能自动找到program.debug) - 或者更可靠的方式:用
build-id机制(现代发行版默认启用),readelf -n program | grep "Build ID"可查 ID,符号文件通常放在/usr/lib/debug/.build-id/xx/xxxxxxxx.debug
调试时 GDB 找不到符号?手动指定 debug-file-directory
即使符号文件存在,GDB 默认只在固定路径找(如 /usr/lib/debug),自定义路径必须显式告知。
- 启动 GDB 后立即执行:
set debug-file-directory /path/to/your/debug/symbols:/usr/lib/debug - 再加载二进制:
file ./program(此时应看到Reading symbols from .../program.debug) - 最后加载 core:
core-file ./core - 常见坑:
set debug-file-directory必须在file前执行;路径末尾不加斜杠;多个路径用冒号分隔(Linux/macOS),Windows 用分号
最易被忽略的一点:动态库的符号也得对得上。如果程序链接了自建的 .so,它同样需要带 -g 编译或配套 .debug 文件,并确保 set solib-search-path 指向其所在目录——否则 bt 一进共享库就又变 ??。


















