第一件事是查看崩溃信号,执行 info signals 或观察GDB启动提示,如“Program terminated with signal SIGSEGV”,因不同信号对应不同根因:SIGSEGV指向非法内存访问(空指针、越界),SIGABRT表明堆已损坏(早前free异常),SIGBUS为内存对齐错误,SIGFPE多因除零;随后须验证可执行文件与core匹配(file比对build ID)、含调试信息(-g未strip),并用bt full查看带变量值的完整调用栈,多线程需thread apply all bt,源码路径不匹配时用directory命令修正。

崩溃信号类型决定后续排查方向
用 gdb 打开 core 文件后,第一件事不是急着看堆栈,而是执行 info signals 或直接看 GDB 启动时的首行提示(如 Program terminated with signal SIGSEGV, Segmentation fault.)。这个信号是核心线索——不同信号对应完全不同的问题根源和排查策略。
常见信号及含义:
-
SIGSEGV:访问非法内存地址,崩溃点大概率就是出问题的地方(比如空指针解引用、数组越界) -
SIGABRT:程序主动中止,通常是 glibc 检测到堆损坏(malloc/free不匹配、重复释放、use-after-free),真正的 bug 可能发生在崩溃前几十次调用之外 -
SIGBUS:内存对齐错误(如在非对齐地址上读取int64_t),多见于结构体 packed 或 mmap 映射场景 -
SIGFPE:浮点异常,最常见是除零,也可能是整数溢出(取决于编译选项)
必须立刻验证可执行文件是否匹配
如果 gdb 启动后显示 No symbol table is loaded 或堆栈全是 ??,说明你用的可执行文件跟生成 core 时运行的不是同一个版本,或者没带调试信息。
检查方法:
- 用
file命令比对:file ./myapp和file core-xxx输出中的 build ID(ELF note)应一致 - 确认该可执行文件编译时加了
-g,且未被strip过;Release 版至少保留符号表(strip --strip-unneeded而非strip -s) - 若程序依赖动态库,需确保
gdb能找到它们:set solib-search-path /path/to/libs
先看崩溃线程的完整调用栈(bt full)
确认信号和可执行文件无误后,立即执行 bt full。它比 bt 多输出局部变量值和参数,很多问题(如传入空指针、越界索引值)一眼就能定位。
注意几个关键点:
- 不要只看最顶上一层(
#0),有时崩溃是深层函数触发的,比如malloc内部报SIGABRT,但真正破坏堆的是上层某次free(p),得顺着栈往回翻 - 多线程程序务必执行
thread apply all bt,主线程没崩溃,Worker 线程可能已踩坏全局数据 - 如果栈里出现大量
??或地址跳变,大概率是栈被破坏(buffer overflow、stack smash),此时info registers查看rsp/rbp是否明显异常更有效
容易被忽略但致命的一点
core 文件本身不包含源码路径,GDB 默认按编译时记录的绝对路径找代码。如果可执行文件是在另一台机器编译的,或源码已移动,list 命令会失败。此时别硬猜,先用 info sources 看 GDB 认为源文件在哪,再用 directory /new/path 添加搜索路径——否则你连哪一行出问题都看不到,所有分析都是空中楼阁。


















