必须加 -g 且禁用优化(-o0),否则 gdb 无法映射地址到源码行号;bt 可能显示 ??,需配合 info registers 和 x/10i $rip 定位崩溃指令,怀疑内存问题时应优先使用 addresssanitizer 配合 -fno-omit-frame-pointer。

崩溃时看不到源码行号,先检查编译选项是否带 -g
没有 -g,GDB 就没法把内存地址映射回源文件和行号,bt(backtrace)只会显示 ??:? 或函数名但无具体位置。常见错误是只加了 -O2 没加 -g,或者用了 strip 清掉了符号表。
- 必须同时用:
gcc-14 -g -O0——-O0关闭优化,否则局部变量可能被删、内联打乱调用栈 - 推荐加
-ggdb:生成更完整的调试信息,尤其对 GDB 友好 - 如果用 CMake,确认
CMAKE_BUILD_TYPE是Debug,且没在set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "")里覆盖掉-g
Segmentation fault 发生后,用 GDB 看 bt 和 info registers
段错误最常由空指针解引用、野指针或栈溢出触发。GDB 启动后直接 run 复现崩溃,然后立刻执行:
-
bt:看调用栈——但注意,若函数被内联或优化过,顶层可能显示??;这时要配合frame 0+list查当前指令附近源码 -
info registers:重点看rip(x86_64)或pc(ARM),它指向崩溃那条指令的地址 -
x/10i $rip:反汇编崩溃点附近指令,确认是不是在访问[rax+0x10]这类内存操作
如果 bt 完全为空或只有 ??,大概率是栈被破坏(比如缓冲区溢出覆盖了返回地址),这时得换 AddressSanitizer。
怀疑内存越界或 use-after-free?直接上 -fsanitize=address
AddressSanitizer(ASan)比 GDB 更早、更准地暴露问题,且自带行号和堆栈。但它要求重新编译,且不能和 -O2 一起用(会干扰检测):
- 编译命令:
gcc-14 -g -fsanitize=address -fno-omit-frame-pointer -O0 file.c -o app - 运行报错示例:
ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000020 at pc 0x5555555561a9,后面紧跟源码文件名和行号 - 注意:
-fno-omit-frame-pointer必须加上,否则 ASan 的调用栈会截断 - 不兼容
valgrind,二者不能共存;ASan 本身不检测内存泄漏,需额外加-fsanitize=leak
程序跑着跑着卡死或逻辑不对,别急着加 printf,先用 gdb attach
对于后台进程、守护进程或长时间运行后才出问题的场景,printf 会干扰时序,还可能因缓冲不刷新而漏日志。更稳的做法是动态附加调试器:
- 查 PID:
ps aux | grep your_app - 附加:
gdb -p <pid></pid>(需有权限,可能要sudo) - 暂停后执行:
thread apply all bt看所有线程状态,快速判断是死锁(多个线程卡在futex)、忙循环(PC 停在同一个地址反复跳转),还是阻塞在系统调用(如read、poll) - 想看变量值但又怕打断流程?用
print或display,别用continue直接放行
真实项目里,崩溃往往不是孤立事件——可能是前一次 ASan 报告的越界,导致后续某处指针错乱;也可能是 bt 显示的函数本身没问题,但它的参数早已被上游污染。定位运行时错误,关键不在“看到哪一行”,而在“这一行为什么拿到坏数据”。











