diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index 64d7baa2..709b29f0 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -110,7 +110,7 @@ impl Btf { } // safety: btf_header is POD so read_unaligned is safe - let header = unsafe { ptr::read_unaligned(data.as_ptr() as *const btf_header) }; + let header = unsafe { read_btf_header(data) }; let str_off = header.hdr_len as usize + header.str_off as usize; let str_len = header.str_len as usize; @@ -229,7 +229,12 @@ impl Btf { use BtfType::*; let size = match ty { - Int(ty, _) | Struct(ty, _) | Union(ty, _) | Enum(ty, _) | DataSec(ty, _) | Float(ty) => { + Int(ty, _) + | Struct(ty, _) + | Union(ty, _) + | Enum(ty, _) + | DataSec(ty, _) + | Float(ty) => { // Safety: union unsafe { ty.__bindgen_anon_1.size as usize } } @@ -258,6 +263,11 @@ impl Btf { } } +unsafe fn read_btf_header(data: &[u8]) -> btf_header { + // safety: btf_header is POD so read_unaligned is safe + ptr::read_unaligned(data.as_ptr() as *const btf_header) +} + #[derive(Debug, Clone)] pub struct BtfExt { data: Vec, @@ -411,3 +421,25 @@ pub(crate) struct SecInfo<'a> { num_info: u32, data: &'a [u8], } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_header() { + let data: &[u8] = &[ + 0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x54, + 0x2a, 0x00, 0x64, 0x54, 0x2a, 0x00, 0x10, 0x64, 0x1c, 0x00, + ]; + let header = unsafe { read_btf_header(data) }; + assert_eq!(header.magic, 0xeb9f); + assert_eq!(header.version, 0x01); + assert_eq!(header.flags, 0x00); + assert_eq!(header.hdr_len, 0x18); + assert_eq!(header.type_off, 0x00); + assert_eq!(header.type_len, 0x2a5464); + assert_eq!(header.str_off, 0x2a5464); + assert_eq!(header.str_len, 0x1c6410); + } +} diff --git a/aya/src/obj/btf/types.rs b/aya/src/obj/btf/types.rs index 42f5ee3c..9c789314 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya/src/obj/btf/types.rs @@ -9,9 +9,9 @@ use crate::{ generated::{ btf_array, btf_enum, btf_member, btf_param, btf_type, btf_type__bindgen_ty_1, btf_var, btf_var_secinfo, BTF_KIND_ARRAY, BTF_KIND_CONST, BTF_KIND_DATASEC, BTF_KIND_ENUM, - BTF_KIND_FUNC, BTF_KIND_FUNC_PROTO, BTF_KIND_FWD, BTF_KIND_INT, BTF_KIND_FLOAT, BTF_KIND_PTR, - BTF_KIND_RESTRICT, BTF_KIND_STRUCT, BTF_KIND_TYPEDEF, BTF_KIND_UNION, BTF_KIND_UNKN, - BTF_KIND_VAR, BTF_KIND_VOLATILE, + BTF_KIND_FLOAT, BTF_KIND_FUNC, BTF_KIND_FUNC_PROTO, BTF_KIND_FWD, BTF_KIND_INT, + BTF_KIND_PTR, BTF_KIND_RESTRICT, BTF_KIND_STRUCT, BTF_KIND_TYPEDEF, BTF_KIND_UNION, + BTF_KIND_UNKN, BTF_KIND_VAR, BTF_KIND_VOLATILE, }, obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}, }; @@ -155,9 +155,8 @@ impl BtfType { use BtfType::*; match self { Unknown => 0, - Fwd(_) | Const(_) | Volatile(_) | Restrict(_) | Ptr(_) | Typedef(_) | Func(_) | Float(_) => { - ty_size - } + Fwd(_) | Const(_) | Volatile(_) | Restrict(_) | Ptr(_) | Typedef(_) | Func(_) + | Float(_) => ty_size, Int(_, _) => ty_size + mem::size_of::(), Enum(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), Array(_, _) => ty_size + mem::size_of::(), @@ -262,7 +261,9 @@ pub(crate) fn types_are_compatible( use BtfType::*; match local_ty { - Unknown | Struct(_, _) | Union(_, _) | Enum(_, _) | Fwd(_) | Float(_) => return Ok(true), + Unknown | Struct(_, _) | Union(_, _) | Enum(_, _) | Fwd(_) | Float(_) => { + return Ok(true) + } Int(_, local_off) => { if let Int(_, target_off) = target_ty { return Ok(*local_off == 0 && *target_off == 0); @@ -393,3 +394,229 @@ impl std::fmt::Debug for btf_type__bindgen_ty_1 { .finish() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_btf_type_int() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Int(ty, nr_bits)) => { + assert_eq!(ty.name_off, 1); + assert_eq!(nr_bits, 64); + } + Ok(t) => panic!("expected int type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_ptr() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Ptr(_)) => {} + Ok(t) => panic!("expected ptr type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_array() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 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) } { + Ok(BtfType::Array(_, _)) => {} + Ok(t) => panic!("expected array type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_struct() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 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) } { + Ok(BtfType::Struct(_, _)) => {} + Ok(t) => panic!("expected struct type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_union() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 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) } { + Ok(BtfType::Union(_, _)) => {} + Ok(t) => panic!("expected union type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_enum() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 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) } { + Ok(BtfType::Enum(_, _)) => {} + Ok(t) => panic!("expected enum type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_fwd() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x0b, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Fwd(_)) => {} + Ok(t) => panic!("expected fwd type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_typedef() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Typedef(_)) => {} + Ok(t) => panic!("expected typedef type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_volatile() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Volatile(_)) => {} + Ok(t) => panic!("expected volatile type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_const() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Const(_)) => {} + Ok(t) => panic!("expected const type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_restrict() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Restrict(_)) => {} + Ok(t) => panic!("expected restrict type gpt {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_func() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x17, 0x8b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xe4, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Func(_)) => {} + Ok(t) => panic!("expected func type gpt {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_func_proto() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 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) } { + Ok(BtfType::FuncProto(_, _)) => {} + Ok(t) => panic!("expected func_proto type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_func_var() { + let endianness = Endianness::default(); + // NOTE: There was no data in /sys/kernell/btf/vmlinux for this type + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Var(_, _)) => {} + Ok(t) => panic!("expected var type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_func_datasec() { + let endianness = Endianness::default(); + // NOTE: There was no data in /sys/kernell/btf/vmlinux for this type + let data: &[u8] = &[ + 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) } { + Ok(BtfType::DataSec(_, _)) => {} + Ok(t) => panic!("expected datasec type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } + + #[test] + fn test_read_btf_type_float() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x78, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, + ]; + match unsafe { BtfType::read(data, endianness) } { + Ok(BtfType::Float(_)) => {} + Ok(t) => panic!("expected float type, got {:#?}", t), + Err(_) => panic!("unexpected error"), + } + } +}