Linux默认不生成core文件,是因为ulimit -c被设为0禁用了该功能;必须先执行ulimit -c unlimited开启,否则后续core_pattern等配置均无效。

ulimit -c unlimited 为什么必须先执行
段错误发生时,Linux 默认不生成 core 文件——不是程序没崩,是系统直接“抹掉现场”。ulimit -c 查出来是 0,就说明这个开关被关死了。不打开它,后面所有分析都缺最关键的一环。
临时生效只要在当前终端运行:ulimit -c unlimited;但如果你用 systemd、supervisor 或容器启动程序,就得改配置:在 /etc/security/limits.conf 加两行:* soft core unlimited* hard core unlimited
容易踩的坑:
• 在 Docker 容器里跑程序?得加 --ulimit core=-1:-1 启动参数,否则宿主机设了也没用
• 某些发行版(如 Ubuntu)默认启用 apport,会拦截 SIGSEGV 并自己处理,导致 core 不生成,可临时关掉:sudo systemctl stop apport
core_pattern 设置成 /var/core/core-%e-%p-%t 有什么好处
默认的 core 文件名就是 core,丢在当前目录,多个进程一崩就覆盖,还分不清是谁干的。用 /proc/sys/kernel/core_pattern 改规则,是最小成本提升可追溯性的操作。
推荐写法:echo "/var/core/core-%e-%p-%t" | sudo tee /proc/sys/kernel/core_pattern
关键点:
• %e 是程序名,一眼看出哪个二进制崩了
• %p 是 PID,避免并发运行时文件名冲突
• %t 是时间戳,精确到秒,方便和日志对齐
• 目录 /var/core 要提前 mkdir -p /var/core && chmod 777 /var/core,否则权限不足照样写失败
gdb ./a.out core-xxx 进去后 bt 看不到源码行号?
这不是 GDB 的问题,是编译时漏了调试信息。bt 能显示函数名和偏移,但要看到 foo.c:42 这种行号,必须满足两个条件:
• 编译时加 -g(GCC/G++ 必须项)
• 程序没 strip 过(检查:file ./a.out,如果输出含 “stripped”,就没了符号表)
• 如果用了链接脚本或构建系统(如 CMake),确认没在最后加 strip 步骤
补救办法有限:若只有 stripped 的二进制 + core,可用 objdump -t ./a.out | grep function_name 找地址,再对照 info registers 和 x/10i $rip 看汇编,但远不如带 -g 直观。
没有 core 文件也能快速定位?试试 catchsegv 和 dmesg
有些场景没法等 core(比如程序只崩一次、环境不允许改 ulimit),这时靠内核和工具层的辅助信息也能抢出关键线索。
catchsegv ./your_program 是 libc 自带的小工具,不改代码、不重编译,运行时自动捕获 SIGSEGV 并打印调用栈——虽然比 GDB 简略,但够筛出是哪个函数第一层崩的。
dmesg | tail -15 看内核日志,典型输出像:[12345.678901] your_app[1234]: segfault at 0000000000000000 ip 000055a1b1d2a13e sp 00007ffc3a4b8d20 error 4
重点看:
• at 0000000000000000 → 几乎肯定是空指针解引用
• error 4 → 用户态读操作失败(error 值查 arch/x86/mm/fault.c 可知含义)
• ip 是指令指针,结合 addr2line -e ./a.out -f -C 000055a1b1d2a13e 能反查源码行
真正容易被忽略的是:这些信息只在 dmesg 缓存里停留很短时间,崩完立刻执行,别等几分钟后再翻。


















