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.
pull/501/head
Alessandro Decina 2 years ago
parent d6b976c6f1
commit 4482db42d8

@ -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")
}

@ -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,
_ => (),
},

@ -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)]

@ -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]

Loading…
Cancel
Save