4
0
Эх сурвалжийг харах

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 <dave@dtucker.co.uk>
Dave Tucker 3 жил өмнө
parent
commit
686ce45f93

+ 5 - 3
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<u8> {
         // Safety: btf_header is POD
         let mut buf = unsafe { bytes_of::<btf_header>(&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())
         }

+ 42 - 15
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>() };
+        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<BtfKind, BtfError> {
@@ -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());
+    }
 }