首頁  >  文章  >  系統教程  >  Linux 核心崩潰的偵測工具 Kdump

Linux 核心崩潰的偵測工具 Kdump

王林
王林轉載
2024-01-03 19:25:421172瀏覽
導讀 kdump 是獲取崩潰的 Linux 核心轉儲的一種方法,但是想找到解釋其使用和內部結構的文件可能有點困難。在本文中,我將研究 kdump 的基本使用方法,以及 kdump/kexec 在核心中如何實作。

kexec 是一個 Linux 核心到核心的引導程序,可以幫助從第一個核心的上下文引導到第二個核心。 kexec 會關閉第一個內核,繞過 BIOS 或韌體階段,並跳到第二個內核。因此,在沒有 BIOS 階段的情況下,重新啟動變得更快。

kdump 可以與kexec 應用程式一起使用—— 例如,當第一個核心崩潰時第二個核心啟動,第二個核心用於複製第一個核心的記憶體轉儲,可以使用gdb 和crash 等工具分析崩潰的原因。 (在本文中,我將使用術語“第一內核”作為當前運行的內核,“第二內核” 作為使用 kexec 運行的內核,“捕獲內核” 表示在當前內核崩潰時運行的內核。)

kexec 機制在核心以及使用者空間中都有元件。核心提供了幾個用於 kexec 重新啟動功能的系統呼叫。名為 kexec-tools 的使用者空間工具使用這些調用,並提供可執行檔來載入和引導“第二核心”。有的發行版還會在 kexec-tools 上新增封裝器,這有助於擷取並保存各種轉儲目標配置的轉儲。在本文中,我將使用名為 distro-kexec-tools 的工具來避免上游 kexec 工具和特定於發行版的 kexec-tools 程式碼之間的混淆。我的範例將使用 Fedora Linux 發行版。

Fedora kexec-tools 工具

使用 dnf install kexec-tools 指令在 Fedora 機器上安裝 fedora-kexec-tools。在安裝 fedora-kexec-tools 後可以執行 systemctl start kdump 指令來啟動 kdump 服務。當此服務啟動時,它將建立一個根檔案系統(initramfs),其中包含了要掛載到目標位置的資源,以保存 vmcore,以及用來複製和轉儲 vmcore 到目標位置的命令。然後,該服務將核心和 initramfs 載入到崩潰核心區域內的合適位置,以便在核心崩潰時可以執行它們。

Fedora 封裝器提供了兩個使用者設定檔:

/etc/kdump.conf 指定修改後需要重建 initramfs 的設定參數。例如,如果將轉儲目標從本機磁碟變更為 NFS 掛載的磁碟,則需要由「捕獲核心」載入的 NFS 相關的核心模組。
/etc/sysconfig/kdump 指定修改後不需要重新建置 initramfs 的設定參數。例如,如果只需修改傳遞給「捕獲核心」的命令列參數,則不需要重新建構 initramfs。
如果核心在 kdump 服務啟動之後發生故障,那麼「捕獲核心」就會執行,其將進一步執行 initramfs 中的 vmcore 保存過程,然後重新啟動到穩定的核心。

kexec-tools 工具

編譯 kexec-tools 的原始碼得到了一個名為 kexec 的執行檔。這個同名的可執行檔可用於載入和執行“第二內核”,或載入“捕獲內核”,它可以在內核崩潰時執行。

載入「第二核心」的指令:

# kexec -l kernel.img --initrd=initramfs-image.img –reuse-cmdline

--reuse-command 參數表示使用與「第一個核心」相同的命令列。使用 --initrd 傳遞 initramfs。 -l 表示你正在載入“第二核心”,可以由 kexec 應用程式本身執行(kexec -e)。使用 -l 載入的核心不能在內核崩潰時執行。為了載入可以在內核崩潰時執行的“捕獲內核”,必須傳遞參數 -p 取代 -l。

載入捕獲內核的命令:

# kexec -p kernel.img --initrd=initramfs-image.img –reuse-cmdline

echo c > /pros/sysrq-trigger 可用於使核心崩潰以進行測試。有關 kexec-tools 提供的選項的詳細信息,請參閱 man kexec。在轉到下一個部分之前,請先看這個 kexec_dump 的示範:


kdump: 端對端流

