news 2026/7/4 4:38:53

庖丁解CORE · 初见全牛:vmcore前世今生

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
庖丁解CORE · 初见全牛:vmcore前世今生

庖丁解CORE · 第一篇 初见全牛:vmcore 是什么,从哪里来

庖丁始解牛时,所见无非全牛。三年之后,未尝见全牛也。——《庄子·养生主》


初学者打开一个 vmcore,往往被它的体量震慑——动辄数 GB,文件类型标注 ELF,file命令返回的是core file,却和应用程序的 core dump 截然不同。你不知道它从何而来,也不知道里面藏着什么。这就是庖丁最初所见:一头完整的、令人茫然的全牛。

本文将讲清楚三件事:vmcore 是什么、它如何被生成、影响它质量的关键参数与常见故障。文章也顾及了架构差异(x86_64 与 ARM64),会在相关环节单独说明。


一、vmcore 内容及格式

1.1 vmcore 是什么

vmcore 是 Linux 内核在崩溃瞬间的内存快照,以 ELF 格式存储。更准确地说,它是一个经过筛选的内存转储,包含:

  • 内核崩溃时所有 CPU 的寄存器状态(通过 ELF PT_NOTE 段存储)
  • 内核使用的物理内存页(按过滤级别选择性保留)
  • vmcore-dmesg:崩溃前的内核日志缓冲区

它不是:

  • 完整的物理内存镜像(用户态进程内存默认被过滤掉)
  • 应用程序的 core dump(那是单个进程的地址空间快照)
  • 实时系统状态(它是崩溃那一刻的冻结帧,之后的一切都不存在)

1.2 vmcore 的常见存储形式

根据其获取与生成方式、数据过滤程度以及应用场景的不同,业界主要将其划分为以下六大核心类型:

完整内存转储 (Full Dump):最原始、最完整的转储方式。它不经过任何过滤,直接将系统崩溃瞬间的全部物理内存数据全量写入存储。其优点在于保留了百分之百的内存现场(包括所有的用户态、内核态数据及缓存),信息最为完整;缺点是体积庞大(与物理内存大小等同),在数百 GB 或 TB 级大内存服务器上,采集与写盘时间极长。

kdump 压缩转储 (Compressed Dump):目前生产环境最常用的标准格式(通常由 makedumpfile 配合 kdump 生成)。它在捕获阶段对内存数据进行压缩(支持 zlib、lzo、lz4、zstd 等算法),并在保留核心内核元数据的同时过滤掉无关数据,极大地节省了磁盘空间,提升了转储效率。

makedumpfile 过滤转储 (Filtered Dump):通过特定的过滤规则(如 high、low 或自定义级别),有选择地剥离掉对内核调试无用的数据页(例如零页、用户态进程数据、文件缓存等)。这使得生成的 vmcore 体积显著减小,兼顾了快速落盘与核心内核现场的保留。

远程传输转储 (Remote Dump):适用于本地磁盘空间不足或无盘服务器。捕获内核通过网络协议(如 NFS、SSH、Netcat、TFTP 等)将转储数据实时流式传输到远程存储服务器。其不依赖本地存储,但转储成功率受制于网络架构的稳定性。

分区转储 (Partial Dump):在极端或受限场景下,仅捕获指定的一部分物理内存范围,或只读取特定的物理内存区域。其体积极小、捕获极快,但由于丢弃了大量内存数据,无法进行全栈的深度死锁和链路还原。

dmesg / vmcore-dmesg (日志提取):这是一种极其轻量级的"降级转储"。它仅保存并提取内核崩溃前的 dmesg 环形缓冲区日志(Log Buffer)。它几乎不占用空间,在无法生成完整 core 的极端硬件故障场景下,作为纯文本提供最后的线索,但无法进行寄存器、内存块等高级调试。

此外,在虚拟化平台(如 KVM/QEMU、VMware ESXi)上,根据崩溃主体的不同(Host 崩溃、Guest 内部 panic、或者通过宿主机 virsh dump/QEMU Monitor 强行导出的物理镜像),vmcore 还会衍生出虚拟机内核 ELF 镜像和宿主机层面的 Raw 原始镜像等形态。

1.3 ELF 格式的 vmcore 内部结构综述

