登录
首页 >  文章 >  linux

Linux核心转储分析教程:定位程序崩溃原因

时间:2026-03-24 08:12:51 393浏览 收藏

本文系统讲解了在Linux环境下如何定位程序崩溃原因,从确认core dump是否启用、识别其实际存储位置(尤其在systemd托管场景下需用coredumpctl而非盲目搜索文件),到使用gdb、addr2line、objdump等工具精准回溯崩溃点,涵盖符号调试、ASLR适配、动态库分析及日志线索挖掘等实战要点,直击生产环境中“找不到core”“看不到源码行”“地址对不上”等高频痛点,强调binary、core、debug info三者版本严格一致这一成败关键。

Linux怎么分析core dump_Linux如何定位程序崩溃原因【教程】

core dump 文件在哪,怎么确认它真被生成了

Linux 默认可能根本没开 core dump,所以第一步不是分析,而是确认你有东西可看。先检查 ulimit -c,输出是 0 就代表被禁用了;临时打开用 ulimit -c unlimited,但要注意这仅对当前 shell 及其子进程生效。

生成的 core 文件默认叫 core,通常落在程序执行时的工作目录(不是源码目录,也不是 /tmp),但实际路径受 /proc/sys/kernel/core_pattern 控制。常见坑是:程序在 systemd 下跑,systemd 会拦截 core dump 并转给 systemd-coredump,此时你得查 coredumpctl list,而不是满硬盘找 core 文件。

  • cat /proc/sys/kernel/core_pattern 看当前策略
  • 若输出类似 |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e,说明走 systemd 管理,别去文件系统里瞎翻
  • 手动测试是否能生成:运行 kill -SEGV $$(对自己 shell 发段错误),再看 ulimit -c 非零且当前目录有没有新 core

用 gdb 打开 core dump 看崩溃点最直接

有 core 文件 + 对应的原始可执行文件(必须是同一构建产物,带调试符号更好),就能定位到具体哪行代码崩的。gdb ./myapp core 进去后,bt(backtrace)是第一指令,它显示函数调用栈,最顶上那帧就是崩溃现场。

容易忽略的是符号问题:如果程序是 release 编译且 strip 过,bt 只能看到函数地址,看不到文件名和行号。这时候要么重编译加 -g,要么用 readelf -S ./myapp | grep debug 确认调试信息是否还在。

  • info registers 查看崩溃时各寄存器值,尤其 rip/pcrsp,能辅助判断是空指针还是栈溢出
  • frame 0 后跟 list,可显示崩溃行附近源码(需有调试信息)
  • 若 core 是 systemd 生成的,用 coredumpctl dump -o core myapp 先导出成传统 core 文件再用 gdb

没有源码或调试信息时,objdump + addr2line 能救急

生产环境常遇到只有 stripped 二进制和 core 的情况。这时靠 gdb 只能看到汇编,但至少能知道崩在哪个函数偏移处。先用 gdb ./myapp core,执行 bt,记下最上面那行的地址(比如 #0 0x0000555555556123 in ?? ())。

这个地址是虚拟内存地址,要映射回代码位置,得结合程序的加载基址。用 readelf -l ./myapp | grep LOAD 找第一个 LOAD 段的 Virtual Address(比如 0x555555554000),然后算偏移:0x0000555555556123 - 0x555555554000 = 0x2123。再用 addr2line -e ./myapp 0x2123 查源码行——前提是编译时没关 -g,否则只能靠 objdump -d ./myapp | grep -A10 -B10 '2123$' 看附近汇编逻辑。

  • gdbinfo proc mappings 可查实际加载地址,比 readelf 更准(尤其开了 ASLR 时)
  • addr2line 输出 ?? 表示没调试信息,不是命令用错了
  • 若程序是动态链接的,崩溃可能在 so 里,得用 info sharedlibrary 看 so 加载地址,再对齐偏移

systemd-coredump 日志里藏了不少线索

很多用户卡在“找不到 core 文件”,其实日志里早写了原因。运行 coredumpctl info myapp,输出里 Signal(如 SIGSEGV)、ExecutableStack trace(如果有符号)都直接可用。更关键的是 Coredump 字段,它告诉你这个 core 存哪(通常是 /var/lib/systemd/coredump/ 下带时间戳的压缩文件)。

systemd 默认把 core 压缩存档,所以不能直接 gdb,得先解压:zcat /var/lib/systemd/coredump/core.myapp.*.xz > core。另一个常被忽略的点是:coredumpctl list 显示的 PID 是崩溃时的进程 ID,但如果你重启过机器,旧 core 可能已被自动清理(看 /etc/systemd/coredump.confMaxUseKeepFree)。

  • 查历史崩溃:用 coredumpctl --since="2024-05-01" list 限定时间范围
  • 想永久保存所有 core,改 /etc/systemd/coredump.confStorage=external 并确保 /var/lib/systemd/coredump 有足够空间
  • coredumpctl debug myapp 会直接启动 gdb 并加载对应 core 和二进制,省一步手动操作

事情说清了就结束。真正难的不是看懂 bt,而是确认你手上的 binary、core、debug info 三者版本完全匹配——差一个 commit,地址就对不上。

今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>