下圖展示了流程圖。必須在引導「第一個核心」期間為捕獲內核保留 crashkernel 的記憶體。您可以在核心命令列中傳遞 crashkernel=Y@X,其中 @X 是可選的。 crashkernel=256M 適用於大多數 x86_64 系統;然而,為崩潰核心選擇適當的記憶體取決於許多因素,如核心大小和 initramfs,以及 initramfs 中包含的模組和應用程式運行時的記憶體需求。有關傳遞崩潰內核參數的更多方法,請參閱 kernel-parameters 文件。
Kdump 检查 Linux 内核崩溃!

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 或“捕获内核”之前,会执行以下操作:

  • 准备 CPU 寄存器(参见内核代码中的 crash_setup_regs());
  • 更新 vmcoreinfo 备注(请参阅 crash_save_vmcoreinfo());
  • 关闭非崩溃的 CPU 并保存准备好的寄存器(请参阅 machine_crash_shutdown() 和 crash_save_cpu());
  • 您可能需要在此处禁用中断控制器;
  • 最后,它执行 kexec 重新启动(请参阅 machine_kexec()),它将加载或刷新 kexec 段到内存,并将控制权传递给进入段的执行文件。输入段可以是下一个内核的 purgatory 或开始地址。
ELF 程序头

kdump 中涉及的大多数转储核心都是 ELF 格式。因此,理解 ELF 程序头部很重要,特别是当您想要找到 vmcore 准备的问题。每个 ELF 文件都有一个程序头:

  • 由系统加载器读取,
  • 描述如何将程序加载到内存中,
  • 可以使用 Objdump -p elf_file 来查看程序头。

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 的表示:
Kdump 检查 Linux 内核崩溃!

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 note

Crash notes 是每个 CPU 中用于在系统崩溃的情况下存储 CPU 状态的区域;它有关于当前 PID 和 CPU 寄存器的信息。

vmcoreinfo

该 note 段具有各种内核调试信息,如结构体大小、符号值、页面大小等。这些值由捕获内核解析并嵌入到 /proc/vmcore 中。 vmcoreinfo 主要由 makedumpfile 应用程序使用。在 Linux 内核,include/linux/kexec.h 宏定义了一个新的 vmcoreinfo。 一些示例宏如下所示:

  • VMCOREINFO_PAGESIZE()
  • VMCOREINFO_SYMBOL()
  • VMCOREINFO_SIZE()
  • VMCOREINFO_STRUCT_SIZE()
makedumpfile

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 没有成功

检查是否分配了崩溃内存。

  • cat /sys/kernel/kexec_crash_size 不應該有零值。
  • cat /proc/iomem | grep "Crash kernel" 應該有一個分配的範圍。
  • 如果未分配,則在命令列中傳遞正確的 crashkernel= 參數。
  • 如果沒有顯示,則在 kexec 命令中傳遞參數 -d,並將輸出訊息傳送至 kexec-tools 郵件清單。
在「第一核心」的最後一個訊息之後,在控制台上看不到任何東西(例如「bye」)
  • 檢查 kexec -e 之後的 kexec -l kernel_image 指令是否運作。
  • 可能缺少支援的體系結構或特定機器的選項。
  • 可能是 purgatory 的 SHA 驗證失敗。如果您的體系結構不支援 purgatory 中的控制台,則很難進行偵錯。
  • 可能是「第二核心」早已崩壞。
  • 將您的系統的 earlycon 或 earlyprintk 選項傳遞給「第二核心」的命令列。
  • 使用 kexec-tools 郵件清單共用第一個核心和捕獲核心的 dmesg 日誌。
資源 fedora-kexec-tools
  • #GitHub 倉庫:git://pkgs.fedoraproject.org/kexec-tools
  • 郵件清單:[email protected]
  • 說明:Specs 檔案和腳本提供了使用者友善的命令和服務,以便 kexec-tools 可以在不同的使用者場景下自動化。
kexec-tools
  • GitHub 倉庫:git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
  • 郵件清單:[email protected]
  • 說明:使用核心系統呼叫並提供使用者命令 kexec。
Linux kernel
  • #GitHub 倉庫: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  • 郵件清單:[email protected]
  • 說明:實作了 kexec_load()、kexec_file_load()、reboot() 系統呼叫和特定體系結構的程式碼,例如 machine_kexec() 和 machine_crash_shutdown()。
Makedumpfile
  • #GitHub 倉庫: git://git.code.sf.net/p/makedumpfile/code
  • #郵件清單:[email protected]
  • 說明:從轉儲檔案壓縮並過濾不必要的元件。

(題圖:Penguin、 Boot,修改:Opensource.com. CC BY-SA 4.0)

作者簡介:

Pratyush Anand - Pratyush 正在以以為 Linux 核心專家的身份與 Red Hat 合作。他主要負責 Red Hat 產品和上游所面臨的幾個 kexec/kdump 問題。他還處理 Red Hat 支援的 ARM64 平台周圍的其他核心調試、追蹤和效能問題。除了 Linux 內核,他還在上游的 kexec-tools 和 makedumpfile 專案中做出了貢獻。他是一名開源愛好者,並在教育機構舉辦志工講座,促進了 FOSS。


 

以上是Linux 核心崩潰的偵測工具 Kdump的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:linuxprobe.com。如有侵權,請聯絡admin@php.cn刪除