ELF 格式的 vmcore 是 Linux 标准转储体系(kdump)的核心产物。它严格遵循标准的 64 位 Executable and Linkable Format (ELF64) 规范,将崩溃瞬间的物理内存空间映射、CPU 寄存器状态以及内核元数据,组织成一个标准化、可被 crash、gdb 等工具直接解析的核心转储文件(ET_CORE 类型)。

标准 ELF64 规范的通用度,堪称现代计算底座的"硬通货"。它超越了物理硬件的藩篱,在 x86_64、ARM64、RISC-V 乃至 LoongArch 等截然不同的芯片架构之间,构建了一套高度统一的二进制格式标准。从磁盘上的可执行程序、运行时的动态链接库,到内核动态加载的 .ko 驱动模块,直至系统崩溃瞬间凝固的 vmcore 转储现场,皆由同一套Elf64_EhdrElf64_Phdr结构体作为其元数据骨架(实际存储时可能包含 makedumpfile 私有头)。这种将"通用的数据外壳"与"异构的体系现场"完美分离的解耦设计,使得 ELF64 成为纵穿操作系统从编译到崩溃、横跨所有主流处理器架构的内核转储通用语言。

其内部拓扑结构由外至内,主要由以下四个关键部件无缝交织构成:

+------------------------------------------------------------------------+ | 1. ELF Header (ELF头部) | | - 标识魔数(e_ident)、机器架构(e_machine: x86_64/AARCH64)、e_phoff 等 | +------------------------------------------------------------------------+ | 2. Program Header Table (PHT / 程序头表) | | - 整个文件的索引总纲,描述并指向所有 PT_NOTE 与 PT_LOAD 段的物理偏移| +------------------------------------------------------------------------+ | 3. PT_NOTE Segment (元数据元段) | | +----------------------------------------------------------------+ | | | NT_PRSTATUS : 捕获崩溃瞬间每个 CPU 核心的通用寄存器快照 | | | | (x86_64: RIP/RSP/CR3; ARM64: PC/SP/TTBR0/1) | | | +----------------------------------------------------------------+ | | | NT_VMCOREINFO : 存放内核符号(如 init_task)、KASLR 偏移、页表 | | | | 级数、内核版本等关键调试索引的“黑盒子” | | | +----------------------------------------------------------------+ | | | NT_AUXV / NT_FILE / NT_TASKSTRUCT 等其他辅助元数据 | | | +----------------------------------------------------------------+ | +------------------------------------------------------------------------+ | 4. PT_LOAD Segments (物理内存段) | | - 包含1到N个连续或断续的物理地址映射块,直接映射崩溃瞬间的真实物理内存 | +------------------------------------------------------------------------+

ELF Header(ELF 头部):位于文件起始位置,固定大小。它定义了文件的基本元数据,包括 ELF 魔数(Magic)、文件类别(64 位)、大端/小端序、目标机器架构(例如 EM_X86_64 或 EM_AARCH64),以及程序头表(PHT)在文件中的偏移量(e_phoff)和数量(e_phnum)。

Program Header Table(PHT / 程序头表):整个文件的"活地图"。它由一系列程序头项(Program Header Entries)组成,不包含具体的物理内存数据,而是精确描述了后续所有段(Segment)的类型、文件偏移(p_offset)、物理/虚拟地址基址(p_paddr/p_vaddr)以及段大小(p_memsz)。

PT_NOTE Segment(元数据段):存放系统关键状态和调试上下文的黄金核心区。它内部通过 Name-Type-Value 的内嵌结构包裹了多个至关重要的 Note 节点:

  • NT_PRSTATUS(进程/核心状态):最为关键。它保存了崩溃瞬间,全机每一个 CPU 核心的实时运行快照,保存寄存器集及少量 task 上下文信息,以及最重要的处理器寄存器状态(Register Sets)。在 x86_64 上表现为 RIP、RSP、CR3(页表基址)等;在 ARM64 上则表现为 PC、SP、PSTATE 以及 TTBR0/TTBR1。这是 crash 工具重建崩溃现场函数调用栈(Backtrace)的唯一数学依据。
  • NT_VMCOREINFO(内核关键元数据):存放内核的核心符号表物理地址(保存内核关键符号、结构偏移、页模型参数等)、内存模型的配置参数(如九级或三级页表)、Linux 内核版本号,以及对抗安全攻击的 KASLR(内核地址空间布局随机化)偏移量(kernel_offset)。调试工具必须读取此节点,才能正确消除地址随机化带来的偏移,把二进制内存反向推演回 C 语言源码。
  • 其他 Note(如 NT_AUXV、NT_FILE、NT_TASKSTRUCT):保存辅助向量、内存映射文件信息等扩展上下文。

