aya-obj: Handle lack of match of enum variants correctly

When comparing `local_spec` with `target_spec` for enum relocations,
we can encounter a sitiation when a matchinng variant in a candidate
spec doesn't exist.

Before this change, such case wasn't handled explicitly, therefore
resulted in returning currently constructed `target_spec` at the
end. The problem is that such `target_spec` was, due to lack of
match, incomplete. It didn't contain any `accessors` nor `parts`.

Later usage of such incomplete `target_spec` was leading to panics,
since the code operating on enums' `target_spec` expects at least
one `accessor` to be available.

Fixes: #868
reviewable/pr874/r1
Michal Rostecki 1 year ago
parent fd2fb98792
commit 4c536c8d36

@ -484,6 +484,7 @@ fn match_candidate<'target>(
return Ok(Some(target_spec));
}
}
return Ok(None);
}
BtfType::Enum64(en) => {
for (index, member) in en.variants.iter().enumerate() {
@ -492,8 +493,11 @@ fn match_candidate<'target>(
return Ok(Some(target_spec));
}
}
return Ok(None);
}
_ => {
return Ok(None);
}
_ => return Ok(None),
}
}
RelocationKind::FieldByteOffset

@ -90,6 +90,38 @@ SEC("uprobe") int enum_unsigned_32(void *ctx) {
return enum_unsigned_32_global();
}
enum relocated_enum_unsigned_32_checked_variants {
#ifndef TARGET
U32_VAL_A = 0xAAAAAAAA,
#endif
U32_VAL_B = 0xBBBBBBBB,
#ifdef TARGET
U32_VAL_C = 0xCCCCCCCC
#endif
};
__noinline int enum_unsigned_32_checked_variants_global() {
#ifndef TARGET
if (bpf_core_enum_value_exists(
enum relocated_enum_unsigned_32_checked_variants, U32_VAL_A)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_32_checked_variants, U32_VAL_A));
#else
if (bpf_core_enum_value_exists(
enum relocated_enum_unsigned_32_checked_variants, U32_VAL_C)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_32_checked_variants, U32_VAL_C));
#endif
} else {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_32_checked_variants, U32_VAL_B));
}
}
SEC("uprobe") int enum_unsigned_32_checked_variants(void *ctx) {
return enum_unsigned_32_checked_variants_global();
}
enum relocated_enum_signed_32 {
S32_VAL =
#ifndef TARGET
@ -106,6 +138,38 @@ __noinline int enum_signed_32_global() {
SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); }
enum relocated_enum_signed_32_checked_variants {
#ifndef TARGET
S32_VAL_A = -0x7AAAAAAA,
#endif
S32_VAL_B = -0x7BBBBBBB,
#ifdef TARGET
S32_VAL_C = -0x7CCCCCCC
#endif
};
__noinline int enum_signed_32_checked_variants_global() {
#ifndef TARGET
if (bpf_core_enum_value_exists(enum relocated_enum_signed_32_checked_variants,
S32_VAL_A)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_32_checked_variants, S32_VAL_A));
#else
if (bpf_core_enum_value_exists(enum relocated_enum_signed_32_checked_variants,
S32_VAL_C)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_32_checked_variants, S32_VAL_C));
#endif
} else {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_32_checked_variants, S32_VAL_B));
}
}
SEC("uprobe") int enum_signed_32_checked_variants(void *ctx) {
return enum_signed_32_checked_variants_global();
}
enum relocated_enum_unsigned_64 {
U64_VAL =
#ifndef TARGET
@ -124,6 +188,38 @@ SEC("uprobe") int enum_unsigned_64(void *ctx) {
return enum_unsigned_64_global();
}
enum relocated_enum_unsigned_64_checked_variants {
#ifndef TARGET
U64_VAL_A = 0xAAAAAAAABBBBBBBB,
#endif
U64_VAL_B = 0xCCCCCCCCDDDDDDDD,
#ifdef TARGET
U64_VAL_C = 0xEEEEEEEEFFFFFFFF
#endif
};
__noinline int enum_unsigned_64_checked_variants_global() {
#ifndef TARGET
if (bpf_core_enum_value_exists(
enum relocated_enum_unsigned_64_checked_variants, U64_VAL_A)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_64_checked_variants, U64_VAL_A));
#else
if (bpf_core_enum_value_exists(
enum relocated_enum_unsigned_64_checked_variants, U64_VAL_C)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_64_checked_variants, U64_VAL_C));
#endif
} else {
return set_output(bpf_core_enum_value(
enum relocated_enum_unsigned_64_checked_variants, U64_VAL_B));
}
}
SEC("uprobe") int enum_unsigned_64_checked_variants(void *ctx) {
return enum_unsigned_64_checked_variants_global();
}
enum relocated_enum_signed_64 {
S64_VAL =
#ifndef TARGET
@ -139,3 +235,35 @@ __noinline int enum_signed_64_global() {
}
SEC("uprobe") int enum_signed_64(void *ctx) { return enum_signed_64_global(); }
enum relocated_enum_signed_64_checked_variants {
#ifndef TARGET
S64_VAL_A = -0xAAAAAAABBBBBBB,
#endif
S64_VAL_B = -0xCCCCCCCDDDDDDD,
#ifdef TARGET
S64_VAL_C = -0xEEEEEEEFFFFFFF
#endif
};
__noinline int enum_signed_64_checked_variants_global() {
#ifndef TARGET
if (bpf_core_enum_value_exists(enum relocated_enum_signed_64_checked_variants,
S64_VAL_A)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_64_checked_variants, S64_VAL_A));
#else
if (bpf_core_enum_value_exists(enum relocated_enum_signed_64_checked_variants,
S64_VAL_C)) {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_64_checked_variants, S64_VAL_C));
#endif
} else {
return set_output(bpf_core_enum_value(
enum relocated_enum_signed_64_checked_variants, S64_VAL_B));
}
}
SEC("uprobe") int enum_signed_64_checked_variants(void *ctx) {
return enum_signed_64_checked_variants_global();
}

@ -3,12 +3,20 @@ use test_case::test_case;
#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)]
#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)]
#[test_case("enum_signed_32_checked_variants", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)]
#[test_case("enum_signed_32_checked_variants", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)]
#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)]
#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)]
#[test_case("enum_signed_64_checked_variants", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBi64 as u64)]
#[test_case("enum_signed_64_checked_variants", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDi64 as u64)]
#[test_case("enum_unsigned_32", false, None, 0xAAAAAAAA)]
#[test_case("enum_unsigned_32", true, None, 0xBBBBBBBB)]
#[test_case("enum_unsigned_32_checked_variants", false, None, 0xAAAAAAAA)]
#[test_case("enum_unsigned_32_checked_variants", true, None, 0xBBBBBBBB)]
#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)]
#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)]
#[test_case("enum_unsigned_64_checked_variants", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)]
#[test_case("enum_unsigned_64_checked_variants", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)]
#[test_case("field", false, None, 2)]
#[test_case("field", true, None, 1)]
#[test_case("pointer", false, None, 42)]

Loading…
Cancel
Save