|
|
@@ -13,8 +13,8 @@ use object::SectionIndex;
|
|
|
use crate::{
|
|
|
Function, Object,
|
|
|
btf::{
|
|
|
- Array, Btf, BtfError, BtfMember, BtfType, IntEncoding, MAX_SPEC_LEN, Struct, Union,
|
|
|
- fields_are_compatible, types_are_compatible,
|
|
|
+ Array, Btf, BtfError, BtfKind, BtfMember, BtfType, IntEncoding, MAX_SPEC_LEN, Struct,
|
|
|
+ Union, fields_are_compatible, types_are_compatible,
|
|
|
},
|
|
|
generated::{
|
|
|
BPF_ALU, BPF_ALU64, BPF_B, BPF_CALL, BPF_DW, BPF_H, BPF_JMP, BPF_K, BPF_LD, BPF_LDX,
|
|
|
@@ -409,10 +409,26 @@ fn find_candidates<'target>(
|
|
|
) -> Result<Vec<Candidate<'target>>, BtfError> {
|
|
|
let mut candidates = Vec::new();
|
|
|
let local_name = flavorless_name(local_name);
|
|
|
- for (type_id, ty) in target_btf.types().enumerate() {
|
|
|
- if local_ty.kind() != ty.kind() {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ let local_kind = local_ty.kind();
|
|
|
+
|
|
|
+ // When we downgrade an ENUM64 to a UNION we still want to match the enum
|
|
|
+ // definition recorded in the target BTF. If the sanitized type has a
|
|
|
+ // fallback, allow ENUM64 candidates through the kind check.
|
|
|
+ //
|
|
|
+ // Note that we do not sanitize the target BTF so the kinds will not
|
|
|
+ // naturally match!
|
|
|
+ let allow_enum_match = matches!(
|
|
|
+ local_ty,
|
|
|
+ BtfType::Union(Union {
|
|
|
+ enum64_fallback: Some(_),
|
|
|
+ ..
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ for (type_id, ty) in target_btf.types().enumerate().filter(|(_, ty)| {
|
|
|
+ let candidate_kind = ty.kind();
|
|
|
+ candidate_kind == local_kind || (allow_enum_match && candidate_kind == BtfKind::Enum64)
|
|
|
+ }) {
|
|
|
let name = &*target_btf.type_name(ty)?;
|
|
|
if local_name != flavorless_name(name) {
|
|
|
continue;
|
|
|
@@ -488,6 +504,14 @@ fn match_candidate<'target>(
|
|
|
BtfType::Enum64(en) => {
|
|
|
match_enum(&mut en.variants.iter().map(|member| member.name_offset))
|
|
|
}
|
|
|
+ BtfType::Union(Union {
|
|
|
+ enum64_fallback: Some(fallback),
|
|
|
+ ..
|
|
|
+ }) => {
|
|
|
+ // Local ENUM64 types become UNIONs during sanitisation; the fallback retains
|
|
|
+ // their original variant names so we can line them up with target enums.
|
|
|
+ match_enum(&mut fallback.variants.iter().map(|variant| variant.name_offset))
|
|
|
+ }
|
|
|
_ => Ok(None),
|
|
|
}
|
|
|
}
|
|
|
@@ -708,6 +732,17 @@ impl<'a> AccessSpec<'a> {
|
|
|
index,
|
|
|
)
|
|
|
}
|
|
|
+ BtfType::Union(Union {
|
|
|
+ enum64_fallback: Some(fallback),
|
|
|
+ ..
|
|
|
+ }) => {
|
|
|
+ let index = index()?;
|
|
|
+ (
|
|
|
+ fallback.variants.len(),
|
|
|
+ fallback.variants.get(index).map(|v| v.name_offset),
|
|
|
+ index,
|
|
|
+ )
|
|
|
+ }
|
|
|
_ => {
|
|
|
return Err(RelocationError::InvalidRelocationKindForType {
|
|
|
relocation_number: relocation.number,
|
|
|
@@ -861,7 +896,7 @@ struct ComputedRelocation {
|
|
|
target: Option<ComputedRelocationValue>,
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug)]
|
|
|
+#[derive(Clone, Copy, Debug)]
|
|
|
struct ComputedRelocationValue {
|
|
|
value: u64,
|
|
|
size: u32,
|
|
|
@@ -1059,6 +1094,17 @@ impl ComputedRelocation {
|
|
|
let variant = &en.variants[accessor.index];
|
|
|
(u64::from(variant.value_high) << 32) | u64::from(variant.value_low)
|
|
|
}
|
|
|
+ BtfType::Union(Union {
|
|
|
+ enum64_fallback: Some(fallback),
|
|
|
+ ..
|
|
|
+ }) => {
|
|
|
+ let variant = &fallback.variants[accessor.index];
|
|
|
+ if fallback.signed {
|
|
|
+ (variant.value as i64) as u64
|
|
|
+ } else {
|
|
|
+ variant.value
|
|
|
+ }
|
|
|
+ }
|
|
|
// candidate selection ensures that rel_kind == local_kind == target_kind
|
|
|
_ => unreachable!(),
|
|
|
}
|