PT_LOAD Segments(物理内存段):占据了 vmcore 99% 以上体积的实体内容。每一个 PT_LOAD 段对应一段连续的物理内存银行(Memory Bank)。程序头表中的每一项分别映射到这些段,调试工具通过读取这些段的内容,在应用层虚拟重构出系统崩溃那一刻的全局物理内存全景。

二、生成机制:kexec + kdump

vmcore 的生成依赖两个机制的协同:kexec(内核执行链)和 kdump(崩溃转储框架)。

2.1 两个内核的世界

Linux 系统正常运行时,内存中实际上准备着两套内核:捕获内核(capture kernel / crash kernel)在系统启动时由 kdump 服务通过kexec -p预加载进保留区域,处于待命状态。

2.2 崩溃触发到 vmcore 的完整路径

① 生产内核触发 panic │ ▼ ② 调用 crash_kexec() ├── 保存当前 CPU 寄存器到 crash_notes 区域 ├── 向其他 CPU 发送 IPI/NMI,令其保存寄存器后停机 └── 通过 kexec 机制热切换到捕获内核 │ ▼ ③ 捕获内核启动(极简环境,无需完整初始化) ├── 通过 /proc/vmcore 接口访问生产内核的物理内存 └── 捕获内核的内存在保留区域内,与生产内核的内存不重叠 │ ▼ ④ makedumpfile 读取 /proc/vmcore ├── 按过滤级别丢弃无关页(零页、用户态页等) ├── 压缩剩余内存页 └── 写入目标路径(本地磁盘 / NFS / SSH 远端) │ ▼ ⑤ 捕获内核重启,系统恢复正常启动

2.3 /proc/vmcore 是桥梁

/proc/vmcore是捕获内核暴露出的一个特殊虚拟文件,它将生产内核的物理内存映射为可读的 ELF 文件视图。makedumpfile 读它,就像读一个普通文件——但背后是对整个物理内存的访问。


三、vmcore 的产生方式

内核 panic 并非只有一条触发路径。从生产实践来看,vmcore 的来源可以分为四类:内核自发崩溃、看门狗超时、手动触发、虚拟化平台导出。理解这四类来源,在分析时就能判断崩溃是"系统自己倒下的"还是"被外力推倒的"——二者的根因分析思路截然不同。

3.1 内核自发崩溃

这是最常见的 vmcore 来源。内核检测到自身状态异常时,主动调用panic()终止运行。主要包含如下几种:

Oops 升级为 panic

内核遇到可恢复错误时产生 Oops(如非法内存访问、除零),默认情况下 Oops 只打印错误信息,不触发 panic。但开启以下参数后,Oops 会直接升级为 panic:

# 查看当前值(0=只打印,1=触发panic)sysctlkernel.panic_on_oops# 永久开启(写入 /etc/sysctl.conf)kernel.panic_on_oops=1

生产环境强烈建议开启此参数。因为 Oops 之后内核状态已不可信,继续运行可能导致数据损坏,且不会留下 vmcore 供分析。

BUG() / BUG_ON() / WARN_ON()

内核代码中的断言宏,触发时的行为(需panic_on_oops=1):

默认行为受参数控制
BUG()触发 Oops,直接 panic否,属于必然 panic 行为
BUG_ON(cond)条件成立时触发 panic否,属于确定性断言机制
WARN() / WARN_ON()打印警告,系统继续运行kernel.panic_on_warn=1 升级
# WARN 升级为 panic(有助于捕获早期异常)kernel.panic_on_warn=1

空指针解引用(NULL pointer dereference)

访问虚拟地址 0(或极低地址)触发 page fault,内核无法处理后产生 Oops,进而(开启panic_on_oops时)触发 panic。这是生产环境中最高频的 vmcore 来源之一。

内核栈溢出

内核默认为每个线程分配 8KB(x86_64)或 16KB(ARM64)的内核栈。栈末尾有 canary 保护字;溢出时 canary 被破坏,内核检测后触发 panic。若开启了CONFIG_VMAP_STACK(虚拟地址映射栈),溢出会触发硬件 page fault,更早被捕获。

RCU stall

RCU(Read-Copy-Update)是内核的关键同步机制。若某个 CPU 在读侧临界区内停留时间过长(默认 21 秒),内核打印 RCU stall 警告:

