diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index a6ba2990..dc83395b 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -7,12 +7,15 @@ use std::{ ptr, }; +use bytes::BufMut; + use object::Endianness; use thiserror::Error; use crate::{ generated::{btf_ext_header, btf_header}, obj::btf::{relocation::Relocation, BtfKind, BtfType}, + util::bytes_of, }; pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; @@ -291,6 +294,18 @@ impl Btf { type_id: root_type_id, }) } + + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = bytes_of::(&self.header).to_vec(); + for t in self.types() { + let b = unsafe { t.to_bytes() }; + buf.put(b.as_slice()) + } + for s in &self.strings { + buf.put_u8(*s); + } + buf + } } unsafe fn read_btf_header(data: &[u8]) -> btf_header { @@ -472,4 +487,54 @@ mod tests { assert_eq!(header.str_off, 0x2a5464); assert_eq!(header.str_len, 0x1c6410); } + + #[test] + fn test_parse_btf() { + let data: &[u8] = &[ + 0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, + 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x04, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x0d, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x01, 0x69, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x00, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x64, 0x70, 0x5f, 0x6d, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x00, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x00, 0x72, 0x78, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x00, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x5f, 0x5f, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6e, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x74, 0x78, + 0x00, 0x69, 0x6e, 0x74, 0x00, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x00, + 0x78, 0x64, 0x70, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, + 0x2f, 0x64, 0x61, 0x76, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x62, 0x70, 0x66, 0x64, + 0x2f, 0x62, 0x70, 0x66, 0x2f, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x2e, + 0x62, 0x70, 0x66, 0x2e, 0x63, 0x00, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x58, 0x44, 0x50, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x3b, 0x00, 0x63, + 0x68, 0x61, 0x72, 0x00, 0x5f, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x5f, 0x53, 0x49, + 0x5a, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5f, 0x00, 0x5f, 0x6c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x00, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x00, + ]; + let got = Btf::parse(data, Endianness::default()); + match got { + Ok(_) => {} + Err(e) => panic!("{}", e), + } + let data2 = got.unwrap().to_bytes(); + assert_eq!(data, data2); + } } diff --git a/aya/src/obj/btf/types.rs b/aya/src/obj/btf/types.rs index acbe57c6..aab93b68 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya/src/obj/btf/types.rs @@ -14,6 +14,7 @@ use crate::{ BTF_KIND_UNKN, BTF_KIND_VAR, BTF_KIND_VOLATILE, }, obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}, + util::bytes_of, }; #[derive(Clone, Debug)] @@ -149,6 +150,63 @@ impl BtfType { }) } + pub(crate) unsafe fn to_bytes(&self) -> Vec { + match self { + BtfType::Fwd(btf_type) + | BtfType::Const(btf_type) + | BtfType::Volatile(btf_type) + | BtfType::Restrict(btf_type) + | BtfType::Ptr(btf_type) + | BtfType::Typedef(btf_type) + | BtfType::Func(btf_type) + | BtfType::Float(btf_type) => bytes_of::(btf_type).to_vec(), + BtfType::Int(btf_type, len) => { + let mut buf = bytes_of::(btf_type).to_vec(); + buf.append(&mut len.to_ne_bytes().to_vec()); + buf + } + BtfType::Enum(btf_type, enums) => { + let mut buf = bytes_of::(btf_type).to_vec(); + for en in enums { + buf.append(&mut bytes_of::(en).to_vec()); + } + buf + } + BtfType::Array(btf_type, btf_array) => { + let mut buf = bytes_of::(btf_type).to_vec(); + buf.append(&mut bytes_of::(btf_array).to_vec()); + buf + } + BtfType::Struct(btf_type, btf_members) | BtfType::Union(btf_type, btf_members) => { + let mut buf = bytes_of::(btf_type).to_vec(); + for m in btf_members { + buf.append(&mut bytes_of::(m).to_vec()); + } + buf + } + BtfType::FuncProto(btf_type, btf_params) => { + let mut buf = bytes_of::(btf_type).to_vec(); + for p in btf_params { + buf.append(&mut bytes_of::(p).to_vec()); + } + buf + } + BtfType::Var(btf_type, btf_var) => { + let mut buf = bytes_of::(btf_type).to_vec(); + buf.append(&mut bytes_of::(btf_var).to_vec()); + buf + } + BtfType::DataSec(btf_type, btf_var_secinfo) => { + let mut buf = bytes_of::(btf_type).to_vec(); + for s in btf_var_secinfo { + buf.append(&mut bytes_of::(s).to_vec()); + } + buf + } + BtfType::Unknown => vec![], + } + } + pub(crate) fn type_info_size(&self) -> usize { let ty_size = mem::size_of::(); @@ -406,7 +464,8 @@ mod tests { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Int(ty, nr_bits)) => { assert_eq!(ty.name_off, 1); assert_eq!(nr_bits, 64); @@ -414,6 +473,8 @@ mod tests { Ok(t) => panic!("expected int type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -422,11 +483,14 @@ mod tests { let data: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Ptr(_)) => {} Ok(t) => panic!("expected ptr type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -436,11 +500,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Array(_, _)) => {} Ok(t) => panic!("expected array type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -450,11 +517,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x47, 0x02, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Struct(_, _)) => {} Ok(t) => panic!("expected struct type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -464,11 +534,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x04, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Union(_, _)) => {} Ok(t) => panic!("expected union type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -478,11 +551,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Enum(_, _)) => {} Ok(t) => panic!("expected enum type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -491,11 +567,14 @@ mod tests { let data: &[u8] = &[ 0x0b, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Fwd(_)) => {} Ok(t) => panic!("expected fwd type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -504,11 +583,14 @@ mod tests { let data: &[u8] = &[ 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Typedef(_)) => {} Ok(t) => panic!("expected typedef type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -517,11 +599,14 @@ mod tests { let data: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Volatile(_)) => {} Ok(t) => panic!("expected volatile type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -530,11 +615,14 @@ mod tests { let data: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Const(_)) => {} Ok(t) => panic!("expected const type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -543,11 +631,14 @@ mod tests { let data: &[u8] = &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Restrict(_)) => {} Ok(t) => panic!("expected restrict type gpt {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -556,11 +647,14 @@ mod tests { let data: &[u8] = &[ 0x17, 0x8b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xe4, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Func(_)) => {} Ok(t) => panic!("expected func type gpt {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -570,11 +664,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::FuncProto(_, _)) => {} Ok(t) => panic!("expected func_proto type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -585,11 +682,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Var(_, _)) => {} Ok(t) => panic!("expected var type, got {:#?}", t), Err(_) => panic!("unexpected error"), - } + }; + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -600,11 +700,14 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::DataSec(_, _)) => {} Ok(t) => panic!("expected datasec type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } #[test] @@ -613,10 +716,13 @@ mod tests { let data: &[u8] = &[ 0x78, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, ]; - match unsafe { BtfType::read(data, endianness) } { + let got = unsafe { BtfType::read(data, endianness) }; + match got { Ok(BtfType::Float(_)) => {} Ok(t) => panic!("expected float type, got {:#?}", t), Err(_) => panic!("unexpected error"), } + let data2 = unsafe { got.unwrap().to_bytes() }; + assert_eq!(data, data2.as_slice()) } } diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index 810cc83b..d6826127 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -609,10 +609,9 @@ fn is_program_section(name: &str) -> bool { mod tests { use matches::assert_matches; use object::Endianness; - use std::slice; use super::*; - use crate::PinningType; + use crate::{util::bytes_of, PinningType}; fn fake_section<'a>(name: &'a str, data: &'a [u8]) -> Section<'a> { Section { @@ -635,11 +634,6 @@ mod tests { } } - fn bytes_of(val: &T) -> &[u8] { - let size = mem::size_of::(); - unsafe { slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size) } - } - #[test] fn test_parse_generic_error() { assert!(matches!( diff --git a/aya/src/util.rs b/aya/src/util.rs index a2496c90..07799ed2 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -4,6 +4,7 @@ use std::{ ffi::CString, fs::{self, File}, io::{self, BufReader}, + mem, slice, str::FromStr, }; @@ -143,6 +144,12 @@ macro_rules! include_bytes_aligned { }}; } +// bytes of converts a to raw bytes +pub(crate) fn bytes_of(val: &T) -> &[u8] { + let size = mem::size_of::(); + unsafe { slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size) } +} + #[cfg(test)] mod tests { use super::*;