mirror of https://github.com/aya-rs/aya
aya: Export BTF crate
Allows users to inspect program BTF for metadata. Allows additional use cases for users who wish only to deal with BTF parsing. Signed-off-by: Dave Tucker <dave@dtucker.co.uk>pull/283/head
parent
7d8365c351
commit
512d86bba0
@ -1,3 +1,4 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": ["Cargo.toml", "bpf/Cargo.toml"]
|
||||
"rust-analyzer.linkedProjects": ["Cargo.toml", "bpf/Cargo.toml"],
|
||||
"rust-analyzer.cargo.allFeatures": true
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": ["Cargo.toml", "bpf/Cargo.toml"]
|
||||
"rust-analyzer.linkedProjects": ["Cargo.toml", "bpf/Cargo.toml"],
|
||||
"rust-analyzer.cargo.allFeatures": true
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
[workspace]
|
||||
members = ["aya", "aya-gen", "xtask"]
|
||||
members = ["aya", "aya-gen", "btftool", "xtask"]
|
||||
|
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "btftool"
|
||||
version = "0.1.0"
|
||||
authors = ["The Aya Contributors"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3", features=["derive"] }
|
||||
aya = { path = "../aya", features = ["btf"] }
|
||||
anyhow = "1"
|
||||
object = "0.28"
|
||||
thiserror = "1"
|
@ -0,0 +1,173 @@
|
||||
use aya::{
|
||||
btf::{member_bit_offset, type_vlen, BtfKind, BtfType},
|
||||
Btf, BtfError, Endianness,
|
||||
};
|
||||
use clap::{Parser, Subcommand};
|
||||
use object::{Object, ObjectSection};
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
fs, io,
|
||||
path::Path,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Dumps the .BTF ELF Section
|
||||
Dump { file: Option<String> },
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error(".BTF section not found")]
|
||||
NoBTF,
|
||||
#[error("error parsing ELF data")]
|
||||
ElfError(#[from] object::read::Error),
|
||||
#[error(transparent)]
|
||||
IOError(io::Error),
|
||||
#[error(transparent)]
|
||||
FmtError(fmt::Error),
|
||||
#[error(transparent)]
|
||||
BtfError(BtfError),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
let cli = Cli::parse();
|
||||
match &cli.command {
|
||||
Commands::Dump { file } => {
|
||||
dump(file.as_ref().unwrap())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dump<P: AsRef<Path>>(input: P) -> Result<(), Error> {
|
||||
let bin_data = fs::read(input).map_err(Error::IOError)?;
|
||||
let obj_file = object::File::parse(&*bin_data).map_err(Error::ElfError)?;
|
||||
if let Some(section) = obj_file.section_by_name(".BTF") {
|
||||
let btf = Btf::parse(section.data()?, Endianness::default()).map_err(Error::BtfError)?;
|
||||
for (i, t) in btf.types().enumerate().skip(1) {
|
||||
let kind = t.kind().unwrap_or(None).unwrap_or(BtfKind::Unknown);
|
||||
let name = if let Some(offset) = t.name_offset() {
|
||||
if offset > 0 {
|
||||
format!(
|
||||
"'{}'",
|
||||
btf.string_at(offset)
|
||||
.unwrap_or(std::borrow::Cow::Borrowed(""))
|
||||
)
|
||||
} else {
|
||||
"''".to_owned()
|
||||
}
|
||||
} else {
|
||||
"''".to_owned()
|
||||
};
|
||||
let info = match t {
|
||||
BtfType::Unknown => "".to_string(),
|
||||
BtfType::Fwd(t)
|
||||
| BtfType::Const(t)
|
||||
| BtfType::Volatile(t)
|
||||
| BtfType::Restrict(t)
|
||||
| BtfType::Ptr(t)
|
||||
| BtfType::Typedef(t)
|
||||
| BtfType::Func(t) => {
|
||||
format!("type_id={}", unsafe { t.__bindgen_anon_1.type_ })
|
||||
}
|
||||
BtfType::Int(t, size) => {
|
||||
let encoding = match (t.info & 0x0f000000) >> 24 {
|
||||
1 => "(signed)",
|
||||
2 => "(char)",
|
||||
4 => "(bool)",
|
||||
_ => "(none)",
|
||||
};
|
||||
let offset = (t.info & 0x00ff0000) >> 16;
|
||||
let bits = t.info & 0x000000ff;
|
||||
format!(
|
||||
"size={} bits_offset={} nr_bits={} encoding={}",
|
||||
size, offset, bits, encoding,
|
||||
)
|
||||
}
|
||||
BtfType::Float(_) => todo!(),
|
||||
BtfType::Enum(_, _) => todo!(),
|
||||
BtfType::Array(_, array) => {
|
||||
format!(
|
||||
"type_id={} index_type_id={} nr_elems={}",
|
||||
array.type_, array.index_type, array.nelems
|
||||
)
|
||||
}
|
||||
BtfType::Struct(ty, members) => {
|
||||
let size = unsafe { ty.__bindgen_anon_1.size };
|
||||
let vlen = type_vlen(ty);
|
||||
let mut out = format!("size={} vlen={}", size, vlen,);
|
||||
for m in members {
|
||||
let name = btf
|
||||
.string_at(m.name_off)
|
||||
.unwrap_or(std::borrow::Cow::Borrowed(""));
|
||||
let type_id = m.type_;
|
||||
let offset = member_bit_offset(ty.info, m);
|
||||
write!(out, "\n\t'{name}' type_id={type_id} bits_offset={offset}")
|
||||
.map_err(Error::FmtError)?;
|
||||
}
|
||||
out
|
||||
}
|
||||
BtfType::Union(_, _) => todo!(),
|
||||
BtfType::FuncProto(ty, params) => {
|
||||
let ret_type_id = unsafe { ty.__bindgen_anon_1.type_ };
|
||||
let vlen = type_vlen(ty);
|
||||
let mut out = format!("ret_type_id={ret_type_id} vlen={vlen}");
|
||||
for p in params {
|
||||
let name = btf
|
||||
.string_at(p.name_off)
|
||||
.unwrap_or(std::borrow::Cow::Borrowed(""));
|
||||
let type_id = p.type_;
|
||||
write!(out, "\n\t'{name}' type_id={type_id}").map_err(Error::FmtError)?;
|
||||
}
|
||||
out
|
||||
}
|
||||
BtfType::Var(ty, var) => {
|
||||
let type_id = unsafe { ty.__bindgen_anon_1.type_ };
|
||||
let linkage = match var.linkage {
|
||||
0 => "static".to_owned(),
|
||||
1 => "global".to_owned(),
|
||||
other => format!("{other}"),
|
||||
};
|
||||
format!("type_id={type_id} linkage={linkage}")
|
||||
}
|
||||
BtfType::DataSec(ty, secinfo) => {
|
||||
let size = unsafe { ty.__bindgen_anon_1.size };
|
||||
let vlen = type_vlen(ty);
|
||||
let mut out = format!("size={size} vlen={vlen}");
|
||||
for s in secinfo {
|
||||
let points_to = btf.type_by_id(s.type_).unwrap();
|
||||
let name = btf
|
||||
.string_at(points_to.name_offset().unwrap_or(0))
|
||||
.unwrap_or(std::borrow::Cow::Borrowed(""));
|
||||
write!(
|
||||
out,
|
||||
"\n\ttype_id={} offset={} size={} ({} '{}')",
|
||||
s.type_,
|
||||
s.offset,
|
||||
s.size,
|
||||
points_to.kind().unwrap_or(None).unwrap_or(BtfKind::Unknown),
|
||||
name
|
||||
)
|
||||
.map_err(Error::FmtError)?;
|
||||
}
|
||||
out
|
||||
}
|
||||
BtfType::DeclTag(_, _) => unimplemented!("decl tag formatting not implemented"),
|
||||
BtfType::TypeTag(_) => unimplemented!("type tag formatting not implemented"),
|
||||
};
|
||||
println!("[{i}] {kind} {name} {info}");
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NoBTF)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue