wip: bpftool but with aya

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/902/head
Dave Tucker 7 months ago
parent d6dfd678f0
commit 1d752136b9

@ -46,6 +46,11 @@ pub enum BtfError {
#[error("error parsing BTF header")]
InvalidHeader,
/// Invalid ELF data
#[cfg(feature = "std")]
#[error("error parsing ELF")]
Elf,
/// invalid BTF type info segment
#[error("invalid BTF type info segment")]
InvalidTypeInfo,
@ -276,7 +281,8 @@ impl Btf {
self.types.types.len() < 2
}
pub(crate) fn types(&self) -> impl Iterator<Item = &BtfType> {
/// Iterates over the BTF types.
pub fn types(&self) -> impl Iterator<Item = &BtfType> {
self.types.types.iter()
}
@ -307,7 +313,7 @@ impl Btf {
/// Loads BTF metadata from the given `path`.
#[cfg(feature = "std")]
pub fn parse_file<P: AsRef<std::path::Path>>(
pub(crate) fn parse_file<P: AsRef<std::path::Path>>(
path: P,
endianness: Endianness,
) -> Result<Btf, BtfError> {
@ -322,6 +328,26 @@ impl Btf {
)
}
/// Loads BTF metadata from an ELF section.
#[cfg(feature = "std")]
pub fn parse_elf_file<P: AsRef<std::path::Path>>(
path: P,
endianness: Endianness,
) -> Result<Btf, BtfError> {
use object::{Object, ObjectSection};
let path = path.as_ref();
let bin_data = std::fs::read(path).map_err(|e| BtfError::FileError {
path: path.to_owned(),
error: e,
})?;
let obj_file = object::File::parse(&*bin_data).map_err(|_| BtfError::Elf)?;
let section = obj_file
.section_by_name(".BTF")
.ok_or_else(|| BtfError::InvalidHeader)?;
let data = section.data().map_err(|_| BtfError::InvalidHeader)?;
Btf::parse(data, endianness)
}
/// Parses BTF from binary data of the given endianness
pub fn parse(data: &[u8], endianness: Endianness) -> Result<Btf, BtfError> {
if data.len() < mem::size_of::<btf_header>() {
@ -374,7 +400,8 @@ impl Btf {
Ok(types)
}
pub(crate) fn string_at(&self, offset: u32) -> Result<Cow<'_, str>, BtfError> {
/// Returns the string at the given offset within the BTF metadata.
pub fn string_at(&self, offset: u32) -> Result<Cow<'_, str>, BtfError> {
let btf_header {
hdr_len,
mut str_off,
@ -400,7 +427,8 @@ impl Btf {
Ok(s.to_string_lossy())
}
pub(crate) fn type_by_id(&self, type_id: u32) -> Result<&BtfType, BtfError> {
/// Returns the BtfType at the given type id.
pub fn type_by_id(&self, type_id: u32) -> Result<&BtfType, BtfError> {
self.types.type_by_id(type_id)
}

@ -82,6 +82,10 @@ impl Const {
btf_type,
}
}
/// The target type of the const.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -104,6 +108,11 @@ impl Volatile {
pub(crate) fn type_info_size(&self) -> usize {
mem::size_of::<Self>()
}
/// The target type of the volatile.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[derive(Clone, Debug)]
@ -125,6 +134,11 @@ impl Restrict {
pub(crate) fn type_info_size(&self) -> usize {
mem::size_of::<Self>()
}
/// The target type of the restrict.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -156,6 +170,11 @@ impl Ptr {
btf_type,
}
}
/// The target type of the pointer.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -187,6 +206,11 @@ impl Typedef {
btf_type,
}
}
/// The target type of the typedef.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -276,6 +300,11 @@ impl Func {
pub(crate) fn set_linkage(&mut self, linkage: FuncLinkage) {
self.info = (self.info & 0xFFFF0000) | (linkage as u32) & 0xFFFF;
}
/// The target type of the func.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -378,17 +407,23 @@ impl Int {
}
}
pub(crate) fn encoding(&self) -> IntEncoding {
/// The integer size.
pub fn size(&self) -> u32 {
self.size
}
/// The integer encoding.
pub fn encoding(&self) -> IntEncoding {
((self.data & 0x0f000000) >> 24).into()
}
pub(crate) fn offset(&self) -> u32 {
/// The offset of the integer.
pub fn offset(&self) -> u32 {
(self.data & 0x00ff0000) >> 16
}
// TODO: Remove directive this when this crate is pub
#[cfg(test)]
pub(crate) fn bits(&self) -> u32 {
/// The size of the integer in bits.
pub fn bits(&self) -> u32 {
self.data & 0x000000ff
}
}
@ -563,15 +598,27 @@ impl Enum64 {
}
}
}
/// A member of a struct or union.
#[repr(C)]
#[derive(Clone, Debug)]
pub(crate) struct BtfMember {
pub struct BtfMember {
pub(crate) name_offset: u32,
pub(crate) btf_type: u32,
pub(crate) offset: u32,
}
impl BtfMember {
/// The offset of the members name in the BTF string section.
pub fn name_offset(&self) -> u32 {
self.name_offset
}
/// The type of the member.
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Struct {
@ -632,7 +679,8 @@ impl Struct {
}
}
pub(crate) fn member_bit_offset(&self, member: &BtfMember) -> usize {
/// The offset of the member within the struct or union.
pub fn member_bit_offset(&self, member: &BtfMember) -> usize {
let k_flag = self.info >> 31 == 1;
let bit_offset = if k_flag {
member.offset & 0xFFFFFF
@ -649,6 +697,21 @@ impl Struct {
size as usize
}
/// The size of the struct.
pub fn size(&self) -> u32 {
self.size
}
/// Vlen
pub fn vlen(&self) -> usize {
type_vlen(self.info)
}
/// The members of the struct.
pub fn members(&self) -> &[BtfMember] {
&self.members
}
}
#[repr(C)]
@ -771,6 +834,14 @@ impl Array {
mem::size_of::<Self>()
}
pub fn index_type(&self) -> u32 {
self.array.index_type
}
pub fn len(&self) -> u32 {
self.array.len
}
#[cfg(test)]
pub(crate) fn new(name_offset: u32, element_type: u32, index_type: u32, len: u32) -> Self {
let info = (BtfKind::Array as u32) << 24;
@ -790,8 +861,24 @@ impl Array {
#[repr(C)]
#[derive(Clone, Debug)]
pub struct BtfParam {
pub name_offset: u32,
pub btf_type: u32,
pub(crate) name_offset: u32,
pub(crate) btf_type: u32,
}
impl BtfParam {
pub fn new(name_offset: u32, btf_type: u32) -> Self {
Self {
name_offset,
btf_type,
}
}
pub fn name_offset(&self) -> u32 {
self.name_offset
}
pub fn btf_type(&self) -> u32 {
self.btf_type
}
}
#[repr(C)]
@ -836,6 +923,18 @@ impl FuncProto {
mem::size_of::<Fwd>() + mem::size_of::<BtfParam>() * self.params.len()
}
pub fn return_type(&self) -> u32 {
self.return_type
}
pub fn vlen(&self) -> usize {
type_vlen(self.info)
}
pub fn params(&self) -> &[BtfParam] {
&self.params
}
pub fn new(params: Vec<BtfParam>, return_type: u32) -> Self {
let mut info = (BtfKind::FuncProto as u32) << 24;
info |= (params.len() as u32) & 0xFFFF;
@ -911,14 +1010,43 @@ impl Var {
linkage,
}
}
pub fn btf_type(&self) -> u32 {
self.btf_type
}
pub fn linkage(&self) -> &VarLinkage {
&self.linkage
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct DataSecEntry {
pub btf_type: u32,
pub offset: u32,
pub size: u32,
pub(crate) btf_type: u32,
pub(crate) offset: u32,
pub(crate) size: u32,
}
impl DataSecEntry {
pub fn new(btf_type: u32, offset: u32, size: u32) -> Self {
Self {
btf_type,
offset,
size,
}
}
pub fn btf_type(&self) -> u32 {
self.btf_type
}
pub fn offset(&self) -> u32 {
self.offset
}
pub fn size(&self) -> u32 {
self.size
}
}
#[repr(C)]
@ -980,6 +1108,18 @@ impl DataSec {
entries,
}
}
pub fn size(&self) -> u32 {
self.size
}
pub fn vlen(&self) -> usize {
type_vlen(self.info)
}
pub fn entries(&self) -> &[DataSecEntry] {
&self.entries
}
}
#[repr(C)]
@ -1337,7 +1477,8 @@ impl BtfType {
}
}
pub(crate) fn name_offset(&self) -> u32 {
/// Returns the name offset of the BTF type.
pub fn name_offset(&self) -> u32 {
match self {
BtfType::Unknown => 0,
BtfType::Fwd(t) => t.name_offset,
@ -1362,7 +1503,8 @@ impl BtfType {
}
}
pub(crate) fn kind(&self) -> BtfKind {
/// Returns the kind of the BTF type.
pub fn kind(&self) -> BtfKind {
match self {
BtfType::Unknown => BtfKind::Unknown,
BtfType::Fwd(t) => t.kind(),

@ -9,8 +9,10 @@ homepage.workspace = true
edition.workspace = true
[dependencies]
aya-obj = { version = "0.1.0", path = "../aya-obj", features = ["std"] }
bindgen = { workspace = true, default-features = true }
clap = { workspace = true, default-features = true, features = ["derive"] }
anyhow = { workspace = true, default-features = true }
thiserror = { workspace = true }
tempfile = { workspace = true }
object = { workspace = true }

@ -1,5 +1,6 @@
use std::{path::PathBuf, process::exit};
use aya_tool::btf::print_btf;
use aya_tool::generate::{generate, InputFile};
use clap::Parser;
@ -23,6 +24,12 @@ enum Command {
#[clap(last = true, action)]
bindgen_args: Vec<String>,
},
/// Pretty print an ELF file's BTF
#[clap(name = "print-btf", action)]
PrintBtf {
/// The ELF file to print BTF for
target: PathBuf,
},
}
fn main() {
@ -48,6 +55,9 @@ fn try_main() -> Result<(), anyhow::Error> {
};
println!("{bindings}");
}
Command::PrintBtf { target } => {
print_btf(target)?;
}
};
Ok(())

@ -0,0 +1,119 @@
use aya_obj::btf::{Btf, BtfType, IntEncoding, VarLinkage};
use object::Endianness;
use std::{fmt::Write, path::Path};
pub fn print_btf<P: AsRef<Path>>(path: P) -> anyhow::Result<()> {
let btf = Btf::parse_elf_file(path, Endianness::default())?;
for (i, t) in btf.types().enumerate().skip(1) {
let kind = t.kind();
let name = if t.name_offset() > 0 {
format!(
"'{}'",
btf.string_at(t.name_offset())
.unwrap_or(std::borrow::Cow::Borrowed(""))
)
} else {
"''".to_owned()
};
let info = match t {
BtfType::Unknown => "".to_string(),
BtfType::Fwd(_) => "type_id=0".to_string(),
BtfType::Const(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Volatile(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Restrict(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Ptr(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Typedef(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Func(ty) => format!("type_id={}", ty.btf_type()),
BtfType::Int(i) => {
let encoding = match i.encoding() {
IntEncoding::Signed => "(signed)",
IntEncoding::Char => "(char)",
IntEncoding::Bool => "(bool)",
IntEncoding::None => "(none)",
IntEncoding::Unknown => "(unknown)",
};
format!(
"size={} bits_offset={} nr_bits={} encoding={}",
i.size(),
i.offset(),
i.bits(),
encoding,
)
}
BtfType::Float(_) => todo!(),
BtfType::Enum(_) => todo!(),
BtfType::Array(ty) => {
format!(
"type_id=0 index_type_id={} nr_elems={}",
ty.index_type(),
ty.len()
)
}
BtfType::Struct(ty) => {
let size = ty.size();
let vlen = ty.vlen();
let mut out = format!("size={} vlen={}", size, vlen,);
for m in ty.members() {
let name = btf
.string_at(m.name_offset())
.unwrap_or(std::borrow::Cow::Borrowed(""));
let type_id = m.btf_type();
let offset = ty.member_bit_offset(m);
write!(out, "\n\t'{name}' type_id={type_id} bits_offset={offset}")?;
}
out
}
BtfType::Union(_) => todo!(),
BtfType::FuncProto(ty) => {
let ret_type_id = ty.return_type();
let vlen = ty.vlen();
let mut out = format!("ret_type_id={ret_type_id} vlen={vlen}");
for p in ty.params() {
let name = btf
.string_at(p.name_offset())
.unwrap_or(std::borrow::Cow::Borrowed(""));
let type_id = p.btf_type();
write!(out, "\n\t'{name}' type_id={type_id}")?;
}
out
}
BtfType::Var(ty) => {
let type_id = ty.btf_type();
let linkage = match ty.linkage() {
VarLinkage::Static => "static".to_owned(),
VarLinkage::Global => "global".to_owned(),
VarLinkage::Extern => "extern".to_owned(),
VarLinkage::Unknown => "unknown".to_owned(),
};
format!("type_id={type_id} linkage={linkage}")
}
BtfType::DataSec(ty) => {
let size = ty.size();
let vlen = ty.vlen();
let mut out = format!("size={size} vlen={vlen}");
for entry in ty.entries() {
let points_to = btf.type_by_id(entry.btf_type()).unwrap();
let name = btf
.string_at(points_to.name_offset())
.unwrap_or(std::borrow::Cow::Borrowed(""));
write!(
out,
"\n\ttype_id={} offset={} size={} ({} '{}')",
entry.btf_type(),
entry.offset(),
entry.size(),
points_to.kind(),
name
)?;
}
out
}
BtfType::DeclTag(_) => unimplemented!("decl tag formatting not implemented"),
BtfType::TypeTag(_) => unimplemented!("type tag formatting not implemented"),
BtfType::Enum64(_) => unimplemented!("enum64 formatting not implemented"),
};
println!("[{i}] {kind} {name} {info}");
}
Ok(())
}

@ -5,6 +5,7 @@ use std::{
};
pub mod bindgen;
pub mod btf;
pub mod generate;
pub mod rustfmt;

@ -849,14 +849,8 @@ pub(crate) fn is_btf_func_supported() -> bool {
let a_name = btf.add_string("a");
let b_name = btf.add_string("b");
let params = vec![
BtfParam {
name_offset: a_name,
btf_type: int_type_id,
},
BtfParam {
name_offset: b_name,
btf_type: int_type_id,
},
BtfParam::new(a_name, int_type_id),
BtfParam::new(b_name, int_type_id),
];
let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
let func_proto_type_id = btf.add_type(func_proto);
@ -879,14 +873,8 @@ pub(crate) fn is_btf_func_global_supported() -> bool {
let a_name = btf.add_string("a");
let b_name = btf.add_string("b");
let params = vec![
BtfParam {
name_offset: a_name,
btf_type: int_type_id,
},
BtfParam {
name_offset: b_name,
btf_type: int_type_id,
},
BtfParam::new(a_name, int_type_id),
BtfParam::new(b_name, int_type_id),
];
let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
let func_proto_type_id = btf.add_type(func_proto);
@ -911,11 +899,7 @@ pub(crate) fn is_btf_datasec_supported() -> bool {
let var_type_id = btf.add_type(var_type);
let name_offset = btf.add_string(".data");
let variables = vec![DataSecEntry {
btf_type: var_type_id,
offset: 0,
size: 4,
}];
let variables = vec![DataSecEntry::new(var_type_id, 0, 4)];
let datasec_type = BtfType::DataSec(DataSec::new(name_offset, variables, 4));
btf.add_type(datasec_type);

Loading…
Cancel
Save