跳转至

KernLens 教程

逐个命令走一遍 KernLens,输出取自真实内核,而不是编造的例子。

每页结构一致:命令回答什么、确切的调用、它在捕获内核上产生的输出、如何读这段输出,以及它在什么情况下会拒绝。页面按 kl-help 打印的分类分组。

捕获内核

本教程的全部输出来自项目测试虚拟机的一次启动:

事实 值
内核 6.1.134 (x86_64, DWARF debug info)
CPU 数 4
SLUB 缓存数 170
KASLR 偏移 0x2d800000
_text(链接时) 0xffffffff81000000
_text(运行时) 0xffffffffae800000
page_offset_base 0xffff90c340000000
vmemmap_base 0xffffcd3b80000000
一个空闲页(物理) 0x400000
它的直接映射别名 0xffff90c340400000
它的 struct page 0xffffcd3b80010000

page_offset_base 与 vmemmap_base 是启动代码填进去的内核变量,所以每次启动都会变,偏移也随之变化。这里其余的(结构体偏移、zone 列表、缓存名、符号名)对本次构建是稳定的。凡是与启动相关的,KernLens 都在运行时重新推导而不是假定,这就是命令显示这些数字而不是某个常量的原因。

复现这份捕获

(gdb) source /path/to/KernLens/gdbinit.py
(gdb) file /path/to/vmlinux
(gdb) target remote :1234
(gdb) kl-color off
(gdb) python exec(open("tools/tutorial_capture.py").read())

kl-color off 不是装饰:它让捕获文本里没有 ANSI 转义序列,这些页面才能干净地 diff。捕获脚本写出 tools/tutorial_capture.json;tools/gen_tutorial.py 再从它渲染页面,页面与捕获不一致时 --check 会失败。

怎么读这些页面

  • 调用 —— 确切的命令行。用的是 kl- 别名;每一个都展开为 kernlens- 名。
  • 输出 —— 原样,包括对齐。表头行下缩进两格是 KernLens 表示“该记录的一行”的约定。
  • 读法 —— 每一行是什么意思,以及从这些值能得出什么结论。
  • 说明 —— 这些值从哪来(DWARF、BTF、注册表兜底,还是裸内存),以及命令在什么情况下拒绝。

页面

Help

在命令集里找到方向。

命令 它回答什么
kl-help Lists every KernLens command, or explains one in detail.

Overview

在陌生的会话上第一个该跑的命令。

命令 它回答什么
kl-status Shows the KernLens version, color mode, KASLR slide, and layout.

Kernel base & kaslr

内核被加载到哪里,以及 KernLens 如何应对随机化的基址。

命令 它回答什么
kl-base Reports the runtime kernel text base and KASLR slide.

Kernel metadata

配置与构建信息:命令行、版本、选项、模块、系统调用表,以及日志。

命令 它回答什么
kl-kcmdline Return the kernel command line (/proc/cmdline).
kl-kconfig Outputs the kernel config (/proc/config.gz).
kl-kdmesg Displays the kernel ring buffer (dmesg) contents.
kl-kmod Displays the loaded Linux kernel modules.
kl-ksyscalls Displays the Linux syscall table, including names and addresses of syscalls.
kl-kversion Outputs the kernel version (/proc/version).

Cpu topology

有多少 CPU,它们的 per-CPU 数据在哪里。

命令 它回答什么
kl-cpu Displays CPU topology, the online mask, and per-CPU offsets.
kl-msr Reads or writes x86_64 model-specific registers (via GDB).
kl-percpu Resolves a per-CPU symbol to its runtime address for a CPU.

Addresses & page tables

从一个原始 64 位值到它指向的物理页,两个方向都有。

命令 它回答什么
kl-addr Classifies an address and reports where it maps.
kl-p2v Translates a physical address to virtual + struct page.
kl-pageinfo Translates a struct page to virtual and physical addresses.
kl-pt Splits a virtual address into page-table indices, or decodes a page-table entry.
kl-v2p Translates a virtual address (live page tables) to physical.
kl-walk Walks the live page tables and decodes every level.

Memory & symbols

读内核自己的内存:符号、栈、SLUB、buddy 分配器、BPF 与 dma-buf。

命令 它回答什么
kl-bt Prints a formatted kernel backtrace.
kl-buddy Locates an address in the buddy allocator: its zone, its free block, and where it sits inside that block.
kl-kbpf Prints information about the linux kernel bpf progs and maps.
kl-kdmabuf Prints DMA buf info.
kl-kvar Reads a KASLR-aware kernel global variable.
kl-read Dumps kernel memory as 64-bit words with symbol annotations.
kl-read-field Reads a struct field (including nested paths), whatever its type.
kl-slab Prints information about the linux kernel's slab allocator SLUB.
kl-sym Resolves an address to a symbol, or finds symbols by name.

Bit & integer primitives

对手上已有的值做纯算术。这是仅有的几个完全不碰内核状态的命令。

命令 它回答什么
kl-bits Inspects a 64-bit value; optionally test/set/clear a bit.
kl-int Shows signed/unsigned and LE/BE integer views.

Output

输出呈现控制。

命令 它回答什么
kl-color Enable, disable, or toggle ANSI color output.

每页通用的约定

KernLens 的输出区分三种状态,读这些页面时这个区分很重要:

  • 一个值(Size: 0xc0)—— 从活动内核读出;
  • ? —— 该数据在本次构建或当前状态下不可得,命令如实说明,而不是打印一个看似合理的 0;
  • <unreadable> —— 内存完全读不出来(坏地址、页未加载)。

每层嵌套缩进两格对齐,标签后面跟 :(一个空格),这样值能排成一列。


由 tools/gen_tutorial_index.py 从与页面相同的捕获生成。不要手改:重新运行生成器。