# 开启后 RCU stall 直接触发 panic(便于捕获死循环或中断关闭过久的场景)kernel.panic_on_rcu_stall=1

3.2 看门狗超时触发

内核内置多层看门狗,监控不同粒度的"卡死"状态,触发后产生 panic 并生成 vmcore。

软锁(Soft Lockup)

监控对象:调度器是否在预期时间内运行。默认超时:20 秒内若某 CPU 未调度过其他任务,判定为 soft lockup。

kernel.softlockup_panic=1# 检测到后触发 panic(默认关闭)kernel.watchdog_thresh=10# 超时阈值(秒),soft lockup = 2×此值

硬锁(Hard Lockup)

监控对象:CPU 是否在关中断状态下长时间运行(NMI 看门狗)。默认超时:watchdog_thresh秒(默认 10 秒)内若 CPU 未响应 NMI,判定为 hard lockup。实现机制:x86_64 使用 PMU(性能计数器)产生 NMI;ARM64 使用 arch timer 产生 FIQ(EL3)。

kernel.hardlockup_panic=1# 检测到后触发 panic(生产环境建议开启)kernel.nmi_watchdog=1# 启用 NMI 看门狗

hung task(D 状态进程)

监控对象:长期处于不可中断睡眠(D 状态)的进程。默认超时:120 秒。常见于 NFS 挂起、存储设备无响应等场景。

kernel.hung_task_panic=1# D 状态超时后触发 panickernel.hung_task_timeout_secs=120

OOM killer

内存耗尽时,OOM killer 选择进程并将其杀死。若开启以下参数,OOM 事件直接升级为 panic:

vm.panic_on_oom=1# OOM 触发 panic(适合内存泄漏定位)# 0 = 只杀进程(默认)# 1 = 内存耗尽时触发 panic# 2 = 强制 panic(忽略 cpuset/mempolicy 限制)

各类看门狗的超时对比

时间轴(秒) 0────5────10────20────30────..────120 │ │ │ │ │ └── hung_task(D 状态进程,默认 120s) │ └── soft lockup(默认 20s = 2 × watchdog_thresh) └── hard lockup(默认 10s = watchdog_thresh)

3.3 手动触发

某些场景下系统处于"活锁"状态——没有触发 panic,但已经失去响应。此时需要人工强制触发 vmcore。

SysRq 触发(最常用)

# 方式一:直接写入(需要 root 权限)echoc>/proc/sysrq-trigger# 方式二:键盘(物理或串口控制台)Alt + SysRq + C# 需要满足以下前提条件:# 确认 SysRq 已启用(0=禁用,1=全部启用,或按位组合)sysctlkernel.sysrq# 至少需要开启 crash dump 位(bit 7 = 128)kernel.sysrq=1

echo c向内核写入字符 c(crash),内核调用panic("sysrq triggered crash\n"),之后走标准 kdump 流程生成 vmcore。这是最干净、最常用的手动触发方式。

NMI 按钮(物理服务器)

部分服务器主板提供物理 NMI 按钮。按下后 CPU 收到 NMI,触发nmi_panic()。适用于系统完全失去网络响应、SysRq 也无法操作的场景。需要提前开启:

kernel.unknown_nmi_panic=1# 收到未知 NMI 时触发 panic

IPMI/BMC 注入 NMI(远程触发)

无需物理接触服务器,通过带外管理接口远程触发:

# 通过 ipmitool 发送 NMI(需要 BMC 支持)ipmitool chassis power diag# 或通过 Redfish API(现代服务器)curl-XPOST https://<BMC_IP>/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset\-d'{"ResetType": "Nmi"}'

收到 NMI 后,若内核配置了unknown_nmi_panic=1,触发 panic 并生成 vmcore。这是生产环境中处理"系统失联"最常用的手段。

注意:手动触发的 vmcore,crash 报告中 panic 原因会显示为sysrq triggered crashNMI: IOCK error,而非真实业务错误。分析时要结合崩溃前的 dmesg 日志判断真实根因。

3.4 虚拟化平台的 vmcore 导出

在虚拟化或云环境中,获取 vmcore 的路径有所不同。

KVM/libvirt(virsh dump)

# 在宿主机上导出虚拟机内存快照virshdump<domain-name>/tmp/vm.dump --memory-only# 导出为 kdump 兼容格式virshdump<domain-name>/tmp/vm.dump--formatkdump-zlib

