aya: Fix BTF type resolution for Arrays and Ints

The union of `size` and `type` is unused in BTF_KIND_ARRAY.
Type information of elements is in the btf_array struct that follows in
the type_ field while the index type is in the index_type field.

For BTF_KIND_INT, only the offset should be compared and size and
signedness should be ignored.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/169/head
Dave Tucker 3 years ago
parent 01187735f0
commit 686ce45f93

@ -138,7 +138,7 @@ impl Btf {
str_len: 0x00, str_len: 0x00,
}, },
strings: vec![0], strings: vec![0],
types: vec![], types: vec![BtfType::Unknown],
_endianness: Endianness::default(), _endianness: Endianness::default(),
} }
} }
@ -153,10 +153,11 @@ impl Btf {
pub(crate) fn add_type(&mut self, type_: BtfType) -> u32 { pub(crate) fn add_type(&mut self, type_: BtfType) -> u32 {
let size = type_.type_info_size() as u32; let size = type_.type_info_size() as u32;
let type_id = self.types.len();
self.types.push(type_); self.types.push(type_);
self.header.type_len += size; self.header.type_len += size;
self.header.str_off += size; self.header.str_off += size;
self.types.len() as u32 type_id as u32
} }
/// Loads BTF metadata from `/sys/kernel/btf/vmlinux`. /// Loads BTF metadata from `/sys/kernel/btf/vmlinux`.
@ -364,7 +365,8 @@ impl Btf {
pub(crate) fn to_bytes(&self) -> Vec<u8> { pub(crate) fn to_bytes(&self) -> Vec<u8> {
// Safety: btf_header is POD // Safety: btf_header is POD
let mut buf = unsafe { bytes_of::<btf_header>(&self.header).to_vec() }; let mut buf = unsafe { bytes_of::<btf_header>(&self.header).to_vec() };
for t in self.types() { // Skip the first type since it's always BtfType::Unknown for type_by_id to work
for t in self.types().skip(1) {
let b = t.to_bytes(); let b = t.to_bytes();
buf.put(b.as_slice()) buf.put(b.as_slice())
} }

@ -394,6 +394,20 @@ impl BtfType {
btf_type.__bindgen_anon_1.type_ = type_; btf_type.__bindgen_anon_1.type_ = type_;
BtfType::Typedef(btf_type) BtfType::Typedef(btf_type)
} }
#[cfg(test)]
pub(crate) fn new_array(name_off: u32, type_: u32, index_type: u32, nelems: u32) -> BtfType {
let info = (BTF_KIND_ARRAY) << 24;
let mut btf_type = unsafe { std::mem::zeroed::<btf_type>() };
btf_type.name_off = name_off;
btf_type.info = info;
let btf_array = btf_array {
type_,
index_type,
nelems,
};
BtfType::Array(btf_type, btf_array)
}
} }
fn type_kind(ty: &btf_type) -> Result<BtfKind, BtfError> { fn type_kind(ty: &btf_type) -> Result<BtfKind, BtfError> {
@ -453,8 +467,10 @@ pub(crate) fn types_are_compatible(
return Ok(true) return Ok(true)
} }
Int(_, local_off) => { Int(_, local_off) => {
let local_off = (local_off >> 16) & 0xFF;
if let Int(_, target_off) = target_ty { if let Int(_, target_off) = target_ty {
return Ok(*local_off == 0 && *target_off == 0); let target_off = (target_off >> 16) & 0xFF;
return Ok(local_off == 0 && target_off == 0);
} }
} }
Ptr(l_ty) => { Ptr(l_ty) => {
@ -467,13 +483,10 @@ pub(crate) fn types_are_compatible(
continue; continue;
} }
} }
Array(l_ty, _) => { Array(_, l_ty) => {
if let Array(t_ty, _) = target_ty { if let Array(_, t_ty) = target_ty {
// Safety: union local_id = l_ty.type_;
unsafe { target_id = t_ty.type_;
local_id = l_ty.__bindgen_anon_1.type_;
target_id = t_ty.__bindgen_anon_1.type_;
}
continue; continue;
} }
} }
@ -546,13 +559,11 @@ pub(crate) fn fields_are_compatible(
} }
Float(_) => return Ok(true), Float(_) => return Ok(true),
Ptr(_) => return Ok(true), Ptr(_) => return Ok(true),
Array(l_ty, _) => { Array(_, l_ty) => {
if let Array(t_ty, _) = target_ty { if let Array(_, t_ty) = target_ty {
// Safety: union local_id = l_ty.type_;
unsafe { target_id = t_ty.type_;
local_id = l_ty.__bindgen_anon_1.type_;
target_id = t_ty.__bindgen_anon_1.type_;
}
continue; continue;
} }
} }
@ -918,4 +929,20 @@ mod tests {
Err(_) => panic!("unexpected error"), Err(_) => panic!("unexpected error"),
} }
} }
#[test]
fn test_types_are_compatible() {
let mut btf = Btf::new();
let name_offset = btf.add_string("u32".to_string());
let u32t = btf.add_type(BtfType::new_int(name_offset, 4, 0, 0));
let name_offset = btf.add_string("u64".to_string());
let u64t = btf.add_type(BtfType::new_int(name_offset, 8, 0, 0));
let name_offset = btf.add_string("widgets".to_string());
let array_type = btf.add_type(BtfType::new_array(name_offset, u64t, u32t, 16));
assert!(types_are_compatible(&btf, u32t, &btf, u32t).unwrap());
// int types are compatible if offsets match. size and encoding aren't compared
assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap());
assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap());
}
} }

Loading…
Cancel
Save