直接用gdb加载可执行文件和core文件后执行bt,就能看到段错误发生的精确地址和调用栈;若core未生成,需先检查ulimit -c(0表示禁用),临时执行ulimit -c unlimited,并确认/proc/sys/kernel/core_pattern路径可写。

直接用 gdb 加载可执行文件和 core 文件后执行 bt,就能看到段错误发生的精确地址和调用栈——不需要猜、不用加断点,崩溃现场原样还原。
core 文件没生成?先确认系统允许 dump
段错误发生时若没留下 core 文件,后续所有分析都无从谈起。默认多数 Linux 系统禁用 core 生成:
- 运行
ulimit -c查看当前限制,输出0表示禁止 - 临时启用:
ulimit -c unlimited(仅当前 shell 有效) - 永久生效需修改
/etc/security/limits.conf,加一行:* soft core unlimited - 检查
/proc/sys/kernel/core_pattern确认保存路径,避免写入失败(比如容器里/tmp最稳妥)
gdb 加载 core 后第一件事是看 backtrace
bt(即 backtrace)输出的是崩溃瞬间的函数调用链,最顶层(#0)就是出问题的指令地址:
gdb ./myapp ./core.12345 (gdb) bt #0 0x000055555555518d in main () at segfault_demo.c:8 #1 0x00007ffff7deca20 in __libc_start_main () from /lib64/libc.so.6
这里 0x000055555555518d 就是触发 SIGSEGV 的指令地址,对应源码第 8 行;如果符号缺失,bt 仍会显示地址,只是不带行号。
- 若
bt显示在strcpy、memcpy等 libc 函数内,说明问题出在上层调用者传了非法指针 - 用
frame 1切到上一帧,再用info registers或x/10i $pc查看寄存器和附近汇编,能确认具体访问了哪个地址
定位到地址后,怎么知道它对应哪行代码?
关键前提是编译时用了 -g(且最好关掉优化,即 -O0)。否则地址只能靠反汇编或符号表硬推:
- 有调试信息时:
list *0x000055555555518d直接显示该地址附近的源码 - 没调试信息但有符号表:用
nm ./myapp | grep "000055555555518d"找最近的函数名,再结合objdump -d ./myapp | grep -A5 -B5 "55555555518d"定位偏移 - 注意:地址中的
0x000055555555518d是虚拟内存地址,不是物理地址,不同进程每次加载位置可能变(ASLR),但对单次崩溃分析完全够用
真正容易被忽略的是:即使 bt 显示了地址,也别急着改那一行——段错误是结果,不是原因。空指针、野指针、栈溢出这些往往在几十行甚至几百行之前就埋下了,得顺着调用栈往上翻,重点看参数传递和内存生命周期管理。


