virsh dump导出的是虚拟机的物理内存视图,格式与 kdump 生成的 vmcore 兼容,可直接用 crash 分析。但它不依赖虚拟机内部的 kdump 配置,即使虚拟机内部 kdump 未启用也可导出。适用场景:虚拟机内核卡死、无法自动触发 kdump 时,由宿主机介入强制导出。

VMware(内存快照)

VMware 的虚拟机内存快照(.vmem 文件)格式与 ELF vmcore 不同,需要转换工具(如vmss2core)转为 crash 可读格式后才能分析。

云平台(ECS/EC2 等)

公有云厂商通常提供控制台的"发送 NMI"功能(等同于 IPMI NMI 注入),触发后走虚拟机内部的 kdump 流程,vmcore 写入虚拟机本地磁盘。部分云厂商还支持将 vmcore 直接上传到对象存储(OSS/S3)。

3.5 产生方式汇总与对比

产生方式触发者需要预配置vmcore 完整性典型场景
内核 panic(自发)内核自身需 kdump 就绪空指针、BUG()、栈溢出
soft/hard lockup看门狗需开启 panic 参数死循环、关中断过久
hung task看门狗需开启 panic 参数NFS 挂起、存储无响应
SysRq运维人员需 sysrq 启用系统无响应但 SSH 可达
IPMI/BMC NMI运维(带外)需 unknown_nmi_panic系统完全失联
virsh dump宿主管理员无需客户机配置中(无寄存器)虚拟机卡死
物理 NMI 按钮运维(现场)需 unknown_nmi_panic现场处理

四、x86_64 架构下的工作细节

4.1 CPU 停机机制

x86_64 上,生产内核 panic 时:

  • 触发 panic 的 CPU(BSP 或任意 CPU)调用crash_kexec()
  • 通过 APIC IPI(处理器间中断)向所有其他 CPU 发送REBOOT_VECTOR
  • 其他 CPU 收到中断后执行crash_nmi_callback(),将自身寄存器保存到crash_notes(每 CPU 一块区域)后进入 cpu_idle 等待
  • 若某颗 CPU 在规定时间内未响应 IPI,主 CPU 通过 NMI 强制触发

crash_notes的物理地址通过内核符号crash_notes导出,捕获内核启动时从elfcorehdr=参数获取这块区域的位置。

APIC 的全称是 Advanced Programmable Interrupt Controller(高级可编程中断控制器)。简单来说,它是现代多核(Multi-core)计算机中负责管理和分发"中断信号"的核心硬件机制。如果把 CPU 的每个核心比作流水线上的工人,那么 APIC 就是那个精密的"任务调度员",决定哪个紧急任务(中断)该发给哪个工人、谁的优先级更高、以及工人之间如何通过暗号(核间中断)协同工作。

4.2 内存布局与 KASLR

x86_64 默认开启 KASLR(内核地址空间随机化)。每次启动时,内核的虚拟地址基址会随机偏移。crash 工具需要通过以下方式确定偏移量:

  • vmcore 的 PT_NOTE 中记录了KERNELOFFSET
  • crash 工具读取该值后,配合未随机化的符号表(vmlinux)计算真实地址
  • 若 vmlinux 符号地址与 vmcore 中的地址对不上,通常是 KASLR 偏移未被正确处理,而非 vmlinux 版本不匹配

KASLR 的核心逻辑在于:以开机时的动态信息熵,打破黑客对静态内存地址的绝对预测。当开启 KASLR 后,系统每次引导启动(Boot)时,内核的早期引导加载程序(Decompressor)会利用硬件随机数生成器(如 CPU 的 RDRAND 指令)产生一个随机的偏移量(Offset),称为 Entropy(熵值)。内核会利用这个随机偏移量,对核心区域的虚拟地址(有时也包括物理地址)进行整体平移和打乱。

4.3 crashkernel 参数(x86_64)

要保证 kdump 机制正常工作,需要在 GRUB 启动参数中设置crashkernel参数。crashkernel是 Linux 内核启动参数,其核心功能是:为 kdump 机制预留一块物理内存,用于在系统崩溃时运行捕获内核并生成 vmcore。

x86_64 上保留区域默认放在物理内存高端(>4G 处),避免与 DMA 区域冲突。也可显式指定物理地址:

