coredump和kdump

下面给你一份完整文档,包含你之前的内容,并且我已经把“运行中进程如何修改 ulimit 触发 coredump”补充完整、按原结构嵌入,且后续内容保持不变


完整文档:coredump + kdump + 非官方/无 debuginfo 分析(含运行中进程修改 ulimit)


1. Core dump(用户态进程崩溃)

1.1 原理(必须理解)

  • 进程崩溃时(SIGSEGV/SIGABRT 等),内核会检查该进程的 RLIMIT_CORE(即 core size 限制)。

  • 若允许生成 core,则内核会将进程内存快照写到文件(core 文件),并写入一些元信息(寄存器、线程、映像映射等)。

  • 生成 core 时涉及:

    • ulimit -c(进程级 rlimit)

    • /proc/sys/kernel/core_pattern(core 文件命名/位置/管道)

    • 运行目录权限 / 指定目录权限

    • systemd 的 LimitCORE(systemd 管理的进程)

补充:运行中的进程怎么修改 ulimit 触发 coredump(完整)

  • ulimit 修改的是 当前 shell 及其子进程的 rlimit。
    对于 已经运行的进程,其 rlimit 已在启动时固定,因此 普通 ulimit -c unlimited 不会影响已运行进程

  • 运行中进程要修改 core limit,需要使用 prlimit 或系统级机制(systemd),否则只能重启进程。

方式 A:使用 prlimit(对运行中进程生效,推荐)

sudo prlimit --pid <pid> --core=unlimited

验证:

cat /proc/<pid>/limits | grep core

输出应为:

Max core file size        unlimited      unlimited      bytes

触发 core(模拟崩溃):

kill -SIGABRT <pid>

或程序实际崩溃(SIGSEGV 等)。

方式 B:如果进程由 systemd 管理(必须修改 systemd)

sudo mkdir -p /etc/systemd/system/<service>.service.d
sudo tee /etc/systemd/system/<service>.service.d/override.conf <<EOF
[Service]
LimitCORE=infinity
EOF
sudo systemctl daemon-reload
sudo systemctl restart <service>

验证:

cat /proc/<pid>/limits | grep core

方式 C:不修改 core limit,直接生成 core(不让进程崩溃)

gcore -o /tmp/core.<pid> <pid>

或:

gdb -p <pid> -batch -ex "generate-core-file /tmp/core" -ex "detach" -ex "quit"

1.2 自动触发(进程崩溃自动生成 core)

1.2.1 全局配置(推荐)

1)设置 core 文件大小无限制:

sudo tee /etc/security/limits.d/99-core.conf <<EOF
* soft core unlimited
* hard core unlimited
EOF

2)设置 core 生成路径与命名:

sudo sysctl -w kernel.core_pattern=/tmp/core.%e.%p.%t

3)确保目录可写:

sudo mkdir -p /tmp/coredumps
sudo chmod 777 /tmp/coredumps
sudo sysctl -w kernel.core_pattern=/tmp/coredumps/core.%e.%p.%t

4)验证:

ulimit -c
cat /proc/sys/kernel/core_pattern

1.2.2 systemd 管理进程(必须设置)

systemd 默认可能限制 core dump。

创建配置:

sudo mkdir -p /etc/systemd/system/<service>.service.d
sudo tee /etc/systemd/system/<service>.service.d/override.conf <<EOF
[Service]
LimitCORE=infinity
EOF
sudo systemctl daemon-reload
sudo systemctl restart <service>

1.3 手动触发 core(不崩溃也能生成)

方式 A:向进程发送 SIGABRT(模拟崩溃)

kill -SIGABRT <pid>

方式 B:gcore(生成 core,不影响进程运行)

gcore -o /tmp/core.dump <pid>

方式 C:使用 ptrace / 调试器强制生成(更底层)

gdb -p <pid> -batch -ex "generate-core-file /tmp/core" -ex "detach" -ex "quit"

1.4 分析 coredump(gdb)

