Home > Article > System Tutorial > Linux kernel crash detection tool Kdump
Introduction | kdump is one way to get a crashed Linux kernel dump, but it can be a bit difficult to find documentation explaining its use and internals. In this article, I will study the basic usage of kdump and how kdump/kexec is implemented in the kernel. |
kexec is a Linux kernel-to-kernel bootloader that helps boot from the context of a first kernel to a second kernel. kexec shuts down the first core, bypassing the BIOS or firmware stage, and jumps to the second core. Therefore, the reboot becomes faster without the BIOS stage.
kdump can be used with the kexec application - for example, when the first kernel crashes a second kernel starts up, and the second kernel is used to copy the memory dump of the first kernel, you can use gdb and crash, etc. The tool analyzes the cause of the crash. (In this article, I will use the terms "first kernel" as the currently running kernel, "second kernel" as the kernel running with kexec, and "capture kernel" to mean the kernel running when the current kernel crashes.)
The kexec mechanism has components in the kernel as well as user space. The kernel provides several system calls for the kexec restart functionality. A userspace tool called kexec-tools uses these calls and provides an executable file to load and boot the "second kernel". Some distributions also add wrappers on kexec-tools, which help capture and save dumps of various dump target configurations. In this article, I will use a tool called distro-kexec-tools to avoid confusion between the upstream kexec tools and the distribution-specific kexec-tools code. My examples will use the Fedora Linux distribution.
Fedora kexec-tools toolUse the dnf install kexec-tools command to install fedora-kexec-tools on the Fedora machine. After installing fedora-kexec-tools, you can execute the systemctl start kdump command to start the kdump service. When this service starts, it creates a root file system (initramfs) that contains the resources to be mounted to the target location, to hold the vmcore, and the commands to copy and dump the vmcore to the target location. The service then loads the kernel and initramfs into appropriate locations within the crashed kernel region so that they can be executed if the kernel crashes.
The Fedora wrapper provides two user configuration files:
/etc/kdump.conf specifies the configuration parameters that need to be rebuilt after modification. For example, if you change the dump target from a local disk to an NFS-mounted disk, you need the NFS-related kernel modules loaded by Capture Kernel.
/etc/sysconfig/kdump specifies configuration parameters that do not require rebuilding the initramfs after modification. For example, if you only need to modify the command line parameters passed to the "capture kernel", you do not need to rebuild the initramfs.
If the kernel fails after the kdump service is started, then a "capture kernel" is performed, which further performs the vmcore save process in the initramfs and then reboots to a stable kernel.
Compile the source code of kexec-tools to get an executable file named kexec. This eponymous executable can be used to load and execute a "second kernel", or load a "capture kernel", which can be executed when the kernel crashes.
Command to load the "second kernel":
# kexec -l kernel.img --initrd=initramfs-image.img –reuse-cmdline
--reuse-command parameter indicates using the same command line as the "first kernel". Use --initrd to pass initramfs. -l indicates that you are loading a "second kernel" that can be executed by the kexec application itself (kexec -e). Kernels loaded with -l cannot be executed on a kernel panic. In order to load a "capture kernel" that can be executed on a kernel crash, the argument -p must be passed instead of -l.
Command to load the capture kernel:
# kexec -p kernel.img --initrd=initramfs-image.img –reuse-cmdline
echo c > /pros/sysrq-trigger can be used to crash the kernel for testing. For more information about the options provided by kexec-tools, see man kexec. Before moving on to the next section, take a look at this demo of kexec_dump:
The figure below shows the flow chart. The crashkernel's memory must be reserved for the capture kernel during booting of the "first kernel". You can pass crashkernel=Y@X on the kernel command line, where @X is optional. crashkernel=256M works for most x86_64 systems; however, choosing the appropriate memory for a crashkernel depends on many factors, such as the size of the kernel and the initramfs, as well as the modules contained in the initramfs and the memory requirements of the application runtime. See the kernel-parameters documentation for more ways to pass crash kernel parameters.
pratyush_f1.png
您可以将内核和 initramfs 镜像传递给 kexec 可执行文件,如(kexec-tools)部分的命令所示。“捕获内核”可以与“第一内核”相同,也可以不同。通常,一样即可。Initramfs 是可选的;例如,当内核使用 CONFIG_INITRAMFS_SOURCE 编译时,您不需要它。通常,从第一个 initramfs 中保存一个不一样的捕获 initramfs,因为在捕获 initramfs 中自动执行 vmcore 的副本能获得更好的效果。当执行 kexec 时,它还加载了 elfcorehdr 数据和 purgatory 可执行文件(LCTT 译注:purgatory 就是一个引导加载程序,是为 kdump 定作的。它被赋予了“炼狱”这样一个古怪的名字应该只是一种调侃)。 elfcorehdr 具有关于系统内存组织的信息,而 purgatory 可以在“捕获内核”执行之前执行并验证第二阶段的二进制或数据是否具有正确的 SHA。purgatory 也是可选的。
当“第一内核”崩溃时,它执行必要的退出过程并切换到 purgatory(如果存在)。purgatory 验证加载二进制文件的 SHA256,如果是正确的,则将控制权传递给“捕获内核”。“捕获内核”根据从 elfcorehdr 接收到的系统内存信息创建 vmcore。因此,“捕获内核”启动后,您将看到 /proc/vmcore 中“第一内核”的转储。根据您使用的 initramfs,您现在可以分析转储,将其复制到任何磁盘,也可以是自动复制的,然后重新启动到稳定的内核。
内核提供了两个系统调用:kexec_load() 和 kexec_file_load(),可以用于在执行 kexec -l 时加载“第二内核”。它还为 reboot() 系统调用提供了一个额外的标志,可用于使用 kexec -e 引导到“第二内核”。
kexec_load():kexec_load() 系统调用加载一个可以在之后通过 reboot() 执行的新的内核。其原型定义如下:
long kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment *segments, unsigned long flags);
用户空间需要为不同的组件传递不同的段,如内核,initramfs 等。因此,kexec 可执行文件有助于准备这些段。kexec_segment 的结构如下所示:
struct kexec_segment { void *buf; /* 用户空间缓冲区 */ size_t bufsz; /* 用户空间中的缓冲区长度 */ void *mem; /* 内核的物理地址 */ size_t memsz; /* 物理地址长度 */ };
当使用 LINUX_REBOOT_CMD_KEXEC 调用 reboot() 时,它会引导进入由 kexec_load 加载的内核。如果标志 KEXEC_ON_CRASH 被传递给 kexec_load(),则加载的内核将不会使用 reboot(LINUX_REBOOT_CMD_KEXEC) 来启动;相反,这将在内核崩溃中执行。必须定义 CONFIG_KEXEC 才能使用 kexec,并且为 kdump 定义 CONFIG_CRASH_DUMP。
kexec_file_load():作为用户,你只需传递两个参数(即 kernel 和 initramfs)到 kexec 可执行文件。然后,kexec 从 sysfs 或其他内核信息源中读取数据,并创建所有段。所以使用 kexec_file_load() 可以简化用户空间,只传递内核和 initramfs 的文件描述符。其余部分由内核本身完成。使用此系统调用时应该启用 CONFIG_KEXEC_FILE。它的原型如下:
long kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char __user * cmdline_ptr, unsigned long flags);
请注意,kexec_file_load 也可以接受命令行,而 kexec_load() 不行。内核根据不同的系统架构来接受和执行命令行。因此,在 kexec_load() 的情况下,kexec-tools 将通过其中一个段(如在 dtb 或 ELF 引导注释等)中传递命令行。
目前,kexec_file_load() 仅支持 x86 和 PowerPC。
当内核崩溃时会发生什么当第一个内核崩溃时,在控制权传递给 purgatory 或“捕获内核”之前,会执行以下操作:
kdump 中涉及的大多数转储核心都是 ELF 格式。因此,理解 ELF 程序头部很重要,特别是当您想要找到 vmcore 准备的问题。每个 ELF 文件都有一个程序头:
vmcore 的 ELF 程序头的示例如下:
# objdump -p vmcore vmcore: file format elf64-littleaarch64 Program Header: NOTE off 0x0000000000010000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**0 filesz 0x00000000000013e8 memsz 0x00000000000013e8 flags --- LOAD off 0x0000000000020000 vaddr 0xffff000008080000 paddr 0x0000004000280000 align 2**0 filesz 0x0000000001460000 memsz 0x0000000001460000 flags rwx LOAD off 0x0000000001480000 vaddr 0xffff800000200000 paddr 0x0000004000200000 align 2**0 filesz 0x000000007fc00000 memsz 0x000000007fc00000 flags rwx LOAD off 0x0000000081080000 vaddr 0xffff8000ffe00000 paddr 0x00000040ffe00000 align 2**0 filesz 0x00000002fa7a0000 memsz 0x00000002fa7a0000 flags rwx LOAD off 0x000000037b820000 vaddr 0xffff8003fa9e0000 paddr 0x00000043fa9e0000 align 2**0 filesz 0x0000000004fc0000 memsz 0x0000000004fc0000 flags rwx LOAD off 0x00000003807e0000 vaddr 0xffff8003ff9b0000 paddr 0x00000043ff9b0000 align 2**0 filesz 0x0000000000010000 memsz 0x0000000000010000 flags rwx LOAD off 0x00000003807f0000 vaddr 0xffff8003ff9f0000 paddr 0x00000043ff9f0000 align 2**0 filesz 0x0000000000610000 memsz 0x0000000000610000 flags rwx
在这个例子中,有一个 note 段,其余的是 load 段。note 段提供了有关 CPU 信息,load 段提供了关于复制的系统内存组件的信息。
vmcore 从 elfcorehdr 开始,它具有与 ELF 程序头相同的结构。参见下图中 elfcorehdr 的表示:
pratyush_f2.png
kexec-tools 读取 /sys/devices/system/cpu/cpu%d/crash_notes 并准备 CPU PT_NOTE 的标头。同样,它读取 /sys/kernel/vmcoreinfo 并准备 vmcoreinfo PT_NOTE 的标头,从 /proc/iomem 读取系统内存并准备存储器 PT_LOAD 标头。当“捕获内核”接收到 elfcorehdr 时,它从标头中提到的地址中读取数据,并准备 vmcore。
Crash noteCrash notes 是每个 CPU 中用于在系统崩溃的情况下存储 CPU 状态的区域;它有关于当前 PID 和 CPU 寄存器的信息。
vmcoreinfo该 note 段具有各种内核调试信息,如结构体大小、符号值、页面大小等。这些值由捕获内核解析并嵌入到 /proc/vmcore 中。 vmcoreinfo 主要由 makedumpfile 应用程序使用。在 Linux 内核,include/linux/kexec.h 宏定义了一个新的 vmcoreinfo。 一些示例宏如下所示:
vmcore 中的许多信息(如可用页面)都没有用处。makedumpfile 是一个用于排除不必要的页面的应用程序,如:
此外,makedumpfile 在复制时压缩 /proc/vmcore 的数据。它也可以从转储中删除敏感的符号信息; 然而,为了做到这一点,它首先需要内核的调试信息。该调试信息来自 VMLINUX 或 vmcoreinfo,其输出可以是 ELF 格式或 kdump 压缩格式。
典型用法:
# makedumpfile -l --message-level 1 -d 31 /proc/vmcore makedumpfilecore
详细信息请参阅 man makedumpfile。
kdump 调试新手在使用 kdump 时可能会遇到的问题:
kexec -p kernel_image 没有成功检查是否分配了崩溃内存。
(Title: Penguin, Boot, modification: Opensource.com. CC BY-SA 4.0)
About the Author:
Pratyush Anand - Pratyush is working with Red Hat as a Linux kernel expert. He is responsible for several kexec/kdump issues faced by Red Hat products and upstream. He also handles other kernel debugging, tracing, and performance issues around the ARM64 platform supported by Red Hat. In addition to the Linux kernel, he has contributed to the upstream kexec-tools and makedumpfile projects. He is an open source enthusiast and promotes FOSS by giving volunteer lectures at educational institutions.
The above is the detailed content of Linux kernel crash detection tool Kdump. For more information, please follow other related articles on the PHP Chinese website!