Browse Source

aya: btf: fix relocations for signed enums (32 bits)

Enums now carry a signed bit in the info flags. Take it into account
when applying enum relocations.
Alessandro Decina 2 years ago
parent
commit
4482db4

+ 3 - 3
aya-obj/src/btf/btf.rs

@@ -529,7 +529,7 @@ impl Btf {
                         .iter()
                         .map(|p| BtfEnum {
                             name_offset: p.name_offset,
-                            value: p.btf_type as i32,
+                            value: p.btf_type,
                         })
                         .collect();
                     let enum_type = BtfType::Enum(Enum::new(ty.name_offset, members));
@@ -1246,9 +1246,9 @@ mod tests {
             assert!(fixed.name_offset == 0);
             assert!(fixed.variants.len() == 2);
             assert!(btf.string_at(fixed.variants[0].name_offset).unwrap() == "a");
-            assert!(fixed.variants[0].value == int_type_id as i32);
+            assert!(fixed.variants[0].value == int_type_id);
             assert!(btf.string_at(fixed.variants[1].name_offset).unwrap() == "b");
-            assert!(fixed.variants[1].value == int_type_id as i32);
+            assert!(fixed.variants[1].value == int_type_id);
         } else {
             panic!("not an emum")
         }

+ 9 - 2
aya-obj/src/btf/relocation.rs

@@ -938,7 +938,14 @@ impl ComputedRelocation {
             (EnumVariantValue, Some(spec)) => {
                 let accessor = &spec.accessors[0];
                 match spec.btf.type_by_id(accessor.type_id)? {
-                    BtfType::Enum(en) => en.variants[accessor.index].value as u64,
+                    BtfType::Enum(en) => {
+                        let value = en.variants[accessor.index].value;
+                        if en.is_signed() {
+                            value as i32 as u64
+                        } else {
+                            value as u64
+                        }
+                    }
                     // candidate selection ensures that rel_kind == local_kind == target_kind
                     _ => unreachable!(),
                 }
@@ -1071,7 +1078,7 @@ impl ComputedRelocation {
                 value.value = byte_size as u64;
             }
             FieldSigned => match member_ty {
-                BtfType::Enum(_) => value.value = 1,
+                BtfType::Enum(en) => value.value = en.is_signed() as u64,
                 BtfType::Int(i) => value.value = i.encoding() as u64 & IntEncoding::Signed as u64,
                 _ => (),
             },

+ 6 - 2
aya-obj/src/btf/types.rs

@@ -389,7 +389,7 @@ impl Int {
 #[derive(Debug, Clone)]
 pub(crate) struct BtfEnum {
     pub(crate) name_offset: u32,
-    pub(crate) value: i32,
+    pub(crate) value: u32,
 }
 
 #[repr(C)]
@@ -409,7 +409,7 @@ impl Enum {
         buf.extend(bytes_of::<u32>(&self.size));
         for v in &self.variants {
             buf.extend(bytes_of::<u32>(&v.name_offset));
-            buf.extend(bytes_of::<i32>(&v.value));
+            buf.extend(bytes_of::<u32>(&v.value));
         }
         buf
     }
@@ -432,6 +432,10 @@ impl Enum {
             variants,
         }
     }
+
+    pub(crate) fn is_signed(&self) -> bool {
+        self.info >> 31 == 1
+    }
 }
 
 #[repr(C)]

+ 27 - 4
test/integration-test/src/tests/relocations.rs

@@ -6,6 +6,9 @@ use aya::{maps::Array, programs::TracePoint, BpfLoader, Btf, Endianness};
 
 use super::{integration_test, IntegrationTest};
 
+// In the tests below we often use values like 0xAAAAAAAA or -0x7AAAAAAA. Those values have no
+// special meaning, they just have "nice" bit patterns that can be helpful while debugging.
+
 #[integration_test]
 fn relocate_field() {
     let test = RelocationTest {
@@ -41,10 +44,30 @@ fn relocate_field() {
 fn relocate_enum() {
     let test = RelocationTest {
         local_definition: r#"
-            enum foo { D = 1 };
+            enum foo { D = 0xAAAAAAAA };
+        "#,
+        target_btf: r#"
+            enum foo { D = 0xBBBBBBBB } e1;
+        "#,
+        relocation_code: r#"
+            #define BPF_ENUMVAL_VALUE 1
+            value = __builtin_preserve_enum_value(*(typeof(enum foo) *)D, BPF_ENUMVAL_VALUE);
+        "#,
+    }
+    .build()
+    .unwrap();
+    assert_eq!(test.run().unwrap(), 0xBBBBBBBB);
+    assert_eq!(test.run_no_btf().unwrap(), 0xAAAAAAAA);
+}
+
+#[integration_test]
+fn relocate_enum_signed() {
+    let test = RelocationTest {
+        local_definition: r#"
+            enum foo { D = -0x7AAAAAAA };
         "#,
         target_btf: r#"
-            enum foo { D = 4 } e1;
+            enum foo { D = -0x7BBBBBBB } e1;
         "#,
         relocation_code: r#"
             #define BPF_ENUMVAL_VALUE 1
@@ -53,8 +76,8 @@ fn relocate_enum() {
     }
     .build()
     .unwrap();
-    assert_eq!(test.run().unwrap(), 4);
-    assert_eq!(test.run_no_btf().unwrap(), 1);
+    assert_eq!(test.run().unwrap() as i64, -0x7BBBBBBBi64);
+    assert_eq!(test.run_no_btf().unwrap() as i64, -0x7AAAAAAAi64);
 }
 
 #[integration_test]