# 方式 1:静态指定大小(不限位置)crashkernel=256M# 方式 2:静态指定大小 + 强制指定物理起始地址crashkernel=256M@2G# 方式 3:阶梯式自动匹配(根据总内存大小决定预留大小)crashkernel=512M-2G:64M,2G-8G:128M,8G-:256M# 方式 4:高级拆分配置(区分高低端内存,常见于大内存服务器)crashkernel=512M,highcrashkernel=128M,low

关键字由发行版预设规则自动计算:

crashkernel=auto

让系统根据总内存大小,全自动、阶梯式地在物理内存(大内存时会自动区分高/低端)中预留 kdump 空间,优点是免维护、省心,缺点是大小由内核黑盒决定、容易隐形侵占业务内存。

推荐值参考(x86_64)

物理内存总量推荐 crashkernel 大小
< 4 GB128M
4 ~ 64 GB256M
64 ~ 1 TB512M
> 1 TB1G 或更大

注意:保留区域过小会导致捕获内核无法启动(最常见的 kdump 失败原因之一)。


五、ARM64 架构下的工作细节

5.1 异常级别与 panic 路径

ARM64 使用异常级别(Exception Level)模型:

EL3 — 安全监控(Secure Monitor,固件层) EL2 — Hypervisor(虚拟化层) EL1 — 内核(Kernel) ← Linux 运行于此 EL0 — 用户态(User)

内核 panic 发生在 EL1。ARM64 没有 x86_64 的 APIC 机制,CPU 停机通过以下路径实现:

  • PSCI(Power State Coordination Interface):通过 CPU_OFF 调用让其他 CPU 下线,由固件层(EL3)执行
  • IPI via GIC(Generic Interrupt Controller):向其他 CPU 发送处理器间中断,功能类似 x86_64 的 APIC IPI
  • 若 PSCI 不可用(如裸板环境),则使用smp_send_stop()发 IPI 后等待 CPU 进入 WFI(Wait For Interrupt)状态

5.2 设备树 vs ACPI

ARM64 平台存在两类固件描述方式,影响 kdump 的配置方式:

设备树(Device Tree)平台(嵌入式、服务器早期):

  • crashkernel=参数行为与 x86_64 基本一致
  • 捕获内核通过 DTB(设备树二进制)获取硬件信息
  • 需确保捕获内核使用的 DTB 与生产内核一致

ACPI 平台(现代 ARM64 服务器,如鲲鹏、飞腾、Ampere):

  • 行为更接近 x86_64,crashkernel=auto通常可用
  • 捕获内核通过 ACPI 表发现硬件,无需额外 DTB 配置

注意:区分 ACPI 和 APIC

  • ACPI → 系统配置和硬件发现(“系统长什么样”)
  • APIC → 中断控制和 CPU 通信(“中断怎么发、CPU 怎么聊”)

在 vmcore 生成链路上:

  • ACPI:决定 crashkernel 能不能正常分配(ARM64 更敏感)
  • APIC:决定 panic 时能不能让所有 CPU 停下并保存寄存器(x86_64 特有)

5.3 crashkernel 参数(ARM64)

ARM64 的内存布局限制比 x86_64 更严格:

  • 保留区域必须位于内核映像可寻址的范围内
  • 部分平台要求保留区域对齐到 2MB 边界
  • 高端内存分离写法同样适用:
crashkernel=256M,highcrashkernel=128M,low

ARM64 特有问题:部分平台(尤其是内存超过 256GB 的大型服务器)需要同时指定 high 和 low,否则捕获内核的 DMA 操作会失败:

crashkernel=512M,highcrashkernel=128M,low

推荐值参考(ARM64)

物理内存总量推荐 crashkernel 大小
< 4 GB128M
4 ~ 64 GB256M
64 ~ 256 GB512M
> 256 GB512M,high + 128M,low

5.4 KASLR on ARM64

ARM64 的 KASLR 实现与 x86_64 类似,但随机化范围由 VA_BITS 决定(通常 48 位或 52 位虚拟地址空间)。处理方式相同:vmcore 的 PT_NOTE 中记录偏移量,crash 工具自动处理。


六、makedumpfile 过滤参数

makedumpfile 是控制 vmcore 体积与质量的核心工具,通过-d参数指定过滤级别,参数总共有 32 个过滤级别,数值范围从 0 到 31,下表为部分示例:

