必须用readelf -S your_program | grep debug验证调试段是否存在,若无.debug_info等段说明符号未进入文件;若有但GDB报错,则可能被strip或CMake构建流程意外剥离。

直接看 readelf -S 输出里有没有 .debug_* 段。没有,说明符号根本没进可执行文件;有但 GDB 还报错,大概率是链接时被 strip 或覆盖了。
检查可执行文件是否真含调试段
别只信编译命令里写了 -g,得验证符号是否实际存在于最终文件中:
- 运行
readelf -S your_program | grep debug,至少应看到.debug_info、.debug_line等段; - 若输出为空,说明链接阶段丢弃了符号——常见于 Makefile 或 CMake 中混用了
-s、--strip-all或install(STRIP); - 若段存在但 GDB 仍报错,可能是
objcopy --strip-debug或strip -g后期处理过该文件,需回溯构建流程。
CMake 项目中调试符号常被悄悄抹掉
CMake 默认不保证 Debug 构建一定带完整调试信息,尤其在启用 install 或多配置生成器时:
-
CMAKE_BUILD_TYPE必须显式设为Debug,不能只靠set(CMAKE_CXX_FLAGS_DEBUG "...-g"); - 检查生成的
compile_commands.json,确认每个条目都含-g(不是仅-O0); - 禁用任何
install(STRIP)或set(CMAKE_INSTALL_PREFIX ...)后自动 strip 的逻辑; - 动态库要额外加
-fPIC,否则即使有-g,GDB 也可能加载失败或断点不命中。
动态库调试时符号“看不见”的真实原因
哪怕主程序能调试,.so 文件没符号也会让 GDB 在调用栈里显示 ??,且无法在库函数内设断点:
- 编译动态库必须同时用
-g和-fPIC,缺一不可; - 验证方式:
readelf -S libxxx.so | grep debug,和主程序一样查段; - GDB 加载后运行
info sharedlibrary,看对应库状态列是否为Yes; - 若为
No,手动加载:symbol-file /path/to/libxxx.so(前提是该文件未被 strip)。
最易被忽略的是:CMake 的 add_library(... SHARED) 不会自动继承 CMAKE_CXX_FLAGS_DEBUG,必须显式用 target_compile_options(your_target PRIVATE $:-g -fPIC>) 控制。漏掉这一句,.so 就只剩机器码。


















