该库用于把 32 位的 Linux 内核地址(u32,十进制)解析为源码文件和行号,依赖于 vmlinux(包含 DWARF 调试信息)。
仓库包含两个部分:
addr_resolver(库):读取 vmlinux、构建 addr2line 上下文并对单个 u32 地址进行解析。dotest(示例可执行程序):演示如何使用addr_resolver来批量解析一组地址(示例内嵌了大量地址)。
- 输入:一个十进制的 u32 内核地址(例如 2164290047)。
- 地址扩展规则(内核地址规则):
- addr64 = (addr_u32 as u64) | 0xFFFF_FFFF_0000_0000
- 输出:若能在 DWARF 中找到对应位置,返回 source_path:line(其中 source_path 会尝试相对于你提供的 linux 源码根路径做简化);否则返回 “无位置”。
- 典型输出形式(在
dotest中):- 2164290047 -> mm/file.c:123
- 2164290061 ->
- 在你的项目的
Cargo.toml中添加依赖(本仓库作为本地依赖):
[dependencies]
addr_resolver = { path = "../addr_resolver" } # 根据你的项目目录调整路径
anyhow = "1.0"- 代码示例:
use anyhow::Result;
use addr_resolver::AddrResolver;
use std::path::Path;
fn example() -> Result<()> {
// vmlinux 文件(包含 DWARF)和 linux 源码根目录(绝对路径)
let resolver = AddrResolver::new(Path::new("/path/to/vmlinux"), Path::new("/absolute/path/to/linux"))?;
let addr_u32: u32 = 2164290047;
match resolver.resolve(addr_u32)? {
Some((file, line)) => println!("{} -> {}:{}", addr_u32, file, line),
None => println!("{} -> <no location>", addr_u32),
}
Ok(())
}API 说明(主要接口):
AddrResolver::new<P: AsRef<Path>, R: AsRef<Path>>(vmlinux_path: P, linux_src_root: R) -> Result<AddrResolver>- vmlinux_path:包含 DWARF 调试信息的 vmlinux 二进制文件路径
- linux_src_root:用于简化 DWARF 中返回的文件路径(如果 DWARF 文件路径在该根目录下,会去掉前缀)
AddrResolver::resolve(&self, addr: u32) -> Result<Option<(String, u32)>>- 返回:Ok(Some((path, line))) 或 Ok(None)(未找到),及错误
仓库自带了 dotest 示例程序,演示了如何批量解析地址列表。
步骤:
- 克隆仓库(或在本地已有仓库):
git clone https://github.com/j1akai/vmlinuxAddrResolver.git
cd vmlinuxAddrResolver- 从源码编译构建linux,将vmlinux放在dotest下(把文件保存为 dotest/vmlinux)。
- 设置 linux 源码根路径:
dotest/src/main.rs中当前硬编码了:AddrResolver::new(vmlinux_path, "/home/jiaai/linux")。你需要把"/home/jiaai/linux"修改为你本地的 linux 源码树的绝对路径(即编译 vmlinux 时使用的源码根路径)。
例如编辑 dotest/src/main.rs,改为:
let resolver = AddrResolver::new(vmlinux_path, "/absolute/path/to/your/linux")?;- 进入
dotest并运行:
cd dotest
cargo run --release程序会读取示例中内嵌的地址列表(常量 ADDRS),逐个解析并打印结果。运行结束会在 stderr 打印处理的地址个数,效果如下:
...
...
2209260383 -> lib/radix-tree.c:67
2209260480 -> lib/radix-tree.c:768
2209260490 -> lib/radix-tree.c:772
11111111 -> <no location>
2209260594 -> lib/radix-tree.c:777
2209260994 -> lib/radix-tree.c:817
2210482572 -> arch/x86/include/asm/irqflags.h:40
done, processed 1575 addresses注意:
- 如果你看到错误 "vmlinux not found":请确认
dotest/vmlinux文件存在且可读。 - 如果输出为
<no location>:可能 vmlinux 不包含 DWARF 信息,或地址不在任何符号/行信息范围内。
- vmlinux 必须包含 DWARF 调试信息(通常需要带 debug 信息的内核镜像)。
- linux 源码根路径需要是绝对路径且是你构建 vmlinux 时使用的源码树根(用于路径简化)。
- 为了把 addr2line 的 Context 保存在结构体中并避免复杂的生命周期,库会将读取的 vmlinux bytes 泄漏(Box::leak),这是刻意为之以简化实现。仅发生一次(在创建 AddrResolver 时)。