1.4.1 基本流程

gdb <binary> <corefile>

常用命令:

bt                      # 查看调用栈
info threads            # 查看线程
thread <n>              # 切换线程
frame <n>               # 进入栈帧
info locals             # 查看局部变量
p <var>                 # 打印变量
info registers          # 寄存器
x/20x $sp               # 查看栈内容

1.4.2 关键点(崩溃定位)

  • bt 找到崩溃帧(通常是 frame 0)

  • 查看寄存器 info registers

  • 查看指针是否为 NULL / 非法地址

  • 找到调用链(调用者参数是否异常)


1.5 符号/调试信息(关键)

  • 没有 debug 符号gdb 只能看到地址,无法看到源代码和变量名。

  • 需要 -g 编译或保留 debug 符号。

1.5.1 编译带 debug(推荐)

gcc -g -O0 -o app app.c

1.5.2 分离 debug 符号(生产环境常用)

objcopy --only-keep-debug app app.debug
strip --strip-debug app
objcopy --add-gnu-debuglink=app.debug app

1.5.3 没有 debuginfo 也能做的事

  • 通过 addr2line 把地址转换为函数/行(如果有符号表)

  • 通过 readelf -s 查看符号表(如果未 strip)

  • 通过 objdump -d 反汇编(无 debug 也能分析)

示例:

addr2line -e app 0x400abc

如果可执行文件被 strip,则需要 app.debug 或重新编译。


1.6 非官方/自定义编译的场景(没有 debuginfo)

1.6.1 只能拿到地址的情况怎么办?

1)用 readelf -s 找到函数符号(如果保留符号)
2)用 objdump -d 反汇编
3)用 addr2line 反查地址对应函数

例如:

objdump -d app | grep -n "400abc"

如果是动态库崩溃:

readelf -Ws libxxx.so | grep <symbol>

1.6.2 通过映射关系定位

core 文件中包含进程的映射表(mmap),可以看到各个库的基地址:

info proc mappings

然后结合 nm / objdump 的偏移,计算实际地址:

实际地址 = 基址 + 偏移

2. kdump(内核崩溃 / kernel panic)

2.1 kdump 原理(必须理解)

  • 当 Linux 内核发生 panic 时,主内核会重启,但在重启前会启动一个 crash kernel(小内核)

  • crash kernel 会在 保留的内存区域 中运行,读取主内核的内存镜像(vmcore),并保存到磁盘或网络。

  • vmcore 相当于“内核级的 core dump”。

关键点:

  • 需要预留 crashkernel 内存(boot 参数)

  • 需要 kexec-tools/kdump 服务

  • 需要可用的 vmlinux(带符号的内核映像)


2.2 自动触发 kdump(内核 panic 自动产生 vmcore)

2.2.1 安装与配置(以常见发行版为例)

sudo yum install -y kexec-tools   # RHEL/CentOS
sudo apt-get install -y kdump-tools   # Debian/Ubuntu

2.2.2 设置 crashkernel(必须)

在 grub 中添加:

crashkernel=256M

并更新 grub:

sudo grub2-mkconfig -o /boot/grub2/grub.cfg  # RHEL/CentOS
sudo update-grub                             # Debian/Ubuntu

2.2.3 启动 kdump 服务

sudo systemctl enable kdump
sudo systemctl start kdump

2.2.4 配置 vmcore 存放位置

编辑 /etc/kdump.conf

path /var/crash
core_collector makedumpfile -c --message-level 1 -d 31

2.3 手动触发 kdump(强制内核 panic)

2.3.1 通过 sysrq 强制 panic(常用)

echo 1 > /proc/sys/kernel/sysrq
echo c > /proc/sysrq-trigger

系统会直接 panic 并触发 kdump(如果配置正确)。

2.3.2 通过 sysctl 触发 panic(更“温和”)

echo 1 > /proc/sys/kernel/panic_on_oops
echo oops > /proc/sysrq-trigger

