Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

vmlinuxAddrResolver

该库用于把 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 ->

快速开始(作为库在你项目中使用)

  1. 在你的项目的 Cargo.toml 中添加依赖(本仓库作为本地依赖):
[dependencies]
addr_resolver = { path = "../addr_resolver" }  # 根据你的项目目录调整路径
anyhow = "1.0"
  1. 代码示例:
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)

仓库自带了 dotest 示例程序,演示了如何批量解析地址列表。

步骤:

  1. 克隆仓库(或在本地已有仓库):
git clone https://github.com/j1akai/vmlinuxAddrResolver.git
cd vmlinuxAddrResolver
  1. 从源码编译构建linux,将vmlinux放在dotest下(把文件保存为 dotest/vmlinux)。
  2. 设置 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")?;
  1. 进入 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 时)。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages