From 686ce45f930cef68f6fdfb73dc5ebc2d259d5954 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Sat, 15 Jan 2022 13:25:30 +0000 Subject: [PATCH] aya: Fix BTF type resolution for Arrays and Ints The union of `size` and `type` is unused in BTF_KIND_ARRAY. Type information of elements is in the btf_array struct that follows in the type_ field while the index type is in the index_type field. For BTF_KIND_INT, only the offset should be compared and size and signedness should be ignored. Signed-off-by: Dave Tucker --- aya/src/obj/btf/btf.rs | 8 +++--- aya/src/obj/btf/types.rs | 57 +++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index 3eced682..1f694b81 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -138,7 +138,7 @@ impl Btf { str_len: 0x00, }, strings: vec![0], - types: vec![], + types: vec![BtfType::Unknown], _endianness: Endianness::default(), } } @@ -153,10 +153,11 @@ impl Btf { pub(crate) fn add_type(&mut self, type_: BtfType) -> u32 { let size = type_.type_info_size() as u32; + let type_id = self.types.len(); self.types.push(type_); self.header.type_len += size; self.header.str_off += size; - self.types.len() as u32 + type_id as u32 } /// Loads BTF metadata from `/sys/kernel/btf/vmlinux`. @@ -364,7 +365,8 @@ impl Btf { pub(crate) fn to_bytes(&self) -> Vec { // Safety: btf_header is POD let mut buf = unsafe { bytes_of::(&self.header).to_vec() }; - for t in self.types() { + // Skip the first type since it's always BtfType::Unknown for type_by_id to work + for t in self.types().skip(1) { let b = t.to_bytes(); buf.put(b.as_slice()) } diff --git a/aya/src/obj/btf/types.rs b/aya/src/obj/btf/types.rs index 86e711df..b046d5e3 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya/src/obj/btf/types.rs @@ -394,6 +394,20 @@ impl BtfType { btf_type.__bindgen_anon_1.type_ = type_; BtfType::Typedef(btf_type) } + + #[cfg(test)] + pub(crate) fn new_array(name_off: u32, type_: u32, index_type: u32, nelems: u32) -> BtfType { + let info = (BTF_KIND_ARRAY) << 24; + let mut btf_type = unsafe { std::mem::zeroed::() }; + btf_type.name_off = name_off; + btf_type.info = info; + let btf_array = btf_array { + type_, + index_type, + nelems, + }; + BtfType::Array(btf_type, btf_array) + } } fn type_kind(ty: &btf_type) -> Result { @@ -453,8 +467,10 @@ pub(crate) fn types_are_compatible( return Ok(true) } Int(_, local_off) => { + let local_off = (local_off >> 16) & 0xFF; if let Int(_, target_off) = target_ty { - return Ok(*local_off == 0 && *target_off == 0); + let target_off = (target_off >> 16) & 0xFF; + return Ok(local_off == 0 && target_off == 0); } } Ptr(l_ty) => { @@ -467,13 +483,10 @@ pub(crate) fn types_are_compatible( continue; } } - Array(l_ty, _) => { - if let Array(t_ty, _) = target_ty { - // Safety: union - unsafe { - local_id = l_ty.__bindgen_anon_1.type_; - target_id = t_ty.__bindgen_anon_1.type_; - } + Array(_, l_ty) => { + if let Array(_, t_ty) = target_ty { + local_id = l_ty.type_; + target_id = t_ty.type_; continue; } } @@ -546,13 +559,11 @@ pub(crate) fn fields_are_compatible( } Float(_) => return Ok(true), Ptr(_) => return Ok(true), - Array(l_ty, _) => { - if let Array(t_ty, _) = target_ty { - // Safety: union - unsafe { - local_id = l_ty.__bindgen_anon_1.type_; - target_id = t_ty.__bindgen_anon_1.type_; - } + Array(_, l_ty) => { + if let Array(_, t_ty) = target_ty { + local_id = l_ty.type_; + target_id = t_ty.type_; + continue; } } @@ -918,4 +929,20 @@ mod tests { Err(_) => panic!("unexpected error"), } } + + #[test] + fn test_types_are_compatible() { + let mut btf = Btf::new(); + let name_offset = btf.add_string("u32".to_string()); + let u32t = btf.add_type(BtfType::new_int(name_offset, 4, 0, 0)); + let name_offset = btf.add_string("u64".to_string()); + let u64t = btf.add_type(BtfType::new_int(name_offset, 8, 0, 0)); + let name_offset = btf.add_string("widgets".to_string()); + let array_type = btf.add_type(BtfType::new_array(name_offset, u64t, u32t, 16)); + + assert!(types_are_compatible(&btf, u32t, &btf, u32t).unwrap()); + // int types are compatible if offsets match. size and encoding aren't compared + assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap()); + assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap()); + } }