2.4 分析 kdump(vmcore)

2.4.1 关键工具:crash

crash 是最常用的分析工具。

crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/<vmcore>

常用命令:

bt         # 内核调用栈
ps         # 查看进程列表
struct     # 查看结构体内容
vm         # 查看内存
log        # 查看日志

2.4.2 如果没有 vmlinux(无符号表)

  • crash 需要 vmlinux(带符号)才能解析符号。

  • 如果只有 bzImage 或 vmlinuz,必须从源码编译或从发行版获取 debug kernel。


3. 非官方 kernel / 没有 debuginfo 的分析策略(重点)

3.1 Core dump 没有 debug 信息时(用户态)

方式 1:用符号表(如果存在)

即使没有 debug 信息,只要未 strip 或保留符号表:

nm -C app | head
readelf -s app | grep " FUNC "

方式 2:没有符号表但有地址

只能用反汇编 + 经验:

  • objdump -d 看代码逻辑

  • 根据崩溃地址推断函数(结合 info proc mappings

  • 找到附近的汇编指令和调用关系

方式 3:通过日志/栈回溯结合上下文

  • 通过 dmesg、应用日志

  • 通过 straceltrace

  • 通过复现脚本定位


3.2 Kdump 没有 vmlinux 或没有符号表

这是最难的情况。可用策略:

方式 1:从 kernel 源码重新编译(建议)

  • 取得相同版本的 kernel 源码

  • 使用相同配置 .config

  • 生成 vmlinux(带符号)

  • 用 crash 分析 vmcore

方式 2:用 makedumpfile / crash 的最小分析

即使没有符号,也可以:

  • 通过 crashbt -abt -d 看到地址

  • 结合 System.map(符号地址表)定位到函数

方式 3:利用 System.map(符号表)

如果有 System.map,可以解析:

grep " some_function" System.map

然后结合 crash 的地址定位。


4. 你需要的“完整落地”执行清单

4.1 生成 core(推荐配置)

# 1) 全局允许
sudo tee /etc/security/limits.d/99-core.conf <<EOF
* soft core unlimited
* hard core unlimited
EOF

# 2) core pattern
sudo mkdir -p /tmp/coredumps
sudo chmod 777 /tmp/coredumps
sudo sysctl -w kernel.core_pattern=/tmp/coredumps/core.%e.%p.%t

# 3) 对 systemd 服务
sudo mkdir -p /etc/systemd/system/<service>.service.d
sudo tee /etc/systemd/system/<service>.service.d/override.conf <<EOF
[Service]
LimitCORE=infinity
EOF
sudo systemctl daemon-reload
sudo systemctl restart <service>

4.2 分析 core(关键步骤)

gdb /path/to/binary /tmp/coredumps/core.<name>.<pid>.<time>
bt
info threads
thread <n>
frame 0
info locals
p <var>

4.3 生成 kdump(推荐配置)

# 1) 安装
sudo yum install -y kexec-tools

# 2) crashkernel
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
# 需要在 /etc/default/grub 添加 crashkernel=256M

# 3) 启动 kdump
sudo systemctl enable kdump
sudo systemctl start kdump

# 4) 手动触发
echo 1 > /proc/sys/kernel/sysrq
echo c > /proc/sysrq-trigger

4.4 分析 vmcore

crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/<vmcore>
bt
ps
log

5. 你需要补充的关键信息(我可以给你定制脚本/配置)

为了给你“完全适配你环境”的完整方案,我需要你补充以下信息:

  1. 你的 Linux 发行版(CentOS/Ubuntu/Debian/Alpine/其他)

  2. 你的程序是 systemd 启动还是手动启动

  3. 你的内核版本 uname -r

  4. 你是否可以安装 kexec-tools/kdump-tools

  5. 你是否能编译内核/程序(是否可获取源码)


 

posted on 2026-01-21 16:56  吃草的青蛙  阅读(2)  评论(0)    收藏  举报

导航