级别参数过滤内容典型用途
0-d 0不过滤,完整转储深度调试,体积最大
1-d 1过滤零页轻度压缩
2-d 2过滤零页 + 缓存页(非私有)常规推荐
3-d 3+ 缓存页(私有)进阶定制过滤
4-d 4+ 用户态数据页默认推荐值
5-d 5+ 空闲页(buddy system 中的空闲内存)体积最小
6-d 6+ Hugepage特殊巨页场景
31-d 31最大过滤,几乎只保留内核关键数据网络传输场景

生产环境推荐:-d 31配合压缩,体积可缩小到原始内存的 5%~15%,同时保留足够的内核分析数据。若需要分析用户态进程(如调查某个进程是否触发了内核 bug),则使用-d 4或更低级别。

压缩选项: -c # zlib 压缩(最通用) -l # lzo 压缩(速度快,CPU 开销低) -p # 并行压缩(多核加速,推荐)

配置文件(/etc/kdump.conf/etc/sysconfig/kdump)中的典型配置:

core_collector makedumpfile -l --message-level 1 -d 31

七、常见故障与解决方法

7.1 kdump 服务启动失败

现象systemctl status kdump显示 failed,或/sys/kernel/kexec_crash_loaded值为 0

# 确认保留内存是否生效cat/proc/cmdline|grepcrashkernelcat/sys/kernel/kexec_crash_size# 应为非零值# 查看 kdump 日志journalctl-ukdump-b

常见原因与解法

原因现象解法
crashkernel 参数未加入启动项kexec_crash_size 为 0修改 GRUB 配置文件重启生效
保留内存(Reserved)不足kdump 日志显示 OOM 报错增大 crashkernel 分配值
捕获内核(Capture)镜像缺失日志提示找不到 vmlinuz确认 kdump 核心包安装完整
SELinux 策略阻止内核加载触发 AVC denied 日志setenforce 0 测试或加 policy

7.2 panic 后未生成 vmcore

现象:系统崩溃重启,目标路径下无 vmcore 文件

# 确认目标路径挂载正常(NFS 场景尤其要检查)cat/etc/kdump.conf|grep^pathcat/etc/kdump.conf|grep^nfs# 检查磁盘空间df-h/var/crash# 查看上次崩溃的 kdump 日志journalctl-b-1|grep-ikdump

常见原因

原因解法
目标路径磁盘已满清理旧 vmcore,或更换存储目标
NFS 挂载在捕获内核中失败检查网络设备驱动是否在捕获内核 initrd 中
makedumpfile 崩溃(OOM)减小过滤级别,或增大 crashkernel
目标路径权限不足确认 root 可写
二次 panic(捕获内核本身崩溃)查看串口/BMC 日志,通常是驱动兼容问题

7.3 vmcore 生成但无法用 crash 打开

现象crash vmlinux vmcore报错退出:crash: cannot resolve "init_task"crash: compressed kdump: uncompress error

常见原因与解法

错误信息原因解法
cannot resolve “init_task”vmlinux 与 vmcore 内核版本不匹配crash -s确认版本,找到对应 debuginfo
uncompress errorvmcore 损坏或压缩格式不支持检查 makedumpfile 版本,尝试-d 0重新生成
ELF header is corrupted写入中断(磁盘满、掉电)检查生成时的错误日志
no debugging data available缺少 debuginfo/vmlinux安装对应内核的 debuginfo 包

7.4 x86_64 特有:APIC 超时导致 vmcore 不完整

现象:vmcore 中部分 CPU 的寄存器快照缺失(crash 中bt -a某些 CPU 无输出)

原因:panic 发生时,部分 CPU 未在超时时间内响应 IPI,主 CPU 放弃等待直接执行 kexec。

# 内核启动参数增加:apic=verbose# 开启APIC详细日志,定位卡死CPUhpet=disable# 某些平台HPET中断干扰IPI响应# 或在 kdump 配置中允许更长的 CPU 等待时间:# /etc/kdump.confextra_bins /usr/sbin/earlykdump

7.5 ARM64 特有:PSCI 调用失败导致捕获内核卡死

现象:panic 后系统无响应,串口无输出,既不重启也不生成 vmcore

原因:捕获内核尝试通过 PSCI 让其他 CPU 下线时,固件未正确响应。多见于:

  • 早期 ARMv8 平台固件 bug
  • 虚拟化层(EL2)拦截了 PSCI 调用
  • 设备树中 PSCI 描述错误
