aya: btf: add support for BTF_KIND_ENUM64

pull/453/head
Alessandro Decina 2 years ago
parent 4482db42d8
commit 9a6f8143a1

@ -406,12 +406,10 @@ fn match_candidate<'target>(
let target_ty = candidate.btf.type_by_id(target_id)?; let target_ty = candidate.btf.type_by_id(target_id)?;
// the first accessor is guaranteed to have a name by construction // the first accessor is guaranteed to have a name by construction
let local_variant_name = local_spec.accessors[0].name.as_ref().unwrap(); let local_variant_name = local_spec.accessors[0].name.as_ref().unwrap();
match target_ty { let match_enum =
BtfType::Enum(en) => { |name_offset, index, target_spec: &mut AccessSpec| -> Result<_, BtfError> {
for (index, member) in en.variants.iter().enumerate() { let target_variant_name = candidate.btf.string_at(name_offset)?;
let target_variant_name = candidate.btf.string_at(member.name_offset)?; if flavorless_name(local_variant_name) == flavorless_name(&target_variant_name)
if flavorless_name(local_variant_name)
== flavorless_name(&target_variant_name)
{ {
target_spec.parts.push(index); target_spec.parts.push(index);
target_spec.accessors.push(Accessor { target_spec.accessors.push(Accessor {
@ -419,6 +417,24 @@ fn match_candidate<'target>(
type_id: target_id, type_id: target_id,
name: None, name: None,
}); });
Ok(Some(()))
} else {
Ok(None)
}
};
match target_ty {
BtfType::Enum(en) => {
for (index, member) in en.variants.iter().enumerate() {
if let Ok(Some(_)) = match_enum(member.name_offset, index, &mut target_spec)
{
return Ok(Some(target_spec));
}
}
}
BtfType::Enum64(en) => {
for (index, member) in en.variants.iter().enumerate() {
if let Ok(Some(_)) = match_enum(member.name_offset, index, &mut target_spec)
{
return Ok(Some(target_spec)); return Ok(Some(target_spec));
} }
} }
@ -620,29 +636,39 @@ impl<'a> AccessSpec<'a> {
} }
} }
RelocationKind::EnumVariantExists | RelocationKind::EnumVariantValue => match ty { RelocationKind::EnumVariantExists | RelocationKind::EnumVariantValue => match ty {
BtfType::Enum(en) => { BtfType::Enum(_) | BtfType::Enum64(_) => {
if parts.len() != 1 { if parts.len() != 1 {
return Err(RelocationError::InvalidAccessString { return Err(RelocationError::InvalidAccessString {
access_str: spec.to_string(), access_str: spec.to_string(),
}); });
} }
let index = parts[0]; let index = parts[0];
if index >= en.variants.len() {
let (n_variants, name_offset) = match ty {
BtfType::Enum(en) => (
en.variants.len(),
en.variants.get(index).map(|v| v.name_offset),
),
BtfType::Enum64(en) => (
en.variants.len(),
en.variants.get(index).map(|v| v.name_offset),
),
_ => unreachable!(),
};
if name_offset.is_none() {
return Err(RelocationError::InvalidAccessIndex { return Err(RelocationError::InvalidAccessIndex {
type_name: btf.err_type_name(ty), type_name: btf.err_type_name(ty),
spec: spec.to_string(), spec: spec.to_string(),
index, index,
max_index: en.variants.len(), max_index: n_variants,
error: "tried to access nonexistant enum variant".to_string(), error: "tried to access nonexistant enum variant".to_string(),
}); });
} }
let accessors = vec![Accessor { let accessors = vec![Accessor {
type_id, type_id,
index, index,
name: Some( name: Some(btf.string_at(name_offset.unwrap())?.to_string()),
btf.string_at(en.variants.get(index).unwrap().name_offset)?
.to_string(),
),
}]; }];
AccessSpec { AccessSpec {
@ -946,6 +972,10 @@ impl ComputedRelocation {
value as u64 value as u64
} }
} }
BtfType::Enum64(en) => {
let variant = &en.variants[accessor.index];
(variant.value_high as u64) << 32 | variant.value_low as u64
}
// candidate selection ensures that rel_kind == local_kind == target_kind // candidate selection ensures that rel_kind == local_kind == target_kind
_ => unreachable!(), _ => unreachable!(),
} }
@ -1079,6 +1109,7 @@ impl ComputedRelocation {
} }
FieldSigned => match member_ty { FieldSigned => match member_ty {
BtfType::Enum(en) => value.value = en.is_signed() as u64, BtfType::Enum(en) => value.value = en.is_signed() as u64,
BtfType::Enum64(en) => value.value = en.is_signed() as u64,
BtfType::Int(i) => value.value = i.encoding() as u64 & IntEncoding::Signed as u64, BtfType::Int(i) => value.value = i.encoding() as u64 & IntEncoding::Signed as u64,
_ => (), _ => (),
}, },

@ -28,6 +28,7 @@ pub enum BtfType {
DataSec(DataSec), DataSec(DataSec),
DeclTag(DeclTag), DeclTag(DeclTag),
TypeTag(TypeTag), TypeTag(TypeTag),
Enum64(Enum64),
} }
#[repr(C)] #[repr(C)]
@ -438,6 +439,50 @@ impl Enum {
} }
} }
#[repr(C)]
#[derive(Debug, Clone)]
pub struct BtfEnum64 {
pub(crate) name_offset: u32,
pub(crate) value_low: u32,
pub(crate) value_high: u32,
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Enum64 {
pub(crate) name_offset: u32,
info: u32,
pub(crate) size: u32,
pub(crate) variants: Vec<BtfEnum64>,
}
impl Enum64 {
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut buf = vec![];
buf.extend(bytes_of::<u32>(&self.name_offset));
buf.extend(bytes_of::<u32>(&self.info));
buf.extend(bytes_of::<u32>(&self.size));
for v in &self.variants {
buf.extend(bytes_of::<u32>(&v.name_offset));
buf.extend(bytes_of::<u32>(&v.value_high));
buf.extend(bytes_of::<u32>(&v.value_low));
}
buf
}
pub(crate) fn kind(&self) -> BtfKind {
BtfKind::Enum64
}
pub(crate) fn type_info_size(&self) -> usize {
mem::size_of::<Fwd>() + mem::size_of::<BtfEnum64>() * self.variants.len()
}
pub(crate) fn is_signed(&self) -> bool {
self.info >> 31 == 1
}
}
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct BtfMember { pub(crate) struct BtfMember {
@ -826,6 +871,7 @@ pub enum BtfKind {
Float = 16, Float = 16,
DeclTag = 17, DeclTag = 17,
TypeTag = 18, TypeTag = 18,
Enum64 = 19,
} }
impl TryFrom<u32> for BtfKind { impl TryFrom<u32> for BtfKind {
@ -853,6 +899,7 @@ impl TryFrom<u32> for BtfKind {
16 => Float, 16 => Float,
17 => DeclTag, 17 => DeclTag,
18 => TypeTag, 18 => TypeTag,
19 => Enum64,
kind => return Err(BtfError::InvalidTypeKind { kind }), kind => return Err(BtfError::InvalidTypeKind { kind }),
}) })
} }
@ -880,6 +927,7 @@ impl Display for BtfKind {
BtfKind::DataSec => write!(f, "[DATASEC]"), BtfKind::DataSec => write!(f, "[DATASEC]"),
BtfKind::DeclTag => write!(f, "[DECL_TAG]"), BtfKind::DeclTag => write!(f, "[DECL_TAG]"),
BtfKind::TypeTag => write!(f, "[TYPE_TAG]"), BtfKind::TypeTag => write!(f, "[TYPE_TAG]"),
BtfKind::Enum64 => write!(f, "[ENUM64]"),
} }
} }
} }
@ -974,6 +1022,12 @@ impl BtfType {
size: ty[2], size: ty[2],
variants: unsafe { read_array::<BtfEnum>(data, vlen)? }, variants: unsafe { read_array::<BtfEnum>(data, vlen)? },
}), }),
BtfKind::Enum64 => BtfType::Enum64(Enum64 {
name_offset: ty[0],
info: ty[1],
size: ty[2],
variants: unsafe { read_array::<BtfEnum64>(data, vlen)? },
}),
BtfKind::Array => BtfType::Array(Array { BtfKind::Array => BtfType::Array(Array {
name_offset: ty[0], name_offset: ty[0],
info: ty[1], info: ty[1],
@ -1037,6 +1091,7 @@ impl BtfType {
BtfType::Int(t) => t.to_bytes(), BtfType::Int(t) => t.to_bytes(),
BtfType::Float(t) => t.to_bytes(), BtfType::Float(t) => t.to_bytes(),
BtfType::Enum(t) => t.to_bytes(), BtfType::Enum(t) => t.to_bytes(),
BtfType::Enum64(t) => t.to_bytes(),
BtfType::Array(t) => t.to_bytes(), BtfType::Array(t) => t.to_bytes(),
BtfType::Struct(t) => t.to_bytes(), BtfType::Struct(t) => t.to_bytes(),
BtfType::Union(t) => t.to_bytes(), BtfType::Union(t) => t.to_bytes(),
@ -1053,6 +1108,7 @@ impl BtfType {
BtfType::Int(t) => Some(t.size), BtfType::Int(t) => Some(t.size),
BtfType::Float(t) => Some(t.size), BtfType::Float(t) => Some(t.size),
BtfType::Enum(t) => Some(t.size), BtfType::Enum(t) => Some(t.size),
BtfType::Enum64(t) => Some(t.size),
BtfType::Struct(t) => Some(t.size), BtfType::Struct(t) => Some(t.size),
BtfType::Union(t) => Some(t.size), BtfType::Union(t) => Some(t.size),
BtfType::DataSec(t) => Some(t.size), BtfType::DataSec(t) => Some(t.size),
@ -1090,6 +1146,7 @@ impl BtfType {
BtfType::Int(t) => t.type_info_size(), BtfType::Int(t) => t.type_info_size(),
BtfType::Float(t) => t.type_info_size(), BtfType::Float(t) => t.type_info_size(),
BtfType::Enum(t) => t.type_info_size(), BtfType::Enum(t) => t.type_info_size(),
BtfType::Enum64(t) => t.type_info_size(),
BtfType::Array(t) => t.type_info_size(), BtfType::Array(t) => t.type_info_size(),
BtfType::Struct(t) => t.type_info_size(), BtfType::Struct(t) => t.type_info_size(),
BtfType::Union(t) => t.type_info_size(), BtfType::Union(t) => t.type_info_size(),
@ -1114,6 +1171,7 @@ impl BtfType {
BtfType::Int(t) => t.name_offset, BtfType::Int(t) => t.name_offset,
BtfType::Float(t) => t.name_offset, BtfType::Float(t) => t.name_offset,
BtfType::Enum(t) => t.name_offset, BtfType::Enum(t) => t.name_offset,
BtfType::Enum64(t) => t.name_offset,
BtfType::Array(t) => t.name_offset, BtfType::Array(t) => t.name_offset,
BtfType::Struct(t) => t.name_offset, BtfType::Struct(t) => t.name_offset,
BtfType::Union(t) => t.name_offset, BtfType::Union(t) => t.name_offset,
@ -1138,6 +1196,7 @@ impl BtfType {
BtfType::Int(t) => t.kind(), BtfType::Int(t) => t.kind(),
BtfType::Float(t) => t.kind(), BtfType::Float(t) => t.kind(),
BtfType::Enum(t) => t.kind(), BtfType::Enum(t) => t.kind(),
BtfType::Enum64(t) => t.kind(),
BtfType::Array(t) => t.kind(), BtfType::Array(t) => t.kind(),
BtfType::Struct(t) => t.kind(), BtfType::Struct(t) => t.kind(),
BtfType::Union(t) => t.kind(), BtfType::Union(t) => t.kind(),
@ -1176,6 +1235,17 @@ impl BtfType {
_ => None, _ => None,
} }
} }
pub(crate) fn is_compatible(&self, other: &BtfType) -> bool {
if self.kind() == other.kind() {
return true;
}
matches!(
(self.kind(), other.kind()),
(BtfKind::Enum, BtfKind::Enum64) | (BtfKind::Enum64, BtfKind::Enum)
)
}
} }
fn type_kind(info: u32) -> Result<BtfKind, BtfError> { fn type_kind(info: u32) -> Result<BtfKind, BtfError> {
@ -1197,7 +1267,7 @@ pub(crate) fn types_are_compatible(
let local_ty = local_btf.type_by_id(local_id)?; let local_ty = local_btf.type_by_id(local_id)?;
let target_ty = target_btf.type_by_id(target_id)?; let target_ty = target_btf.type_by_id(target_id)?;
if local_ty.kind() != target_ty.kind() { if !local_ty.is_compatible(target_ty) {
return Ok(false); return Ok(false);
} }
@ -1207,7 +1277,7 @@ pub(crate) fn types_are_compatible(
let local_ty = local_btf.type_by_id(local_id)?; let local_ty = local_btf.type_by_id(local_id)?;
let target_ty = target_btf.type_by_id(target_id)?; let target_ty = target_btf.type_by_id(target_id)?;
if local_ty.kind() != target_ty.kind() { if !local_ty.is_compatible(target_ty) {
return Ok(false); return Ok(false);
} }
@ -1216,6 +1286,7 @@ pub(crate) fn types_are_compatible(
| BtfType::Struct(_) | BtfType::Struct(_)
| BtfType::Union(_) | BtfType::Union(_)
| BtfType::Enum(_) | BtfType::Enum(_)
| BtfType::Enum64(_)
| BtfType::Fwd(_) | BtfType::Fwd(_)
| BtfType::Float(_) => return Ok(true), | BtfType::Float(_) => return Ok(true),
BtfType::Int(local) => { BtfType::Int(local) => {
@ -1279,12 +1350,12 @@ pub(crate) fn fields_are_compatible(
return Ok(true); return Ok(true);
} }
if local_ty.kind() != target_ty.kind() { if !local_ty.is_compatible(target_ty) {
return Ok(false); return Ok(false);
} }
match local_ty { match local_ty {
BtfType::Fwd(_) | BtfType::Enum(_) => { BtfType::Fwd(_) | BtfType::Enum(_) | BtfType::Enum64(_) => {
let flavorless_name = let flavorless_name =
|name: &str| name.split_once("___").map_or(name, |x| x.0).to_string(); |name: &str| name.split_once("___").map_or(name, |x| x.0).to_string();

@ -80,6 +80,46 @@ fn relocate_enum_signed() {
assert_eq!(test.run_no_btf().unwrap() as i64, -0x7AAAAAAAi64); assert_eq!(test.run_no_btf().unwrap() as i64, -0x7AAAAAAAi64);
} }
#[integration_test]
fn relocate_enum64() {
let test = RelocationTest {
local_definition: r#"
enum foo { D = 0xAAAAAAAABBBBBBBB };
"#,
target_btf: r#"
enum foo { D = 0xCCCCCCCCDDDDDDDD } 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(), 0xCCCCCCCCDDDDDDDD);
assert_eq!(test.run_no_btf().unwrap(), 0xAAAAAAAABBBBBBBB);
}
#[integration_test]
fn relocate_enum64_signed() {
let test = RelocationTest {
local_definition: r#"
enum foo { D = -0xAAAAAAABBBBBBBB };
"#,
target_btf: r#"
enum foo { D = -0xCCCCCCCDDDDDDDD } 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() as i64, -0xCCCCCCCDDDDDDDDi64);
assert_eq!(test.run_no_btf().unwrap() as i64, -0xAAAAAAABBBBBBBBi64);
}
#[integration_test] #[integration_test]
fn relocate_pointer() { fn relocate_pointer() {
let test = RelocationTest { let test = RelocationTest {

Loading…
Cancel
Save