GDB默认不拦截SIGABRT/SIGSEGV等崩溃信号,程序直接退出导致无法执行bt;需在run前用handle SIGABRT stop print等命令配置拦截,或依赖coredump文件配合gdb分析。

程序收到 SIGABRT 等信号时,bt 为什么没反应?
因为 GDB 默认会“接管”某些信号(如 SIGINT、SIGTERM),但对 SIGABRT、SIGSEGV 等崩溃类信号,默认行为是**直接传递给程序,不中断执行**——结果就是程序退出了,你连 gdb 提示符都等不到,自然没法输 bt。
解决办法是告诉 GDB:这类信号一来,立刻停住,让我看栈。
- 在启动 GDB 后、运行程序前,执行:
handle SIGABRT stop print - 同理,对段错误加:
handle SIGSEGV stop print - 如果不确定具体信号,可先用
info signals查看当前所有信号的处理策略
handle 命令的三个关键参数不能乱设
handle <sig> <action1> <action2> 中两个动作分别控制:是否停住(stop)、是否打印通知(print)。漏掉 stop 就白配了。
-
stop:必须加。没有它,GDB 不暂停,bt就无从谈起 -
print:建议加。否则信号来了静悄悄,你可能以为程序卡死,其实是已崩溃但没提示 -
pass或nostop:慎用。设成pass表示信号仍发给程序,但 GDB 不停——这和默认行为一样,起不到调试作用
信号触发后,bt 看到的栈帧可能不完整?
是的。尤其当信号由 abort()、assert() 或 C++ 异常未捕获触发时,调用栈里常含 __libc_start_main、std::terminate 这类系统/运行时函数,而你的业务代码可能藏在倒数第 3–5 层。
- 用
bt full而非仅bt,能同时看到局部变量和参数,帮你确认触发点上下文 - 若栈顶是
raise/abort,往上翻几层(up 2或frame 3)大概率找到你自己的函数 - 注意:优化编译(
-O2)可能导致内联或帧省略,务必用-g -O0编译调试版
coredump + gdb 是更稳的兜底方案
如果信号来得太快、或 handle 配置漏了,程序直接退出,这时靠 coredump 文件反查最可靠。
- 提前打开 coredump:
ulimit -c unlimited - 确认路径:
cat /proc/sys/kernel/core_pattern,常见如/tmp/core.%e.%p - 崩溃后进目录,运行:
gdb ./your_program /tmp/core.your_program.12345 - 进去直接输:
bt full—— 此时看到的是**崩溃瞬间的精确现场**,不受运行时干扰
真正容易被忽略的点是:信号处理配置必须在 run 前完成;而 coredump 路径一旦设错,文件就写到看不见的地方去了——这两处出问题,调试会卡死在第一步。


