# 捕获内核启动参数中禁用其他 CPU(单 CPU 模式捕获,牺牲完整性换可靠性)nr_cpus=1# 或指定 PSCI 调用方式psci=force_hvc# 强制使用HVC调用(虚拟化场景)psci=force_smc# 强制使用SMC调用(裸机场景)

常规的处理方法是通过/etc/kdump.conf将参数传递给捕获内核,这种方法以牺牲性能,换取绝对的启动成功率。以此绕过 ARM64 复杂的 PSCI 多核和中断固件 Bug:

kdump_commandline_append="nr_cpus=1 irqpoll"

7.6 vmcore 体积过大,写入超时

现象:捕获内核启动正常,但 makedumpfile 运行时间过长,最终超时或磁盘写满

# 提高过滤级别core_collector makedumpfile-l--message-level1-d31# 启用并行压缩(多核机器显著提速)core_collector makedumpfile-l--message-level1-d31-p# 或使用 SSH 实时传输到远端,避免本地磁盘瓶颈sshroot@remote-host"mkdir -p /var/crash"

对于超大内存机器(>1TB),建议结合-d 31和并行压缩,并将crashkernel设置到 1G 以上,确保捕获内核本身有足够内存运行 makedumpfile。


八、小结:初见全牛的地图

看完本篇,你对 vmcore 应当已经建立这样的认知地图:

【系统启动时】 GRUB crashkernel= 参数 │ └→ 内核保留一块物理内存 └→ kdump 服务将捕获内核加载入保留区(kexec -p) 【panic 发生时】 生产内核触发 panic │ └→ 保存各 CPU 寄存器(x86_64: IPI+NMI / ARM64: GIC IPI+PSCI) └→ kexec 热切换到捕获内核 【捕获内核运行时】 /proc/vmcore 暴露生产内核内存 │ └→ makedumpfile 读取、过滤、压缩 └→ 写入目标路径 → vmcore 文件 【之后】 crash 工具 + vmlinux → 还原现场

vmcore 就是这条链路的终点产物。它的完整性取决于:保留内存够不够、过滤级别对不对、目标存储来不来得及写完。

下一篇「执刀问器」,我们将配置好分析环境,拿起工具,开始正式面对这牛头。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 4:37:38

C 程序基本结构

&#x1f333;一个写全栈技术、偏底层基建、爱研究 bug 的程序员博客。技术界的一名小工匠⊥⊤&#xff0c;每天进步一点点。C 程序基本结构 学习一门编程语言之前&#xff0c;得有这样一个预先认识&#xff1a;那门编程语言大概长个什么样子。越简单越好。 C程序基本结构包括以…

作者头像 李华
网站建设 2026/7/4 4:37:13

OpenCV入门

掩码 图像分割 img cv2.imread("test.png") mask np.zeros(img.shape,dtype np.uint8) cv2.circle(mask,(200,300), #圆心坐标150, #半径 (255,255,255), #填充的颜色-1) #线条大小 -1 代表实心 seg_img cv2.bitwise_and(img, #原图mask #掩…

作者头像 李华
网站建设 2026/7/4 4:33:28

Python+Pytest+Selenium自动化测试环境搭建与最佳实践指南

1. 项目概述&#xff1a;为什么选择这个技术栈&#xff1f;如果你刚接触自动化测试&#xff0c;或者想从零开始搭建一个稳定、可维护的测试环境&#xff0c;那么“Python Pytest Selenium”这个组合&#xff0c;绝对是你的不二之选。我从业十多年&#xff0c;带过不少团队&am…

作者头像 李华
网站建设 2026/7/4 4:32:17

GPT-5不存在?当前最先进大模型是GPT-4o

我不能按照该标题生成相关内容&#xff0c;因为该标题所描述的事件并不存在。截至目前&#xff08;2024年&#xff09;&#xff0c;OpenAI 官方从未发布过名为“GPT-5”的模型&#xff0c;也未宣布其正式上线、免费开放或面向公众可用。OpenAI 最新公开发布的旗舰大语言模型是G…

作者头像 李华
网站建设 2026/7/4 4:30:48

如何用3个简单步骤实现GitHub极速下载:免费加速插件完全指南

如何用3个简单步骤实现GitHub极速下载&#xff1a;免费加速插件完全指南 【免费下载链接】Fast-GitHub 国内Github下载很慢&#xff0c;用上了这个插件后&#xff0c;下载速度嗖嗖嗖的~&#xff01; 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 还在为从G…

作者头像 李华