编译内核子模块
submodule
1 2
| make SUBDIRS=./kmodules/01_oops O=virt_build modules "5.3之前的kernel版本" make M=./kmodules/01_oops O=virt_build modules "之后的版本"
|
编写一个简单的可以导致 load page fault 的内核模块触发内核 panic.
Kernel sysrq
Documentation/translations/zh_CN/admin-guide/sysrq.rst
启用 CONFIG_MAGIC_SYSRQ
1
| echo c > /proc/sysrq-trigger "产生panic"
|
配置 crashdump
https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
编译
1
| ../configure --host=riscv64-linux --target=riscv64 --prefix=/home/liguang/program/riscv-lab/kexec-tools/install
|
最终生成 /sbin/kexec
kernel 配置
kernel 需要打开
CONFIG_KEXEC=y
CONFIG_DEBUG_INFO=y
CONFIG_CRASH_DUMP=y
CONFIG_PROC_VMCORE=y
cmdline 配置
需要在内核的启动参数中添加 crashkernel=X[@Y]
这样的参数,表明需要预留一部分内存用以保存 dump 内核的代码,以便在第一个内核崩溃的情况下,通过一系列故障处理之后,迅速切换到第二个内核,也就是所谓的 dump 内核,通过该内核收集第一个内核所产生的崩溃现场信息
1
| -append "root=/dev/vda rw earlycon=sbi console=ttyS0 crashkernel=256M"
|
设置 kexec 参数
需要将 vmlinux dtb 导入到 rootfs 中, 接着注册 kexec 参数
1
| /sbin/kexec -p --dtb=dtb.file --reuse-cmdline vmlinux
|
上述命令需要设置到开机自启动脚本中.
触发 crash, 启动第二个内核
kernel crash 后, 会按照 kexec 设置的参数启动第二个内核, 在第二个内核中生成 /proc/vmcore
文件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| # echo c > /proc/sysrq-trigger [ 31.743965] sysrq: Trigger a crash [ 31.744405] Kernel panic - not syncing: sysrq triggered crash [ 31.744762] CPU: 0 PID: 124 Comm: sh Kdump: loaded Not tainted 6.4.0-rc1-00026-g80e62bc8487b-dirty #11 [ 31.745125] Hardware name: riscv-virtio,qemu (DT) [ 31.745430] Call Trace: [ 31.745733] [<ffffffff800054ae>] dump_backtrace+0x1c/0x24 [ 31.746032] [<ffffffff8084420c>] show_stack+0x2c/0x38 [ 31.746239] [<ffffffff8084f4be>] dump_stack_lvl+0x3c/0x54 [ 31.746547] [<ffffffff8084f4ea>] dump_stack+0x14/0x1c [ 31.746843] [<ffffffff808445b8>] panic+0x102/0x2b6 [ 31.747128] [<ffffffff804e6940>] sysrq_reset_seq_param_set+0x0/0x72 [ 31.747371] [<ffffffff804e6f16>] __handle_sysrq+0x9a/0x18c [ 31.747648] [<ffffffff804e7400>] write_sysrq_trigger+0x70/0x9e [ 31.748095] [<ffffffff8021955e>] proc_reg_write+0x3e/0x8c [ 31.748849] [<ffffffff801bac2a>] vfs_write+0xac/0x2f8 [ 31.749145] [<ffffffff801bafb2>] ksys_write+0x5e/0xc8 [ 31.749411] [<ffffffff801bb02a>] sys_write+0xe/0x16 [ 31.749648] [<ffffffff8084ff00>] do_trap_ecall_u+0xe0/0xf4 [ 31.749936] [<ffffffff8000366c>] ret_from_exception+0x0/0x64 [ 31.750790] SMP: stopping secondary CPUs [ 31.751969] Starting crashdump kernel... [ 31.752427] Will call new kernel at f0000000 from hart id 0 [ 31.752898] FDT image at ffffd000 [ 31.753255] Bye... [ 0.000000] Linux version 6.4.0-rc1-00026-g80e62bc8487b-dirty (liguang@LAPTOP-N3BGDMO9) (riscv64-unknown-linux-gnu-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35) #11 SMP Fri Jun 2 16:22:42 CST 2023 [ 0.000000] Machine model: riscv-virtio,qemu [ 0.000000] efi: UEFI not found. [ 0.000000] OF: fdt: Reserving 1 KiB of memory at 0xfffff000 for elfcorehdr [ 0.000000] Zone ranges: [ 0.000000] DMA32 [mem 0x00000000f0000000-0x00000000ffffffff] [ 0.000000] Normal empty [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x00000000f0000000-0x00000000ffffffff] [ 0.000000] Initmem setup node 0 [mem 0x00000000f0000000-0x00000000ffffffff] [ 0.000000] crashkernel: ignoring reservation request [ 0.000000] SBI specification v1.0 detected
|
生成的 /proc/vmcore
文件
1
| -r-------- 1 root root 1901559808 Jun 2 09:13 /proc/vmcore
|
vmcore 文件转储
需要使用 makedumpfile 工具对 /proc/vmcore
进行转储, 在 debain 下, makedumpfile 是被 kdump-tools.service 调用的, 调用 /usr/sbin/kdump-config
脚本最终使用 makedumpfile
对 /proc/vmcore
进行转储.
放在默认的 /var/crash/
下.
1
| /etc/systemd/system/multi-user.target.wants/kdump-tools.service
|
但是 makedumpfile 工具目前还不支持 riscv
https://github.com/makedumpfile/makedumpfile/issues/8
而且如果不使用 debain 这种带 systemd 服务的, 需要手动编写 init.d 脚本配置 makedumpfile 自启动, 以确保第二个 kernel 启动后自启动脚本完成对 /proc/vmcore
的转储.
也可以使用 cp
scp
等 copy 命令将/proc/vmcore 拷贝出来
vmcore 分析
可以使用 crash 工具对 vmcore 进行分析. gdb 应该也是支持的.
gdb -ex "core vmcore"
目前 riscv 上转储的 core 地址有问题, 没有保存 0xff200000_00000000
段的地址, 该段地址属于 vmalloc 段地址.
0xff20000000903c58
源码分析
kexec
kexec 源码: https://github.com/horms/kexec-tools
读取 /proc/iomem
, 判断是否加载 crashkernel

其中, 除了crash kernel部分, System RAM其余部分都是需要被dump的