diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index 1e212fb9..3290a817 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -1,7 +1,8 @@ use std::{ borrow::Cow, collections::HashMap, - ffi::{c_void, CStr, CString}, + convert::TryInto, + ffi::{CStr, CString}, fs, io, mem, path::{Path, PathBuf}, ptr, @@ -14,17 +15,17 @@ use object::Endianness; use thiserror::Error; use crate::{ - generated::{btf_enum, btf_ext_header, btf_func_linkage, btf_header, btf_member}, - obj::btf::{relocation::Relocation, BtfKind, BtfType}, + generated::{btf_ext_header, btf_header}, + obj::btf::{ + info::{FuncSecInfo, LineSecInfo}, + relocation::Relocation, + Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int, + IntEncoding, LineInfo, Struct, Typedef, VarLinkage, + }, util::bytes_of, Features, }; -use super::{ - info::{FuncSecInfo, LineSecInfo}, - type_vlen, FuncInfo, LineInfo, -}; - pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; pub(crate) const MAX_SPEC_LEN: usize = 64; @@ -198,16 +199,16 @@ impl Btf { pub(crate) fn add_string(&mut self, name: String) -> u32 { let str = CString::new(name).unwrap(); - let name_off = self.strings.len(); + let name_offset = self.strings.len(); self.strings.extend(str.as_c_str().to_bytes_with_nul()); self.header.str_len = self.strings.len() as u32; - name_off as u32 + name_offset as u32 } - pub(crate) fn add_type(&mut self, type_: BtfType) -> u32 { - let size = type_.type_info_size() as u32; + pub(crate) fn add_type(&mut self, btf_type: BtfType) -> u32 { + let size = btf_type.type_info_size() as u32; let type_id = self.types.len(); - self.types.push(type_); + self.types.push(btf_type); self.header.type_len += size; self.header.str_off += size; type_id as u32 @@ -315,35 +316,23 @@ impl Btf { self.types.resolve_type(root_type_id) } - pub(crate) fn type_name(&self, ty: &BtfType) -> Result>, BtfError> { - ty.name_offset().map(|off| self.string_at(off)).transpose() + pub(crate) fn type_name(&self, ty: &BtfType) -> Result, BtfError> { + self.string_at(ty.name_offset()) } pub(crate) fn err_type_name(&self, ty: &BtfType) -> Option { - ty.name_offset() - .and_then(|off| self.string_at(off).ok().map(String::from)) + self.string_at(ty.name_offset()).ok().map(String::from) } pub(crate) fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result { for (type_id, ty) in self.types().enumerate() { - match ty.kind()? { - Some(k) => { - if k != kind { - continue; - } - } - None => continue, + if ty.kind() != kind { + continue; } - - match self.type_name(ty)? { - Some(ty_name) => { - if ty_name == name { - return Ok(type_id as u32); - } - continue; - } - None => continue, + if self.type_name(ty)? == name { + return Ok(type_id as u32); } + continue; } Err(BtfError::UnknownBtfTypeName { @@ -356,41 +345,24 @@ impl Btf { let mut n_elems = 1; for _ in 0..MAX_RESOLVE_DEPTH { let ty = self.types.type_by_id(type_id)?; - - use BtfType::*; let size = match ty { - Int(ty, _) - | Struct(ty, _) - | Union(ty, _) - | Enum(ty, _) - | DataSec(ty, _) - | Float(ty) => { - // Safety: union - unsafe { ty.__bindgen_anon_1.size as usize } - } - Ptr(_) => mem::size_of::<*const c_void>(), // FIXME - Typedef(ty) - | Volatile(ty) - | Const(ty) - | Restrict(ty) - | Var(ty, _) - | DeclTag(ty, _) - | TypeTag(ty) => { - // Safety: union - type_id = unsafe { ty.__bindgen_anon_1.type_ }; + BtfType::Array(Array { array, .. }) => { + n_elems = array.len; + type_id = array.element_type; continue; } - Array(_, array) => { - n_elems *= array.nelems as usize; - type_id = array.type_; - continue; - } - Unknown | Fwd(_) | Func(_) | FuncProto(_, _) => { - return Err(BtfError::UnexpectedBtfType { type_id }) + other => { + if let Some(size) = other.size() { + size + } else if let Some(next) = other.btf_type() { + type_id = next; + continue; + } else { + return Err(BtfError::UnexpectedBtfType { type_id }); + } } }; - - return Ok(size * n_elems); + return Ok((size * n_elems) as usize); } Err(BtfError::MaximumTypeDepthReached { @@ -416,56 +388,55 @@ impl Btf { let mut types = mem::take(&mut self.types); for i in 0..types.types.len() { let t = &types.types[i]; - let kind = t.kind()?.unwrap_or_default(); + let kind = t.kind(); match t { // Fixup PTR for Rust // LLVM emits names for Rust pointer types, which the kernel doesn't like // While I figure out if this needs fixing in the Kernel or LLVM, we'll // do a fixup here - BtfType::Ptr(ty) => { - let mut fixed_ty = *ty; - fixed_ty.name_off = 0; + BtfType::Ptr(ptr) => { + let mut fixed_ty = ptr.clone(); + fixed_ty.name_offset = 0; types.types[i] = BtfType::Ptr(fixed_ty) } // Sanitize VAR if they are not supported - BtfType::Var(ty, _) if !features.btf_datasec => { - types.types[i] = BtfType::new_int(ty.name_off, 1, 0, 0); + BtfType::Var(v) if !features.btf_datasec => { + types.types[i] = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); } // Sanitize DATASEC if they are not supported - BtfType::DataSec(ty, data) if !features.btf_datasec => { + BtfType::DataSec(d) if !features.btf_datasec => { debug!("{}: not supported. replacing with STRUCT", kind); let mut members = vec![]; - for member in data { - let mt = types.type_by_id(member.type_).unwrap(); - members.push(btf_member { - name_off: mt.btf_type().unwrap().name_off, - type_: member.type_, + for member in d.entries.iter() { + let mt = types.type_by_id(member.btf_type).unwrap(); + members.push(BtfMember { + name_offset: mt.name_offset(), + btf_type: member.btf_type, offset: member.offset * 8, }) } - types.types[i] = BtfType::new_struct(ty.name_off, members, 0); + types.types[i] = BtfType::Struct(Struct::new(t.name_offset(), members, 0)); } // Fixup DATASEC // DATASEC sizes aren't always set by LLVM // we need to fix them here before loading the btf to the kernel - BtfType::DataSec(ty, data) if features.btf_datasec => { + BtfType::DataSec(d) if features.btf_datasec => { // Start DataSec Fixups - let sec_name = self.string_at(ty.name_off)?; + let sec_name = self.string_at(d.name_offset)?; let name = sec_name.to_string(); - let mut fixed_ty = *ty; - let mut fixed_data = data.clone(); + let mut fixed_ty = d.clone(); // Handle any "/" characters in section names // Example: "maps/hashmap" let fixed_name = name.replace('/', "."); if fixed_name != name { - fixed_ty.name_off = self.add_string(fixed_name); + fixed_ty.name_offset = self.add_string(fixed_name); } // There are some cases when the compiler does indeed populate the // size - if unsafe { ty.__bindgen_anon_1.size > 0 } { + if t.size().unwrap() > 0 { debug!("{} {}: size fixup not required", kind, name); } else { // We need to get the size of the section from the ELF file @@ -477,19 +448,19 @@ impl Btf { } })?; debug!("{} {}: fixup size to {}", kind, name, size); - fixed_ty.__bindgen_anon_1.size = *size as u32; + fixed_ty.size = *size as u32; // The Vec contains BTF_KIND_VAR sections // that need to have their offsets adjusted. To do this, // we need to get the offset from the ELF file. // This was also cached during initial parsing and // we can query by name in symbol_offsets - for d in &mut fixed_data { - let var_type = types.type_by_id(d.type_)?; - let var_kind = var_type.kind()?.unwrap(); - if let BtfType::Var(vty, var) = var_type { - let var_name = self.string_at(vty.name_off)?.to_string(); - if var.linkage == btf_func_linkage::BTF_FUNC_STATIC as u32 { + for d in &mut fixed_ty.entries.iter_mut() { + let var_type = types.type_by_id(d.btf_type)?; + let var_kind = var_type.kind(); + if let BtfType::Var(var) = var_type { + let var_name = self.string_at(var.name_offset)?.to_string(); + if var.linkage == VarLinkage::Static { debug!( "{} {}: {} {}: fixup not required", kind, name, var_kind, var_name @@ -512,68 +483,66 @@ impl Btf { } } } - types.types[i] = BtfType::DataSec(fixed_ty, fixed_data); + types.types[i] = BtfType::DataSec(fixed_ty); } // Fixup FUNC_PROTO - BtfType::FuncProto(ty, params) if features.btf_func => { - let mut params = params.clone(); - for (i, mut param) in params.iter_mut().enumerate() { - if param.name_off == 0 && param.type_ != 0 { - param.name_off = self.add_string(format!("param{}", i)); + BtfType::FuncProto(ty) if features.btf_func => { + let mut ty = ty.clone(); + for (i, mut param) in ty.params.iter_mut().enumerate() { + if param.name_offset == 0 && param.btf_type != 0 { + param.name_offset = self.add_string(format!("param{}", i)); } } - types.types[i] = BtfType::FuncProto(*ty, params); + types.types[i] = BtfType::FuncProto(ty); } // Sanitize FUNC_PROTO - BtfType::FuncProto(ty, vars) if !features.btf_func => { + BtfType::FuncProto(ty) if !features.btf_func => { debug!("{}: not supported. replacing with ENUM", kind); - let members: Vec = vars + let members: Vec = ty + .params .iter() - .map(|p| btf_enum { - name_off: p.name_off, - val: p.type_ as i32, + .map(|p| BtfEnum { + name_offset: p.name_offset, + value: p.btf_type as i32, }) .collect(); - let enum_type = BtfType::new_enum(ty.name_off, members); + let enum_type = BtfType::Enum(Enum::new(ty.name_offset, members)); types.types[i] = enum_type; } // Sanitize FUNC BtfType::Func(ty) if !features.btf_func => { debug!("{}: not supported. replacing with TYPEDEF", kind); - let typedef_type = - BtfType::new_typedef(ty.name_off, unsafe { ty.__bindgen_anon_1.type_ }); + let typedef_type = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type)); types.types[i] = typedef_type; } // Sanitize BTF_FUNC_GLOBAL BtfType::Func(ty) if !features.btf_func_global => { - let mut fixed_ty = *ty; - if type_vlen(ty) == btf_func_linkage::BTF_FUNC_GLOBAL as usize { + let mut fixed_ty = ty.clone(); + if ty.linkage() == FuncLinkage::Global { debug!( "{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC", kind ); - fixed_ty.info = (ty.info & 0xFFFF0000) - | (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF; + fixed_ty.set_linkage(FuncLinkage::Static); } types.types[i] = BtfType::Func(fixed_ty); } // Sanitize FLOAT BtfType::Float(ty) if !features.btf_float => { debug!("{}: not supported. replacing with STRUCT", kind); - let struct_ty = - BtfType::new_struct(0, vec![], unsafe { ty.__bindgen_anon_1.size }); + let struct_ty = BtfType::Struct(Struct::new(0, vec![], ty.size)); types.types[i] = struct_ty; } // Sanitize DECL_TAG - BtfType::DeclTag(ty, _) if !features.btf_decl_tag => { + BtfType::DeclTag(ty) if !features.btf_decl_tag => { debug!("{}: not supported. replacing with INT", kind); - let int_type = BtfType::new_int(ty.name_off, 1, 0, 0); + let int_type = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); types.types[i] = int_type; } // Sanitize TYPE_TAG BtfType::TypeTag(ty) if !features.btf_type_tag => { debug!("{}: not supported. replacing with CONST", kind); - let const_type = BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ }); + let const_type = BtfType::Const(Const::new(ty.btf_type)); types.types[i] = const_type; } // The type does not need fixing up or sanitization @@ -670,12 +639,12 @@ impl BtfExt { SecInfoIter::new(ext.func_info_data(), ext.func_info_rec_size, endianness) .map(move |sec| { let name = btf - .string_at(sec.sec_name_off) + .string_at(sec.name_offset) .ok() .map(String::from) .unwrap(); let info = FuncSecInfo::parse( - sec.sec_name_off, + sec.name_offset, sec.num_info, func_info_rec_size, sec.data, @@ -691,12 +660,12 @@ impl BtfExt { SecInfoIter::new(ext.line_info_data(), ext.line_info_rec_size, endianness) .map(move |sec| { let name = btf - .string_at(sec.sec_name_off) + .string_at(sec.name_offset) .ok() .map(String::from) .unwrap(); let info = LineSecInfo::parse( - sec.sec_name_off, + sec.name_offset, sec.num_info, line_info_rec_size, sec.data, @@ -717,7 +686,7 @@ impl BtfExt { .enumerate() .map(|(n, rec)| unsafe { Relocation::parse(rec, n) }) .collect::, _>>()?; - Ok((sec.sec_name_off, relos)) + Ok((sec.name_offset, relos)) }) .collect::, _>>()?, ); @@ -793,7 +762,7 @@ impl<'a> Iterator for SecInfoIter<'a> { } else { u32::from_be_bytes }; - let sec_name_off = read_u32(data[self.offset..self.offset + 4].try_into().unwrap()); + let name_offset = read_u32(data[self.offset..self.offset + 4].try_into().unwrap()); self.offset += 4; let num_info = u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap()); self.offset += 4; @@ -802,7 +771,7 @@ impl<'a> Iterator for SecInfoIter<'a> { self.offset += self.rec_size * num_info as usize; Some(SecInfo { - sec_name_off, + name_offset, num_info, data, }) @@ -829,7 +798,7 @@ impl BtfTypes { let mut buf = vec![]; for t in self.types.iter().skip(1) { let b = t.to_bytes(); - buf.put(b.as_slice()) + buf.extend(b) } buf } @@ -855,9 +824,24 @@ impl BtfTypes { use BtfType::*; match ty { - Volatile(ty) | Const(ty) | Restrict(ty) | Typedef(ty) | TypeTag(ty) => { - // Safety: union - type_id = unsafe { ty.__bindgen_anon_1.type_ }; + Volatile(ty) => { + type_id = ty.btf_type; + continue; + } + Const(ty) => { + type_id = ty.btf_type; + continue; + } + Restrict(ty) => { + type_id = ty.btf_type; + continue; + } + Typedef(ty) => { + type_id = ty.btf_type; + continue; + } + TypeTag(ty) => { + type_id = ty.btf_type; continue; } _ => return Ok(type_id), @@ -872,15 +856,15 @@ impl BtfTypes { #[derive(Debug)] pub(crate) struct SecInfo<'a> { - sec_name_off: u32, + name_offset: u32, num_info: u32, data: &'a [u8], } #[cfg(test)] mod tests { - use crate::generated::{ - btf_param, btf_var_secinfo, BTF_INT_SIGNED, BTF_VAR_GLOBAL_EXTERN, BTF_VAR_STATIC, + use crate::obj::btf::{ + BtfParam, DataSec, DataSecEntry, DeclTag, Float, Func, FuncProto, Ptr, TypeTag, Var, }; use super::*; @@ -976,11 +960,11 @@ mod tests { fn test_write_btf() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); btf.add_type(int_type); let name_offset = btf.add_string("widget".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); btf.add_type(int_type); let btf_bytes = btf.to_bytes(); @@ -1002,10 +986,15 @@ mod tests { fn test_fixup_ptr() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let name_offset = btf.add_string("&mut int".to_string()); - let ptr_type_id = btf.add_type(BtfType::new_ptr(name_offset, int_type_id)); + let ptr_type_id = btf.add_type(BtfType::Ptr(Ptr::new(name_offset, int_type_id))); let features = Features { ..Default::default() @@ -1015,9 +1004,9 @@ mod tests { .unwrap(); if let BtfType::Ptr(fixed) = btf.type_by_id(ptr_type_id).unwrap() { assert!( - fixed.name_off == 0, + fixed.name_offset == 0, "expected offset 0, got {}", - fixed.name_off + fixed.name_offset ) } else { panic!("not a ptr") @@ -1031,10 +1020,19 @@ mod tests { fn test_sanitize_var() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let name_offset = btf.add_string("&mut int".to_string()); - let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC)); + let var_type_id = btf.add_type(BtfType::Var(Var::new( + name_offset, + int_type_id, + VarLinkage::Static, + ))); let features = Features { btf_datasec: false, @@ -1043,8 +1041,8 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - if let BtfType::Int(fixed, _) = btf.type_by_id(var_type_id).unwrap() { - assert!(fixed.name_off == name_offset) + if let BtfType::Int(fixed) = btf.type_by_id(var_type_id).unwrap() { + assert!(fixed.name_offset == name_offset) } else { panic!("not an int") } @@ -1057,18 +1055,28 @@ mod tests { fn test_sanitize_datasec() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let name_offset = btf.add_string("foo".to_string()); - let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC)); + let var_type_id = btf.add_type(BtfType::Var(Var::new( + name_offset, + int_type_id, + VarLinkage::Static, + ))); let name_offset = btf.add_string(".data".to_string()); - let variables = vec![btf_var_secinfo { - type_: var_type_id, + let variables = vec![DataSecEntry { + btf_type: var_type_id, offset: 0, size: 4, }]; - let datasec_type_id = btf.add_type(BtfType::new_datasec(name_offset, variables, 0)); + let datasec_type_id = + btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0))); let features = Features { btf_datasec: false, @@ -1077,11 +1085,11 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - if let BtfType::Struct(fixed, members) = btf.type_by_id(datasec_type_id).unwrap() { - assert!(fixed.name_off == name_offset); - assert!(members.len() == 1); - assert!(members[0].type_ == var_type_id); - assert!(members[0].offset == 0) + if let BtfType::Struct(fixed) = btf.type_by_id(datasec_type_id).unwrap() { + assert!(fixed.name_offset == name_offset); + assert!(fixed.members.len() == 1); + assert!(fixed.members[0].btf_type == var_type_id); + assert!(fixed.members[0].offset == 0) } else { panic!("not a struct") } @@ -1094,22 +1102,28 @@ mod tests { fn test_fixup_datasec() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let name_offset = btf.add_string("foo".to_string()); - let var_type_id = btf.add_type(BtfType::new_var( + let var_type_id = btf.add_type(BtfType::Var(Var::new( name_offset, int_type_id, - BTF_VAR_GLOBAL_EXTERN, - )); + VarLinkage::Global, + ))); let name_offset = btf.add_string(".data/foo".to_string()); - let variables = vec![btf_var_secinfo { - type_: var_type_id, + let variables = vec![DataSecEntry { + btf_type: var_type_id, offset: 0, size: 4, }]; - let datasec_type_id = btf.add_type(BtfType::new_datasec(name_offset, variables, 0)); + let datasec_type_id = + btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0))); let features = Features { btf_datasec: true, @@ -1123,17 +1137,17 @@ mod tests { ) .unwrap(); - if let BtfType::DataSec(fixed, sec_info) = btf.type_by_id(datasec_type_id).unwrap() { - assert!(fixed.name_off != name_offset); - assert!(unsafe { fixed.__bindgen_anon_1.size } == 32); - assert!(sec_info.len() == 1); - assert!(sec_info[0].type_ == var_type_id); + if let BtfType::DataSec(fixed) = btf.type_by_id(datasec_type_id).unwrap() { + assert!(fixed.name_offset != name_offset); + assert!(fixed.size == 32); + assert!(fixed.entries.len() == 1); + assert!(fixed.entries[0].btf_type == var_type_id); assert!( - sec_info[0].offset == 64, + fixed.entries[0].offset == 64, "expected 64, got {}", - sec_info[0].offset + fixed.entries[0].offset ); - assert!(btf.string_at(fixed.name_off).unwrap() == ".data.foo") + assert!(btf.string_at(fixed.name_offset).unwrap() == ".data.foo") } else { panic!("not a datasec") } @@ -1146,25 +1160,31 @@ mod tests { fn test_sanitize_func_and_proto() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let params = vec![ - btf_param { - name_off: btf.add_string("a".to_string()), - type_: int_type_id, + BtfParam { + name_offset: btf.add_string("a".to_string()), + btf_type: int_type_id, }, - btf_param { - name_off: btf.add_string("b".to_string()), - type_: int_type_id, + BtfParam { + name_offset: btf.add_string("b".to_string()), + btf_type: int_type_id, }, ]; - let func_proto_type_id = btf.add_type(BtfType::new_func_proto(params, int_type_id)); + let func_proto_type_id = + btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id))); let inc = btf.add_string("inc".to_string()); - let func_type_id = btf.add_type(BtfType::new_func( + let func_type_id = btf.add_type(BtfType::Func(Func::new( inc, func_proto_type_id, - btf_func_linkage::BTF_FUNC_STATIC, - )); + FuncLinkage::Static, + ))); let features = Features { btf_func: false, @@ -1173,21 +1193,20 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - - if let BtfType::Enum(fixed, vars) = btf.type_by_id(func_proto_type_id).unwrap() { - assert!(fixed.name_off == 0); - assert!(vars.len() == 2); - assert!(btf.string_at(vars[0].name_off).unwrap() == "a"); - assert!(vars[0].val == int_type_id as i32); - assert!(btf.string_at(vars[1].name_off).unwrap() == "b"); - assert!(vars[1].val == int_type_id as i32); + if let BtfType::Enum(fixed) = btf.type_by_id(func_proto_type_id).unwrap() { + 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!(btf.string_at(fixed.variants[1].name_offset).unwrap() == "b"); + assert!(fixed.variants[1].value == int_type_id as i32); } else { panic!("not an emum") } if let BtfType::Typedef(fixed) = btf.type_by_id(func_type_id).unwrap() { - assert!(fixed.name_off == inc); - assert!(unsafe { fixed.__bindgen_anon_1.type_ } == func_proto_type_id); + assert!(fixed.name_offset == inc); + assert!(fixed.btf_type == func_proto_type_id); } else { panic!("not a typedef") } @@ -1200,20 +1219,20 @@ mod tests { fn test_fixup_func_proto() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let params = vec![ - btf_param { - name_off: 0, - type_: int_type_id, + BtfParam { + name_offset: 0, + btf_type: int_type_id, }, - btf_param { - name_off: 0, - type_: int_type_id, + BtfParam { + name_offset: 0, + btf_type: int_type_id, }, ]; - let func_proto = BtfType::new_func_proto(params, int_type_id); + let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id)); let func_proto_type_id = btf.add_type(func_proto); let features = Features { @@ -1224,9 +1243,9 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - if let BtfType::FuncProto(_, vars) = btf.type_by_id(func_proto_type_id).unwrap() { - assert!(btf.string_at(vars[0].name_off).unwrap() == "param0"); - assert!(btf.string_at(vars[1].name_off).unwrap() == "param1"); + if let BtfType::FuncProto(fixed) = btf.type_by_id(func_proto_type_id).unwrap() { + assert!(btf.string_at(fixed.params[0].name_offset).unwrap() == "param0"); + assert!(btf.string_at(fixed.params[1].name_offset).unwrap() == "param1"); } else { panic!("not a func_proto") } @@ -1239,25 +1258,31 @@ mod tests { fn test_sanitize_func_global() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let params = vec![ - btf_param { - name_off: btf.add_string("a".to_string()), - type_: int_type_id, + BtfParam { + name_offset: btf.add_string("a".to_string()), + btf_type: int_type_id, }, - btf_param { - name_off: btf.add_string("b".to_string()), - type_: int_type_id, + BtfParam { + name_offset: btf.add_string("b".to_string()), + btf_type: int_type_id, }, ]; - let func_proto_type_id = btf.add_type(BtfType::new_func_proto(params, int_type_id)); + let func_proto_type_id = + btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id))); let inc = btf.add_string("inc".to_string()); - let func_type_id = btf.add_type(BtfType::new_func( + let func_type_id = btf.add_type(BtfType::Func(Func::new( inc, func_proto_type_id, - btf_func_linkage::BTF_FUNC_GLOBAL, - )); + FuncLinkage::Global, + ))); let features = Features { btf_func: true, @@ -1269,7 +1294,7 @@ mod tests { .unwrap(); if let BtfType::Func(fixed) = btf.type_by_id(func_type_id).unwrap() { - assert!(type_vlen(fixed) == btf_func_linkage::BTF_FUNC_STATIC as usize); + assert!(fixed.linkage() == FuncLinkage::Static); } else { panic!("not a func") } @@ -1282,7 +1307,7 @@ mod tests { fn test_sanitize_float() { let mut btf = Btf::new(); let name_offset = btf.add_string("float".to_string()); - let float_type_id = btf.add_type(BtfType::new_float(name_offset, 16)); + let float_type_id = btf.add_type(BtfType::Float(Float::new(name_offset, 16))); let features = Features { btf_float: false, @@ -1291,9 +1316,9 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - if let BtfType::Struct(fixed, _) = btf.type_by_id(float_type_id).unwrap() { - assert!(fixed.name_off == 0); - assert!(unsafe { fixed.__bindgen_anon_1.size } == 16); + if let BtfType::Struct(fixed) = btf.type_by_id(float_type_id).unwrap() { + assert!(fixed.name_offset == 0); + assert!(fixed.size == 16); } else { panic!("not a struct") } @@ -1306,13 +1331,23 @@ mod tests { fn test_sanitize_decl_tag() { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new( + name_offset, + 4, + IntEncoding::Signed, + 0, + ))); let name_offset = btf.add_string("foo".to_string()); - let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC)); + let var_type_id = btf.add_type(BtfType::Var(Var::new( + name_offset, + int_type_id, + VarLinkage::Static, + ))); let name_offset = btf.add_string("decl_tag".to_string()); - let decl_tag_type_id = btf.add_type(BtfType::new_decl_tag(name_offset, var_type_id, -1)); + let decl_tag_type_id = + btf.add_type(BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1))); let features = Features { btf_decl_tag: false, @@ -1321,9 +1356,9 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); - if let BtfType::Int(fixed, _) = btf.type_by_id(decl_tag_type_id).unwrap() { - assert!(fixed.name_off == name_offset); - assert!(unsafe { fixed.__bindgen_anon_1.size } == 1); + if let BtfType::Int(fixed) = btf.type_by_id(decl_tag_type_id).unwrap() { + assert!(fixed.name_offset == name_offset); + assert!(fixed.size == 1); } else { panic!("not an int") } @@ -1336,11 +1371,11 @@ mod tests { fn test_sanitize_type_tag() { let mut btf = Btf::new(); - let int_type_id = btf.add_type(BtfType::new_int(0, 4, BTF_INT_SIGNED, 0)); + let int_type_id = btf.add_type(BtfType::Int(Int::new(0, 4, IntEncoding::Signed, 0))); let name_offset = btf.add_string("int".to_string()); - let type_tag_type = btf.add_type(BtfType::new_type_tag(name_offset, int_type_id)); - btf.add_type(BtfType::new_ptr(0, type_tag_type)); + let type_tag_type = btf.add_type(BtfType::TypeTag(TypeTag::new(name_offset, int_type_id))); + btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type))); let features = Features { btf_type_tag: false, @@ -1350,7 +1385,7 @@ mod tests { btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) .unwrap(); if let BtfType::Const(fixed) = btf.type_by_id(type_tag_type).unwrap() { - assert!(unsafe { fixed.__bindgen_anon_1.type_ } == int_type_id); + assert!(fixed.btf_type == int_type_id); } else { panic!("not a const") } @@ -1358,4 +1393,29 @@ mod tests { let raw = btf.to_bytes(); Btf::parse(&raw, Endianness::default()).unwrap(); } + + #[test] + #[cfg_attr(miri, ignore)] + fn test_read_btf_from_sys_fs() { + let btf = Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default()).unwrap(); + let task_struct_id = btf + .id_by_type_name_kind("task_struct", BtfKind::Struct) + .unwrap(); + // we can't assert on exact ID since this may change across kernel versions + assert!(task_struct_id != 0); + + let netif_id = btf + .id_by_type_name_kind("netif_receive_skb", BtfKind::Func) + .unwrap(); + assert!(netif_id != 0); + + let u32_def = btf.id_by_type_name_kind("__u32", BtfKind::Typedef).unwrap(); + assert!(u32_def != 0); + + let u32_base = btf.resolve_type(u32_def).unwrap(); + assert!(u32_base != 0); + + let u32_ty = btf.type_by_id(u32_base).unwrap(); + assert_eq!(u32_ty.kind(), BtfKind::Int); + } } diff --git a/aya/src/obj/btf/relocation.rs b/aya/src/obj/btf/relocation.rs index d6f5f662..d34b69d1 100644 --- a/aya/src/obj/btf/relocation.rs +++ b/aya/src/obj/btf/relocation.rs @@ -9,8 +9,8 @@ use crate::{ }, obj::{ btf::{ - fields_are_compatible, member_bit_field_size, member_bit_offset, types_are_compatible, - BtfType, MAX_SPEC_LEN, + fields_are_compatible, types_are_compatible, Array, BtfMember, BtfType, IntEncoding, + Struct, Union, MAX_SPEC_LEN, }, Btf, BtfError, Object, Program, ProgramSection, }, @@ -207,7 +207,7 @@ fn relocate_btf_program<'target>( } let local_ty = local_btf.type_by_id(rel.type_id)?; - let local_name = &*local_btf.type_name(local_ty)?.unwrap(); + let local_name = &*local_btf.type_name(local_ty)?; let access_str = &*local_btf.string_at(rel.access_str_offset)?; let local_spec = AccessSpec::new(local_btf, rel.type_id, access_str, *rel)?; @@ -288,10 +288,10 @@ fn find_candidates<'target>( 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()? { + if local_ty.kind() != ty.kind() { continue; } - let name = &*target_btf.type_name(ty)?.unwrap(); + let name = &*target_btf.type_name(ty)?; if local_name != flavorless_name(name) { continue; } @@ -342,9 +342,9 @@ fn match_candidate<'target>( // the first accessor is guaranteed to have a name by construction let local_variant_name = local_spec.accessors[0].name.as_ref().unwrap(); match target_ty { - BtfType::Enum(_, members) => { - for (index, member) in members.iter().enumerate() { - let target_variant_name = candidate.btf.string_at(member.name_off)?; + BtfType::Enum(en) => { + for (index, member) in en.variants.iter().enumerate() { + let target_variant_name = candidate.btf.string_at(member.name_offset)?; if flavorless_name(local_variant_name) == flavorless_name(&target_variant_name) { @@ -389,24 +389,24 @@ fn match_candidate<'target>( if i > 0 { let target_ty = candidate.btf.type_by_id(target_id)?; let array = match target_ty { - BtfType::Array(_, array) => array, + BtfType::Array(Array { array, .. }) => array, _ => return Ok(None), }; - let var_len = array.nelems == 0 && { + let var_len = array.len == 0 && { // an array is potentially variable length if it's the last field // of the parent struct and has 0 elements let parent = target_spec.accessors.last().unwrap(); let parent_ty = candidate.btf.type_by_id(parent.type_id)?; match parent_ty { - BtfType::Struct(_, members) => parent.index == members.len() - 1, + BtfType::Struct(s) => parent.index == s.members.len() - 1, _ => false, } }; - if !var_len && accessor.index >= array.nelems as usize { + if !var_len && accessor.index >= array.len as usize { return Ok(None); } - target_id = candidate.btf.resolve_type(array.type_)?; + target_id = candidate.btf.resolve_type(array.element_type)?; } if target_spec.parts.len() == MAX_SPEC_LEN { @@ -442,21 +442,20 @@ fn match_member<'local, 'target>( ) -> Result, ErrorWrapper> { let local_ty = local_btf.type_by_id(local_accessor.type_id)?; let local_member = match local_ty { - BtfType::Struct(_, members) | BtfType::Union(_, members) => { - // this won't panic, bounds are checked when local_spec is built in AccessSpec::new - members[local_accessor.index] - } + // this won't panic, bounds are checked when local_spec is built in AccessSpec::new + BtfType::Struct(s) => s.members.get(local_accessor.index).unwrap(), + BtfType::Union(u) => u.members.get(local_accessor.index).unwrap(), _ => panic!("bug! this should only be called for structs and unions"), }; - let local_name = &*local_btf.string_at(local_member.name_off)?; + let local_name = &*local_btf.string_at(local_member.name_offset)?; let target_id = target_btf.resolve_type(target_id)?; let target_ty = target_btf.type_by_id(target_id)?; - let target_members = match target_ty { - BtfType::Struct(_, members) | BtfType::Union(_, members) => members, + let target_members: Vec<&BtfMember> = match target_ty.members() { + Some(members) => members.collect(), // not a fields type, no match - _ => return Ok(None), + None => return Ok(None), }; for (index, target_member) in target_members.iter().enumerate() { @@ -468,8 +467,9 @@ fn match_member<'local, 'target>( .into()); } - let bit_offset = member_bit_offset(target_ty.info().unwrap(), target_member); - let target_name = &*target_btf.string_at(target_member.name_off)?; + // this will not panic as we've already established these are fields types + let bit_offset = target_ty.member_bit_offset(target_member).unwrap(); + let target_name = &*target_btf.string_at(target_member.name_offset)?; if target_name.is_empty() { let ret = match_member( @@ -477,7 +477,7 @@ fn match_member<'local, 'target>( local_spec, local_accessor, target_btf, - target_member.type_, + target_member.btf_type, target_spec, )?; if ret.is_some() { @@ -488,9 +488,9 @@ fn match_member<'local, 'target>( } else if local_name == target_name { if fields_are_compatible( local_spec.btf, - local_member.type_, + local_member.btf_type, target_btf, - target_member.type_, + target_member.btf_type, )? { target_spec.bit_offset += bit_offset; target_spec.parts.push(index); @@ -499,7 +499,7 @@ fn match_member<'local, 'target>( index, name: Some(target_name.to_owned()), }); - return Ok(Some(target_member.type_)); + return Ok(Some(target_member.btf_type)); } else { return Ok(None); } @@ -558,7 +558,7 @@ impl<'a> AccessSpec<'a> { } } RelocationKind::EnumVariantExists | RelocationKind::EnumVariantValue => match ty { - BtfType::Enum(_, members) => { + BtfType::Enum(en) => { if parts.len() != 1 { return Err(RelocationError::InvalidAccessString { access_str: spec.to_string(), @@ -566,12 +566,12 @@ impl<'a> AccessSpec<'a> { .into()); } let index = parts[0]; - if index >= members.len() { + if index >= en.variants.len() { return Err(RelocationError::InvalidAccessIndex { type_name: btf.err_type_name(ty), spec: spec.to_string(), index, - max_index: members.len(), + max_index: en.variants.len(), error: "tried to access nonexistant enum variant".to_string(), } .into()); @@ -579,7 +579,10 @@ impl<'a> AccessSpec<'a> { let accessors = vec![Accessor { type_id, index, - name: Some(btf.string_at(members[index].name_off)?.to_string()), + name: Some( + btf.string_at(en.variants.get(index).unwrap().name_offset)? + .to_string(), + ), }]; AccessSpec { @@ -595,7 +598,7 @@ impl<'a> AccessSpec<'a> { return Err(RelocationError::InvalidRelocationKindForType { relocation_number: relocation.number, relocation_kind: format!("{:?}", relocation.kind), - type_kind: format!("{:?}", ty.kind()?.unwrap()), + type_kind: format!("{:?}", ty.kind()), error: "enum relocation on non-enum type".to_string(), } .into()) @@ -618,9 +621,9 @@ impl<'a> AccessSpec<'a> { type_id = btf.resolve_type(type_id)?; let ty = btf.type_by_id(type_id)?; - use BtfType::*; match ty { - Struct(t, members) | Union(t, members) => { + BtfType::Struct(Struct { members, .. }) + | BtfType::Union(Union { members, .. }) => { if index >= members.len() { return Err(RelocationError::InvalidAccessIndex { type_name: btf.err_type_name(ty), @@ -632,38 +635,38 @@ impl<'a> AccessSpec<'a> { .into()); } - let member = members[index]; - bit_offset += member_bit_offset(t.info, &member); + let member = &members[index]; + bit_offset += ty.member_bit_offset(member).unwrap(); - if member.name_off != 0 { + if member.name_offset != 0 { accessors.push(Accessor { type_id, index, - name: Some(btf.string_at(member.name_off)?.to_string()), + name: Some(btf.string_at(member.name_offset)?.to_string()), }); } - type_id = member.type_; + type_id = member.btf_type; } - Array(_, array) => { - type_id = btf.resolve_type(array.type_)?; - let var_len = array.nelems == 0 && { + BtfType::Array(Array { array, .. }) => { + type_id = btf.resolve_type(array.element_type)?; + let var_len = array.len == 0 && { // an array is potentially variable length if it's the last field // of the parent struct and has 0 elements let parent = accessors.last().unwrap(); let parent_ty = btf.type_by_id(parent.type_id)?; match parent_ty { - Struct(_, members) => index == members.len() - 1, + BtfType::Struct(s) => index == s.members.len() - 1, _ => false, } }; - if !var_len && index >= array.nelems as usize { + if !var_len && index >= array.len as usize { return Err(RelocationError::InvalidAccessIndex { type_name: btf.err_type_name(ty), spec: spec.to_string(), index, - max_index: array.nelems as usize, + max_index: array.len as usize, error: "array index out of bounds".to_string(), } .into()); @@ -814,8 +817,8 @@ impl ComputedRelocation { use BtfType::*; match (local_ty, target_ty) { (Ptr(_), Ptr(_)) => {} - (Int(_, local_info), Int(_, target_info)) - if unsigned(*local_info) && unsigned(*target_info) => {} + (Int(local), Int(target)) + if unsigned(local.data) && unsigned(target.data) => {} _ => { return Err(RelocationError::InvalidInstruction { relocation_number: rel.number, @@ -885,7 +888,7 @@ impl ComputedRelocation { let spec = spec.unwrap(); let accessor = &spec.accessors[0]; match spec.btf.type_by_id(accessor.type_id)? { - BtfType::Enum(_, variants) => variants[accessor.index].val as u32, + BtfType::Enum(en) => en.variants[accessor.index].value as u32, _ => panic!("should not be reached"), } } @@ -946,9 +949,8 @@ impl ComputedRelocation { let ty = spec.btf.type_by_id(accessor.type_id)?; let (ll_ty, member) = match ty { - BtfType::Struct(ty, members) | BtfType::Union(ty, members) => { - (ty, members[accessor.index]) - } + BtfType::Struct(t) => (ty, t.members.get(accessor.index).unwrap()), + BtfType::Union(t) => (ty, t.members.get(accessor.index).unwrap()), _ => { return Err(RelocationError::InvalidRelocationKindForType { relocation_number: rel.number, @@ -961,17 +963,16 @@ impl ComputedRelocation { }; let bit_off = spec.bit_offset as u32; - let member_type_id = spec.btf.resolve_type(member.type_)?; + let member_type_id = spec.btf.resolve_type(member.btf_type)?; let member_ty = spec.btf.type_by_id(member_type_id)?; - let ll_member_ty = member_ty.btf_type().unwrap(); let mut byte_size; let mut byte_off; - let mut bit_size = member_bit_field_size(ll_ty, &member) as u32; + let mut bit_size = ll_ty.member_bit_field_size(member).unwrap() as u32; let is_bitfield = bit_size > 0; if is_bitfield { // find out the smallest int size to load the bitfield - byte_size = unsafe { ll_member_ty.__bindgen_anon_1.size }; + byte_size = member_ty.size().unwrap(); byte_off = bit_off / 8 / byte_size * byte_size; while bit_off + bit_size - byte_off * 8 > byte_size * 8 { if byte_size >= 8 { @@ -1006,8 +1007,8 @@ impl ComputedRelocation { value.value = byte_size; } FieldSigned => match member_ty { - BtfType::Enum(_, _) => value.value = 1, - BtfType::Int(_, i) => value.value = ((i >> 24) & 0x0F) & BTF_INT_SIGNED, + BtfType::Enum(_) => value.value = 1, + BtfType::Int(i) => value.value = i.encoding() as u32 & IntEncoding::Signed as u32, _ => (), }, #[cfg(target_endian = "little")] diff --git a/aya/src/obj/btf/types.rs b/aya/src/obj/btf/types.rs index bd7ba6b6..d31dcca2 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya/src/obj/btf/types.rs @@ -2,63 +2,822 @@ use std::{fmt::Display, mem, ptr}; use object::Endianness; -use crate::{ - generated::{ - btf_array, btf_decl_tag, btf_enum, btf_func_linkage, btf_member, btf_param, btf_type, - btf_type__bindgen_ty_1, btf_var, btf_var_secinfo, BTF_KIND_ARRAY, BTF_KIND_CONST, - BTF_KIND_DATASEC, BTF_KIND_DECL_TAG, BTF_KIND_ENUM, BTF_KIND_FLOAT, BTF_KIND_FUNC, - BTF_KIND_FUNC_PROTO, BTF_KIND_FWD, BTF_KIND_INT, BTF_KIND_PTR, BTF_KIND_RESTRICT, - BTF_KIND_STRUCT, BTF_KIND_TYPEDEF, BTF_KIND_TYPE_TAG, BTF_KIND_UNION, BTF_KIND_UNKN, - BTF_KIND_VAR, BTF_KIND_VOLATILE, - }, - obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}, -}; +use crate::obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}; #[derive(Clone, Debug)] pub(crate) enum BtfType { Unknown, - Fwd(btf_type), - Const(btf_type), - Volatile(btf_type), - Restrict(btf_type), - Ptr(btf_type), - Typedef(btf_type), - Func(btf_type), - Int(btf_type, u32), - Float(btf_type), - Enum(btf_type, Vec), - Array(btf_type, btf_array), - Struct(btf_type, Vec), - Union(btf_type, Vec), - FuncProto(btf_type, Vec), - Var(btf_type, btf_var), - DataSec(btf_type, Vec), - DeclTag(btf_type, btf_decl_tag), - TypeTag(btf_type), + Fwd(Fwd), + Const(Const), + Volatile(Volatile), + Restrict(Restrict), + Ptr(Ptr), + Typedef(Typedef), + Func(Func), + Int(Int), + Float(Float), + Enum(Enum), + Array(Array), + Struct(Struct), + Union(Union), + FuncProto(FuncProto), + Var(Var), + DataSec(DataSec), + DeclTag(DeclTag), + TypeTag(TypeTag), +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Fwd { + pub(crate) name_offset: u32, + info: u32, + _unused: u32, +} + +impl Fwd { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Fwd + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Const { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +impl Const { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Const + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(btf_type: u32) -> Self { + let info = (BtfKind::Const as u32) << 24; + Const { + name_offset: 0, + info, + btf_type, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Volatile { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +impl Volatile { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Volatile + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } +} + +#[derive(Clone, Debug)] +pub(crate) struct Restrict { + pub(crate) name_offset: u32, + _info: u32, + pub(crate) btf_type: u32, +} + +impl Restrict { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Restrict + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Ptr { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +impl Ptr { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Ptr + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, btf_type: u32) -> Self { + let info = (BtfKind::Ptr as u32) << 24; + Ptr { + name_offset, + info, + btf_type, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Typedef { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +impl Typedef { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Typedef + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, btf_type: u32) -> Self { + let info = (BtfKind::Typedef as u32) << 24; + Typedef { + name_offset, + info, + btf_type, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Float { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, +} + +impl Float { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Float + } + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, size: u32) -> Self { + let info = (BtfKind::Float as u32) << 24; + Float { + name_offset, + info, + size, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Func { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +#[repr(u32)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum FuncLinkage { + Static = 0, + Global = 1, + Extern = 2, + Unknown, +} + +impl From for FuncLinkage { + fn from(v: u32) -> Self { + match v { + 0 => FuncLinkage::Static, + 1 => FuncLinkage::Global, + 2 => FuncLinkage::Extern, + _ => FuncLinkage::Unknown, + } + } +} + +impl Func { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Func + } + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, proto: u32, linkage: FuncLinkage) -> Self { + let mut info = (BtfKind::Func as u32) << 24; + info |= (linkage as u32) & 0xFFFF; + Func { + name_offset, + info, + btf_type: proto, + } + } + + pub(crate) fn linkage(&self) -> FuncLinkage { + (self.info & 0xFFF).into() + } + + pub(crate) fn set_linkage(&mut self, linkage: FuncLinkage) { + self.info = (self.info & 0xFFFF0000) | (linkage as u32) & 0xFFFF; + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct TypeTag { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, +} + +impl TypeTag { + pub(crate) fn to_bytes(&self) -> Vec { + bytes_of::(self).to_vec() + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::TypeTag + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, btf_type: u32) -> Self { + let info = (BtfKind::TypeTag as u32) << 24; + TypeTag { + name_offset, + info, + btf_type, + } + } +} + +#[repr(u32)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) enum IntEncoding { + None, + Signed = 1, + Char = 2, + Bool = 4, + Unknown, +} + +impl From for IntEncoding { + fn from(v: u32) -> Self { + match v { + 0 => IntEncoding::None, + 1 => IntEncoding::Signed, + 2 => IntEncoding::Char, + 4 => IntEncoding::Bool, + _ => IntEncoding::Unknown, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Int { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, + pub(crate) data: u32, +} + +impl Int { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.size)); + buf.extend(bytes_of::(&self.data)); + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Int + } + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, size: u32, encoding: IntEncoding, offset: u32) -> Self { + let info = (BtfKind::Int as u32) << 24; + let mut data = 0u32; + data |= (encoding as u32 & 0x0f) << 24; + data |= (offset & 0xff) << 16; + data |= (size * 8) & 0xff; + Int { + name_offset, + info, + size, + data, + } + } + + pub(crate) fn encoding(&self) -> IntEncoding { + ((self.data & 0x0f000000) >> 24).into() + } + + pub(crate) fn offset(&self) -> u32 { + (self.data & 0x00ff0000) >> 16 + } + + // TODO: Remove directive this when this crate is pub + #[cfg(test)] + pub(crate) fn bits(&self) -> u32 { + self.data & 0x000000ff + } +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub(crate) struct BtfEnum { + pub(crate) name_offset: u32, + pub(crate) value: i32, +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Enum { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, + pub(crate) variants: Vec, +} + +impl Enum { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.size)); + for v in &self.variants { + buf.extend(bytes_of::(&v.name_offset)); + buf.extend(bytes_of::(&v.value)); + } + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Enum + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + mem::size_of::() * self.variants.len() + } + + pub(crate) fn new(name_offset: u32, variants: Vec) -> Self { + let mut info = (BtfKind::Enum as u32) << 24; + info |= (variants.len() as u32) & 0xFFFF; + Enum { + name_offset, + info, + size: 4, + variants, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct BtfMember { + pub(crate) name_offset: u32, + pub(crate) btf_type: u32, + pub(crate) offset: u32, +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Struct { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, + pub(crate) members: Vec, +} + +impl Struct { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.size)); + for v in &self.members { + buf.extend(bytes_of::(&v.name_offset)); + buf.extend(bytes_of::(&v.btf_type)); + buf.extend(bytes_of::(&v.offset)); + } + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Struct + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + mem::size_of::() * self.members.len() + } + + pub(crate) fn new(name_offset: u32, members: Vec, size: u32) -> Self { + let mut info = (BtfKind::Struct as u32) << 24; + info |= (members.len() as u32) & 0xFFFF; + Struct { + name_offset, + info, + size, + members, + } + } + + pub(crate) fn member_bit_offset(&self, member: &BtfMember) -> usize { + let k_flag = self.info >> 31 == 1; + let bit_offset = if k_flag { + member.offset & 0xFFFFFF + } else { + member.offset + }; + + bit_offset as usize + } + + pub(crate) fn member_bit_field_size(&self, member: &BtfMember) -> usize { + let k_flag = (self.info >> 31) == 1; + let size = if k_flag { member.offset >> 24 } else { 0 }; + + size as usize + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Union { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, + pub(crate) members: Vec, +} + +impl Union { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.size)); + for v in &self.members { + buf.extend(bytes_of::(&v.name_offset)); + buf.extend(bytes_of::(&v.btf_type)); + buf.extend(bytes_of::(&v.offset)); + } + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Union + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + mem::size_of::() * self.members.len() + } + + pub(crate) fn member_bit_offset(&self, member: &BtfMember) -> usize { + let k_flag = self.info >> 31 == 1; + let bit_offset = if k_flag { + member.offset & 0xFFFFFF + } else { + member.offset + }; + + bit_offset as usize + } + + pub(crate) fn member_bit_field_size(&self, member: &BtfMember) -> usize { + let k_flag = (self.info >> 31) == 1; + let size = if k_flag { member.offset >> 24 } else { 0 }; + + size as usize + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct BtfArray { + pub(crate) element_type: u32, + pub(crate) index_type: u32, + pub(crate) len: u32, +} +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Array { + pub(crate) name_offset: u32, + info: u32, + _unused: u32, + pub(crate) array: BtfArray, +} + +impl Array { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self._unused)); + buf.extend(bytes_of::(&self.array)); + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Array + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + #[cfg(test)] + pub(crate) fn new(name_offset: u32, element_type: u32, index_type: u32, len: u32) -> Self { + let info = (BtfKind::Array as u32) << 24; + Array { + name_offset, + info, + _unused: 0, + array: BtfArray { + element_type, + index_type, + len, + }, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct BtfParam { + pub(crate) name_offset: u32, + pub(crate) btf_type: u32, +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct FuncProto { + pub(crate) name_offset: u32, + info: u32, + pub(crate) return_type: u32, + pub(crate) params: Vec, +} + +impl FuncProto { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.return_type)); + for p in &self.params { + buf.extend(bytes_of::(&p.name_offset)); + buf.extend(bytes_of::(&p.btf_type)); + } + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::FuncProto + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + mem::size_of::() * self.params.len() + } + + pub(crate) fn new(params: Vec, return_type: u32) -> Self { + let mut info = (BtfKind::FuncProto as u32) << 24; + info |= (params.len() as u32) & 0xFFFF; + FuncProto { + name_offset: 0, + info, + return_type, + params, + } + } +} + +#[repr(u32)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum VarLinkage { + Static, + Global, + Extern, + Unknown, +} + +impl From for VarLinkage { + fn from(v: u32) -> Self { + match v { + 0 => VarLinkage::Static, + 1 => VarLinkage::Global, + 2 => VarLinkage::Extern, + _ => VarLinkage::Unknown, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct Var { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, + pub(crate) linkage: VarLinkage, +} + +impl Var { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.btf_type)); + buf.extend(bytes_of::(&self.linkage)); + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::Var + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, btf_type: u32, linkage: VarLinkage) -> Self { + let info = (BtfKind::Var as u32) << 24; + Var { + name_offset, + info, + btf_type, + linkage, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct DataSecEntry { + pub(crate) btf_type: u32, + pub(crate) offset: u32, + pub(crate) size: u32, +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct DataSec { + pub(crate) name_offset: u32, + info: u32, + pub(crate) size: u32, + pub(crate) entries: Vec, +} + +impl DataSec { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.size)); + for e in &self.entries { + buf.extend(bytes_of::(&e.btf_type)); + buf.extend(bytes_of::(&e.offset)); + buf.extend(bytes_of::(&e.size)); + } + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::DataSec + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + mem::size_of::() * self.entries.len() + } + + pub(crate) fn new(name_offset: u32, entries: Vec, size: u32) -> Self { + let mut info = (BtfKind::DataSec as u32) << 24; + info |= (entries.len() as u32) & 0xFFFF; + DataSec { + name_offset, + info, + size, + entries, + } + } +} + +#[repr(C)] +#[derive(Clone, Debug)] +pub(crate) struct DeclTag { + pub(crate) name_offset: u32, + info: u32, + pub(crate) btf_type: u32, + pub(crate) component_index: i32, +} + +impl DeclTag { + pub(crate) fn to_bytes(&self) -> Vec { + let mut buf = vec![]; + buf.extend(bytes_of::(&self.name_offset)); + buf.extend(bytes_of::(&self.info)); + buf.extend(bytes_of::(&self.btf_type)); + buf.extend(bytes_of::(&self.component_index)); + buf + } + + pub(crate) fn kind(&self) -> BtfKind { + BtfKind::DeclTag + } + + pub(crate) fn type_info_size(&self) -> usize { + mem::size_of::() + } + + pub(crate) fn new(name_offset: u32, btf_type: u32, component_index: i32) -> Self { + let info = (BtfKind::DeclTag as u32) << 24; + DeclTag { + name_offset, + info, + btf_type, + component_index, + } + } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(u32)] pub(crate) enum BtfKind { - Unknown = BTF_KIND_UNKN, - Int = BTF_KIND_INT, - Float = BTF_KIND_FLOAT, - Ptr = BTF_KIND_PTR, - Array = BTF_KIND_ARRAY, - Struct = BTF_KIND_STRUCT, - Union = BTF_KIND_UNION, - Enum = BTF_KIND_ENUM, - Fwd = BTF_KIND_FWD, - Typedef = BTF_KIND_TYPEDEF, - Volatile = BTF_KIND_VOLATILE, - Const = BTF_KIND_CONST, - Restrict = BTF_KIND_RESTRICT, - Func = BTF_KIND_FUNC, - FuncProto = BTF_KIND_FUNC_PROTO, - Var = BTF_KIND_VAR, - DataSec = BTF_KIND_DATASEC, - DeclTag = BTF_KIND_DECL_TAG, - TypeTag = BTF_KIND_TYPE_TAG, + Unknown = 0, + Int = 1, + Ptr = 2, + Array = 3, + Struct = 4, + Union = 5, + Enum = 6, + Fwd = 7, + Typedef = 8, + Volatile = 9, + Const = 10, + Restrict = 11, + Func = 12, + FuncProto = 13, + Var = 14, + DataSec = 15, + Float = 16, + DeclTag = 17, + TypeTag = 18, } impl TryFrom for BtfKind { @@ -67,25 +826,25 @@ impl TryFrom for BtfKind { fn try_from(v: u32) -> Result { use BtfKind::*; Ok(match v { - BTF_KIND_UNKN => Unknown, - BTF_KIND_INT => Int, - BTF_KIND_FLOAT => Float, - BTF_KIND_PTR => Ptr, - BTF_KIND_ARRAY => Array, - BTF_KIND_STRUCT => Struct, - BTF_KIND_UNION => Union, - BTF_KIND_ENUM => Enum, - BTF_KIND_FWD => Fwd, - BTF_KIND_TYPEDEF => Typedef, - BTF_KIND_VOLATILE => Volatile, - BTF_KIND_CONST => Const, - BTF_KIND_RESTRICT => Restrict, - BTF_KIND_FUNC => Func, - BTF_KIND_FUNC_PROTO => FuncProto, - BTF_KIND_VAR => Var, - BTF_KIND_DATASEC => DataSec, - BTF_KIND_DECL_TAG => DeclTag, - BTF_KIND_TYPE_TAG => TypeTag, + 0 => Unknown, + 1 => Int, + 2 => Ptr, + 3 => Array, + 4 => Struct, + 5 => Union, + 6 => Enum, + 7 => Fwd, + 8 => Typedef, + 9 => Volatile, + 10 => Const, + 11 => Restrict, + 12 => Func, + 13 => FuncProto, + 14 => Var, + 15 => DataSec, + 16 => Float, + 17 => DeclTag, + 18 => TypeTag, kind => return Err(BtfError::InvalidTypeKind { kind }), }) } @@ -146,20 +905,46 @@ unsafe fn read_array(data: &[u8], len: usize) -> Result, BtfError> { impl BtfType { #[allow(unused_unsafe)] pub(crate) unsafe fn read(data: &[u8], endianness: Endianness) -> Result { - let ty = unsafe { read::(data)? }; - let data = &data[mem::size_of::()..]; - - let vlen = type_vlen(&ty) as usize; - use BtfType::*; - Ok(match type_kind(&ty)? { - BtfKind::Unknown => Unknown, - BtfKind::Fwd => Fwd(ty), - BtfKind::Const => Const(ty), - BtfKind::Volatile => Volatile(ty), - BtfKind::Restrict => Restrict(ty), - BtfKind::Ptr => Ptr(ty), - BtfKind::Typedef => Typedef(ty), - BtfKind::Func => Func(ty), + let ty = unsafe { read_array::(data, 3)? }; + let data = &data[mem::size_of::() * 3..]; + let vlen = type_vlen(ty[1]) as usize; + Ok(match type_kind(ty[1])? { + BtfKind::Unknown => BtfType::Unknown, + BtfKind::Fwd => BtfType::Fwd(Fwd { + name_offset: ty[0], + info: ty[1], + _unused: 0, + }), + BtfKind::Const => BtfType::Const(Const { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), + BtfKind::Volatile => BtfType::Volatile(Volatile { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), + BtfKind::Restrict => BtfType::Restrict(Restrict { + name_offset: ty[0], + _info: ty[1], + btf_type: ty[2], + }), + BtfKind::Ptr => BtfType::Ptr(Ptr { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), + BtfKind::Typedef => BtfType::Typedef(Typedef { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), + BtfKind::Func => BtfType::Func(Func { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), BtfKind::Int => { if mem::size_of::() > data.len() { return Err(BtfError::InvalidTypeInfo); @@ -169,324 +954,233 @@ impl BtfType { } else { u32::from_be_bytes }; - Int( - ty, - read_u32(data[..mem::size_of::()].try_into().unwrap()), - ) + BtfType::Int(Int { + name_offset: ty[0], + info: ty[1], + size: ty[2], + data: read_u32(data[..mem::size_of::()].try_into().unwrap()), + }) } - BtfKind::Float => Float(ty), - BtfKind::Enum => Enum(ty, unsafe { read_array(data, vlen)? }), - BtfKind::Array => Array(ty, unsafe { read(data)? }), - BtfKind::Struct => Struct(ty, unsafe { read_array(data, vlen)? }), - BtfKind::Union => Union(ty, unsafe { read_array(data, vlen)? }), - BtfKind::FuncProto => FuncProto(ty, unsafe { read_array(data, vlen)? }), - BtfKind::Var => Var(ty, unsafe { read(data)? }), - BtfKind::DataSec => DataSec(ty, unsafe { read_array(data, vlen)? }), - BtfKind::DeclTag => DeclTag(ty, unsafe { read(data)? }), - BtfKind::TypeTag => TypeTag(ty), + BtfKind::Float => BtfType::Float(Float { + name_offset: ty[0], + info: ty[1], + size: ty[2], + }), + BtfKind::Enum => BtfType::Enum(Enum { + name_offset: ty[0], + info: ty[1], + size: ty[2], + variants: unsafe { read_array::(data, vlen)? }, + }), + BtfKind::Array => BtfType::Array(Array { + name_offset: ty[0], + info: ty[1], + _unused: 0, + array: unsafe { read(data)? }, + }), + BtfKind::Struct => BtfType::Struct(Struct { + name_offset: ty[0], + info: ty[1], + size: ty[2], + members: unsafe { read_array::(data, vlen)? }, + }), + BtfKind::Union => BtfType::Union(Union { + name_offset: ty[0], + info: ty[1], + size: ty[2], + members: unsafe { read_array::(data, vlen)? }, + }), + BtfKind::FuncProto => BtfType::FuncProto(FuncProto { + name_offset: ty[0], + info: ty[1], + return_type: ty[2], + params: unsafe { read_array::(data, vlen)? }, + }), + BtfKind::Var => BtfType::Var(Var { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + linkage: unsafe { read(data)? }, + }), + BtfKind::DataSec => BtfType::DataSec(DataSec { + name_offset: ty[0], + info: ty[1], + size: ty[2], + entries: unsafe { read_array::(data, vlen)? }, + }), + BtfKind::DeclTag => BtfType::DeclTag(DeclTag { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + component_index: unsafe { read(data)? }, + }), + BtfKind::TypeTag => BtfType::TypeTag(TypeTag { + name_offset: ty[0], + info: ty[1], + btf_type: ty[2], + }), }) } pub(crate) fn to_bytes(&self) -> Vec { - fn bytes_of(val: &T) -> &[u8] { - // Safety: all btf types are POD - unsafe { crate::util::bytes_of(val) } - } match self { - BtfType::Fwd(btf_type) - | BtfType::Const(btf_type) - | BtfType::Volatile(btf_type) - | BtfType::Restrict(btf_type) - | BtfType::Ptr(btf_type) - | BtfType::Typedef(btf_type) - | BtfType::Func(btf_type) - | BtfType::Float(btf_type) - | BtfType::TypeTag(btf_type) => bytes_of::(btf_type).to_vec(), - BtfType::Int(btf_type, len) => { - let mut buf = bytes_of::(btf_type).to_vec(); - buf.append(&mut len.to_ne_bytes().to_vec()); - buf - } - BtfType::Enum(btf_type, enums) => { - let mut buf = bytes_of::(btf_type).to_vec(); - for en in enums { - buf.append(&mut bytes_of::(en).to_vec()); - } - buf - } - BtfType::Array(btf_type, btf_array) => { - let mut buf = bytes_of::(btf_type).to_vec(); - buf.append(&mut bytes_of::(btf_array).to_vec()); - buf - } - BtfType::Struct(btf_type, btf_members) | BtfType::Union(btf_type, btf_members) => { - let mut buf = bytes_of::(btf_type).to_vec(); - for m in btf_members { - buf.append(&mut bytes_of::(m).to_vec()); - } - buf - } - BtfType::FuncProto(btf_type, btf_params) => { - let mut buf = bytes_of::(btf_type).to_vec(); - for p in btf_params { - buf.append(&mut bytes_of::(p).to_vec()); - } - buf - } - BtfType::Var(btf_type, btf_var) => { - let mut buf = bytes_of::(btf_type).to_vec(); - buf.append(&mut bytes_of::(btf_var).to_vec()); - buf - } - BtfType::DataSec(btf_type, btf_var_secinfo) => { - let mut buf = bytes_of::(btf_type).to_vec(); - for s in btf_var_secinfo { - buf.append(&mut bytes_of::(s).to_vec()); - } - buf - } BtfType::Unknown => vec![], - BtfType::DeclTag(btf_type, btf_decl_tag) => { - let mut buf = bytes_of::(btf_type).to_vec(); - buf.append(&mut bytes_of::(btf_decl_tag).to_vec()); - buf - } + BtfType::Fwd(t) => t.to_bytes(), + BtfType::Const(t) => t.to_bytes(), + BtfType::Volatile(t) => t.to_bytes(), + BtfType::Restrict(t) => t.to_bytes(), + BtfType::Ptr(t) => t.to_bytes(), + BtfType::Typedef(t) => t.to_bytes(), + BtfType::Func(t) => t.to_bytes(), + BtfType::Int(t) => t.to_bytes(), + BtfType::Float(t) => t.to_bytes(), + BtfType::Enum(t) => t.to_bytes(), + BtfType::Array(t) => t.to_bytes(), + BtfType::Struct(t) => t.to_bytes(), + BtfType::Union(t) => t.to_bytes(), + BtfType::FuncProto(t) => t.to_bytes(), + BtfType::Var(t) => t.to_bytes(), + BtfType::DataSec(t) => t.to_bytes(), + BtfType::DeclTag(t) => t.to_bytes(), + BtfType::TypeTag(t) => t.to_bytes(), } } - pub(crate) fn type_info_size(&self) -> usize { - let ty_size = mem::size_of::(); - - use BtfType::*; + pub(crate) fn size(&self) -> Option { match self { - Unknown => ty_size, - Fwd(_) | Const(_) | Volatile(_) | Restrict(_) | Ptr(_) | Typedef(_) | Func(_) - | Float(_) | TypeTag(_) => ty_size, - Int(_, _) => ty_size + mem::size_of::(), - Enum(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), - Array(_, _) => ty_size + mem::size_of::(), - Struct(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), - Union(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), - FuncProto(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), - Var(_, _) => ty_size + mem::size_of::(), - DataSec(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), - DeclTag(_, _) => ty_size + mem::size_of::(), - } - } - - pub(crate) fn btf_type(&self) -> Option<&btf_type> { - use BtfType::*; - Some(match self { - Unknown => return None, - Fwd(ty) => ty, - Const(ty) => ty, - Volatile(ty) => ty, - Restrict(ty) => ty, - Ptr(ty) => ty, - Typedef(ty) => ty, - Func(ty) => ty, - Int(ty, _) => ty, - Float(ty) => ty, - Enum(ty, _) => ty, - Array(ty, _) => ty, - Struct(ty, _) => ty, - Union(ty, _) => ty, - FuncProto(ty, _) => ty, - Var(ty, _) => ty, - DataSec(ty, _) => ty, - DeclTag(ty, _) => ty, - TypeTag(ty) => ty, - }) - } - - pub(crate) fn info(&self) -> Option { - self.btf_type().map(|ty| ty.info) - } - - pub(crate) fn name_offset(&self) -> Option { - self.btf_type().map(|ty| ty.name_off) - } - - pub(crate) fn kind(&self) -> Result, BtfError> { - self.btf_type().map(type_kind).transpose() - } - - pub(crate) fn is_composite(&self) -> bool { - matches!(self, BtfType::Struct(_, _) | BtfType::Union(_, _)) - } - - pub(crate) fn new_int(name_off: u32, size: u32, encoding: u32, offset: u32) -> BtfType { - let info = (BTF_KIND_INT) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.size = size; - - let mut data = 0u32; - data |= (encoding & 0x0f) << 24; - data |= (offset & 0xff) << 16; - data |= (size * 8) & 0xff; - BtfType::Int(btf_type, data) - } - - pub(crate) fn new_func(name_off: u32, proto: u32, linkage: btf_func_linkage) -> BtfType { - let mut info = (BTF_KIND_FUNC) << 24; - info |= (linkage as u32) & 0xFFFF; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = proto; - BtfType::Func(btf_type) + BtfType::Int(t) => Some(t.size), + BtfType::Float(t) => Some(t.size), + BtfType::Enum(t) => Some(t.size), + BtfType::Struct(t) => Some(t.size), + BtfType::Union(t) => Some(t.size), + BtfType::DataSec(t) => Some(t.size), + _ => None, + } } - pub(crate) fn new_func_proto(params: Vec, return_type: u32) -> BtfType { - let mut info = (BTF_KIND_FUNC_PROTO) << 24; - info |= (params.len() as u32) & 0xFFFF; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = 0; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = return_type; - BtfType::FuncProto(btf_type, params) - } - - pub(crate) fn new_var(name_off: u32, type_: u32, linkage: u32) -> BtfType { - let info = (BTF_KIND_VAR) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - let var = btf_var { linkage }; - BtfType::Var(btf_type, var) - } - - pub(crate) fn new_datasec( - name_off: u32, - variables: Vec, - size: u32, - ) -> BtfType { - let mut info = (BTF_KIND_DATASEC) << 24; - info |= (variables.len() as u32) & 0xFFFF; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.size = size; - BtfType::DataSec(btf_type, variables) - } - - pub(crate) fn new_float(name_off: u32, size: u32) -> BtfType { - let info = (BTF_KIND_FLOAT) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.size = size; - BtfType::Float(btf_type) - } - - pub(crate) fn new_struct(name_off: u32, members: Vec, size: u32) -> BtfType { - let mut info = (BTF_KIND_STRUCT) << 24; - info |= (members.len() as u32) & 0xFFFF; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.size = size; - BtfType::Struct(btf_type, members) + pub(crate) fn btf_type(&self) -> Option { + match self { + BtfType::Const(t) => Some(t.btf_type), + BtfType::Volatile(t) => Some(t.btf_type), + BtfType::Restrict(t) => Some(t.btf_type), + BtfType::Ptr(t) => Some(t.btf_type), + BtfType::Typedef(t) => Some(t.btf_type), + // FuncProto contains the return type here, and doesn't directly reference another type + BtfType::FuncProto(t) => Some(t.return_type), + BtfType::Var(t) => Some(t.btf_type), + BtfType::DeclTag(t) => Some(t.btf_type), + BtfType::TypeTag(t) => Some(t.btf_type), + _ => None, + } } - pub(crate) fn new_enum(name_off: u32, members: Vec) -> BtfType { - let mut info = (BTF_KIND_ENUM) << 24; - info |= (members.len() as u32) & 0xFFFF; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.size = 4; - BtfType::Enum(btf_type, members) + pub(crate) fn type_info_size(&self) -> usize { + match self { + BtfType::Unknown => mem::size_of::(), + BtfType::Fwd(t) => t.type_info_size(), + BtfType::Const(t) => t.type_info_size(), + BtfType::Volatile(t) => t.type_info_size(), + BtfType::Restrict(t) => t.type_info_size(), + BtfType::Ptr(t) => t.type_info_size(), + BtfType::Typedef(t) => t.type_info_size(), + BtfType::Func(t) => t.type_info_size(), + BtfType::Int(t) => t.type_info_size(), + BtfType::Float(t) => t.type_info_size(), + BtfType::Enum(t) => t.type_info_size(), + BtfType::Array(t) => t.type_info_size(), + BtfType::Struct(t) => t.type_info_size(), + BtfType::Union(t) => t.type_info_size(), + BtfType::FuncProto(t) => t.type_info_size(), + BtfType::Var(t) => t.type_info_size(), + BtfType::DataSec(t) => t.type_info_size(), + BtfType::DeclTag(t) => t.type_info_size(), + BtfType::TypeTag(t) => t.type_info_size(), + } } - pub(crate) fn new_typedef(name_off: u32, type_: u32) -> BtfType { - let info = (BTF_KIND_TYPEDEF) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - BtfType::Typedef(btf_type) + pub(crate) fn name_offset(&self) -> u32 { + match self { + BtfType::Unknown => 0, + BtfType::Fwd(t) => t.name_offset, + BtfType::Const(t) => t.name_offset, + BtfType::Volatile(t) => t.name_offset, + BtfType::Restrict(t) => t.name_offset, + BtfType::Ptr(t) => t.name_offset, + BtfType::Typedef(t) => t.name_offset, + BtfType::Func(t) => t.name_offset, + BtfType::Int(t) => t.name_offset, + BtfType::Float(t) => t.name_offset, + BtfType::Enum(t) => t.name_offset, + BtfType::Array(t) => t.name_offset, + BtfType::Struct(t) => t.name_offset, + BtfType::Union(t) => t.name_offset, + BtfType::FuncProto(t) => t.name_offset, + BtfType::Var(t) => t.name_offset, + BtfType::DataSec(t) => t.name_offset, + BtfType::DeclTag(t) => t.name_offset, + BtfType::TypeTag(t) => t.name_offset, + } } - #[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.name_off = name_off; - btf_type.info = info; - let btf_array = btf_array { - type_, - index_type, - nelems, - }; - BtfType::Array(btf_type, btf_array) + pub(crate) fn kind(&self) -> BtfKind { + match self { + BtfType::Unknown => BtfKind::Unknown, + BtfType::Fwd(t) => t.kind(), + BtfType::Const(t) => t.kind(), + BtfType::Volatile(t) => t.kind(), + BtfType::Restrict(t) => t.kind(), + BtfType::Ptr(t) => t.kind(), + BtfType::Typedef(t) => t.kind(), + BtfType::Func(t) => t.kind(), + BtfType::Int(t) => t.kind(), + BtfType::Float(t) => t.kind(), + BtfType::Enum(t) => t.kind(), + BtfType::Array(t) => t.kind(), + BtfType::Struct(t) => t.kind(), + BtfType::Union(t) => t.kind(), + BtfType::FuncProto(t) => t.kind(), + BtfType::Var(t) => t.kind(), + BtfType::DataSec(t) => t.kind(), + BtfType::DeclTag(t) => t.kind(), + BtfType::TypeTag(t) => t.kind(), + } } - pub(crate) fn new_decl_tag(name_off: u32, type_: u32, component_idx: i32) -> BtfType { - let info = (BTF_KIND_DECL_TAG) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - let btf_decl_tag = btf_decl_tag { component_idx }; - BtfType::DeclTag(btf_type, btf_decl_tag) + pub(crate) fn is_composite(&self) -> bool { + matches!(self, BtfType::Struct(_) | BtfType::Union(_)) } - pub(crate) fn new_type_tag(name_off: u32, type_: u32) -> BtfType { - let info = (BTF_KIND_TYPE_TAG) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - BtfType::TypeTag(btf_type) + pub(crate) fn members(&self) -> Option> { + match self { + BtfType::Struct(t) => Some(t.members.iter()), + BtfType::Union(t) => Some(t.members.iter()), + _ => None, + } } - pub(crate) fn new_ptr(name_off: u32, type_: u32) -> BtfType { - let info = (BTF_KIND_PTR) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = name_off; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - BtfType::Ptr(btf_type) + pub(crate) fn member_bit_field_size(&self, member: &BtfMember) -> Option { + match self { + BtfType::Struct(t) => Some(t.member_bit_field_size(member)), + BtfType::Union(t) => Some(t.member_bit_field_size(member)), + _ => None, + } } - pub(crate) fn new_const(type_: u32) -> BtfType { - let info = (BTF_KIND_CONST) << 24; - let mut btf_type = unsafe { std::mem::zeroed::() }; - btf_type.name_off = 0; - btf_type.info = info; - btf_type.__bindgen_anon_1.type_ = type_; - BtfType::Const(btf_type) + pub(crate) fn member_bit_offset(&self, member: &BtfMember) -> Option { + match self { + BtfType::Struct(t) => Some(t.member_bit_offset(member)), + BtfType::Union(t) => Some(t.member_bit_offset(member)), + _ => None, + } } } -fn type_kind(ty: &btf_type) -> Result { - ((ty.info >> 24) & 0x1F).try_into() +fn type_kind(info: u32) -> Result { + ((info >> 24) & 0x1F).try_into() } -pub(crate) fn type_vlen(ty: &btf_type) -> usize { - (ty.info & 0xFFFF) as usize -} - -pub(crate) fn member_bit_offset(info: u32, member: &btf_member) -> usize { - let k_flag = info >> 31 == 1; - let bit_offset = if k_flag { - member.offset & 0xFFFFFF - } else { - member.offset - }; - - bit_offset as usize -} - -pub(crate) fn member_bit_field_size(ty: &btf_type, member: &btf_member) -> usize { - let k_flag = (ty.info >> 31) == 1; - let size = if k_flag { member.offset >> 24 } else { 0 }; - - size as usize +fn type_vlen(info: u32) -> usize { + (info & 0xFFFF) as usize } pub(crate) fn types_are_compatible( @@ -500,7 +1194,7 @@ pub(crate) fn types_are_compatible( let local_ty = local_btf.type_by_id(local_id)?; let target_ty = target_btf.type_by_id(target_id)?; - if local_ty.kind()? != target_ty.kind()? { + if local_ty.kind() != target_ty.kind() { return Ok(false); } @@ -510,58 +1204,52 @@ pub(crate) fn types_are_compatible( let local_ty = local_btf.type_by_id(local_id)?; let target_ty = target_btf.type_by_id(target_id)?; - if local_ty.kind()? != target_ty.kind()? { + if local_ty.kind() != target_ty.kind() { return Ok(false); } - use BtfType::*; match local_ty { - Unknown | Struct(_, _) | Union(_, _) | Enum(_, _) | Fwd(_) | Float(_) => { - return Ok(true) - } - Int(_, local_off) => { - let local_off = (local_off >> 16) & 0xFF; - if let Int(_, target_off) = target_ty { - let target_off = (target_off >> 16) & 0xFF; - return Ok(local_off == 0 && target_off == 0); + BtfType::Unknown + | BtfType::Struct(_) + | BtfType::Union(_) + | BtfType::Enum(_) + | BtfType::Fwd(_) + | BtfType::Float(_) => return Ok(true), + BtfType::Int(local) => { + if let BtfType::Int(target) = target_ty { + return Ok(local.offset() == 0 && target.offset() == 0); } } - Ptr(l_ty) => { - if let Ptr(t_ty) = target_ty { - // Safety: union - unsafe { - local_id = l_ty.__bindgen_anon_1.type_; - target_id = t_ty.__bindgen_anon_1.type_; - } + BtfType::Ptr(local) => { + if let BtfType::Ptr(target) = target_ty { + local_id = local.btf_type; + target_id = target.btf_type; continue; } } - Array(_, l_ty) => { - if let Array(_, t_ty) = target_ty { - local_id = l_ty.type_; - target_id = t_ty.type_; + BtfType::Array(Array { array: local, .. }) => { + if let BtfType::Array(Array { array: target, .. }) = target_ty { + local_id = local.element_type; + target_id = target.element_type; continue; } } - FuncProto(l_ty, l_params) => { - if let FuncProto(t_ty, t_params) = target_ty { - if l_params.len() != t_params.len() { + BtfType::FuncProto(local) => { + if let BtfType::FuncProto(target) = target_ty { + if local.params.len() != target.params.len() { return Ok(false); } - for (l_param, t_param) in l_params.iter().zip(t_params.iter()) { - let local_id = local_btf.resolve_type(l_param.type_)?; - let target_id = target_btf.resolve_type(t_param.type_)?; + for (l_param, t_param) in local.params.iter().zip(target.params.iter()) { + let local_id = local_btf.resolve_type(l_param.btf_type)?; + let target_id = target_btf.resolve_type(t_param.btf_type)?; if !types_are_compatible(local_btf, local_id, target_btf, target_id)? { return Ok(false); } } - // Safety: union - unsafe { - local_id = l_ty.__bindgen_anon_1.type_; - target_id = t_ty.__bindgen_anon_1.type_; - } + local_id = local.return_type; + target_id = target.return_type; continue; } } @@ -588,35 +1276,31 @@ pub(crate) fn fields_are_compatible( return Ok(true); } - if local_ty.kind()? != target_ty.kind()? { + if local_ty.kind() != target_ty.kind() { return Ok(false); } - use BtfType::*; match local_ty { - Fwd(_) | Enum(_, _) => { + BtfType::Fwd(_) | BtfType::Enum(_) => { let flavorless_name = |name: &str| name.split_once("___").map_or(name, |x| x.0).to_string(); - let local_name = flavorless_name(&local_btf.type_name(local_ty)?.unwrap()); - let target_name = flavorless_name(&target_btf.type_name(target_ty)?.unwrap()); + let local_name = flavorless_name(&local_btf.type_name(local_ty)?); + let target_name = flavorless_name(&target_btf.type_name(target_ty)?); return Ok(local_name == target_name); } - Int(_, local_off) => { - let local_off = (local_off >> 16) & 0xFF; - if let Int(_, target_off) = target_ty { - let target_off = (target_off >> 16) & 0xFF; - return Ok(local_off == 0 && target_off == 0); + BtfType::Int(local) => { + if let BtfType::Int(target) = target_ty { + return Ok(local.offset() == 0 && target.offset() == 0); } } - Float(_) => return Ok(true), - Ptr(_) => return Ok(true), - Array(_, l_ty) => { - if let Array(_, t_ty) = target_ty { - local_id = l_ty.type_; - target_id = t_ty.type_; - + BtfType::Float(_) => return Ok(true), + BtfType::Ptr(_) => return Ok(true), + BtfType::Array(Array { array: local, .. }) => { + if let BtfType::Array(Array { array: target, .. }) = target_ty { + local_id = local.element_type; + target_id = target.element_type; continue; } } @@ -627,30 +1311,12 @@ pub(crate) fn fields_are_compatible( Err(BtfError::MaximumTypeDepthReached { type_id: local_id }) } -impl std::fmt::Debug for btf_type { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("btf_type") - .field("name_off", &self.name_off) - .field("info", &self.info) - .field("__bindgen_anon_1", &self.__bindgen_anon_1) - .finish() - } -} - -impl std::fmt::Debug for btf_type__bindgen_ty_1 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Safety: union - f.debug_struct("btf_type__bindgen_ty_1") - .field("size", unsafe { &self.size }) - .field("type_", unsafe { &self.type_ }) - .finish() - } +fn bytes_of(val: &T) -> &[u8] { + // Safety: all btf types are POD + unsafe { crate::util::bytes_of(val) } } - #[cfg(test)] mod tests { - use crate::generated::BTF_INT_SIGNED; - use super::*; #[test] @@ -662,16 +1328,16 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Int(ty, nr_bits)) => { - assert_eq!(ty.name_off, 1); - assert_eq!(unsafe { ty.__bindgen_anon_1.size }, 8); - assert_eq!(nr_bits, 64); + Ok(BtfType::Int(new)) => { + assert_eq!(new.name_offset, 1); + assert_eq!(new.size, 8); + assert_eq!(new.bits(), 64); + let data2 = new.to_bytes(); + assert_eq!(data, data2); } Ok(t) => panic!("expected int type, got {:#?}", t), Err(_) => panic!("unexpected error"), } - let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()); } #[test] @@ -680,7 +1346,7 @@ mod tests { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ]; - let int = BtfType::new_int(1, 8, 0, 0); + let int = Int::new(1, 8, IntEncoding::None, 0); assert_eq!(int.to_bytes(), data); } @@ -690,7 +1356,7 @@ mod tests { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, ]; - let int = BtfType::new_int(0x13, 1, 0, 0); + let int = Int::new(0x13, 1, IntEncoding::None, 0); assert_eq!(int.to_bytes(), data); } @@ -700,7 +1366,7 @@ mod tests { 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, ]; - let int = BtfType::new_int(0x4a, 2, BTF_INT_SIGNED, 0); + let int = Int::new(0x4a, 2, IntEncoding::Signed, 0); assert_eq!(int.to_bytes(), data); } @@ -717,7 +1383,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -729,12 +1395,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Array(_, _)) => {} + Ok(BtfType::Array(_)) => {} Ok(t) => panic!("expected array type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -746,12 +1412,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Struct(_, _)) => {} + Ok(BtfType::Struct(_)) => {} Ok(t) => panic!("expected struct type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -763,12 +1429,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Union(_, _)) => {} + Ok(BtfType::Union(_)) => {} Ok(t) => panic!("expected union type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -780,12 +1446,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Enum(_, _)) => {} + Ok(BtfType::Enum(_)) => {} Ok(t) => panic!("expected enum type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -801,7 +1467,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -817,7 +1483,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -833,7 +1499,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -849,7 +1515,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -865,7 +1531,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -881,7 +1547,7 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -893,12 +1559,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::FuncProto(_, _)) => {} + Ok(BtfType::FuncProto(_)) => {} Ok(t) => panic!("expected func_proto type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -911,12 +1577,12 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match got { - Ok(BtfType::Var(_, _)) => {} + Ok(BtfType::Var(_)) => {} Ok(t) => panic!("expected var type, got {:#?}", t), Err(_) => panic!("unexpected error"), }; let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -928,19 +1594,17 @@ mod tests { ]; let got = unsafe { BtfType::read(data, endianness) }; match &got { - Ok(BtfType::DataSec(ty, info)) => { - assert_eq!(0, unsafe { ty.__bindgen_anon_1.size } as usize); - assert_eq!(1, type_vlen(ty) as usize); - assert_eq!(1, info.len()); - assert_eq!(11, info[0].type_); - assert_eq!(0, info[0].offset); - assert_eq!(4, info[0].size); + Ok(BtfType::DataSec(ty)) => { + assert_eq!(0, ty.size); + assert_eq!(11, ty.entries[0].btf_type); + assert_eq!(0, ty.entries[0].offset); + assert_eq!(4, ty.entries[0].size); } Ok(t) => panic!("expected datasec type, got {:#?}", t), Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] @@ -956,27 +1620,27 @@ mod tests { Err(_) => panic!("unexpected error"), } let data2 = got.unwrap().to_bytes(); - assert_eq!(data, data2.as_slice()) + assert_eq!(data, data2) } #[test] fn test_write_btf_func_proto() { let params = vec![ - btf_param { - name_off: 1, - type_: 1, + BtfParam { + name_offset: 1, + btf_type: 1, }, - btf_param { - name_off: 3, - type_: 1, + BtfParam { + name_offset: 3, + btf_type: 1, }, ]; - let func_proto = BtfType::new_func_proto(params, 2); + let func_proto = FuncProto::new(params, 2); let data = func_proto.to_bytes(); let got = unsafe { BtfType::read(&data, Endianness::default()) }; match got { - Ok(BtfType::FuncProto(btf_type, _params)) => { - assert_eq!(type_vlen(&btf_type), 2); + Ok(BtfType::FuncProto(fp)) => { + assert_eq!(fp.params.len(), 2); } Ok(t) => panic!("expected func proto type, got {:#?}", t), Err(_) => panic!("unexpected error"), @@ -987,11 +1651,11 @@ mod tests { 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 u32t = btf.add_type(BtfType::Int(Int::new(name_offset, 4, IntEncoding::None, 0))); let name_offset = btf.add_string("u64".to_string()); - let u64t = btf.add_type(BtfType::new_int(name_offset, 8, 0, 0)); + let u64t = btf.add_type(BtfType::Int(Int::new(name_offset, 8, IntEncoding::None, 0))); let name_offset = btf.add_string("widgets".to_string()); - let array_type = btf.add_type(BtfType::new_array(name_offset, u64t, u32t, 16)); + let array_type = btf.add_type(BtfType::Array(Array::new(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 diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index fafcde59..2d0b39c2 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -19,14 +19,14 @@ use relocation::*; use crate::{ bpf_map_def, - generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, btf_var_secinfo, BPF_F_RDONLY_PROG}, + generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG}, obj::btf::{Btf, BtfError, BtfExt, BtfType}, programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType}, BpfError, BtfMapDef, PinningType, }; use std::slice::from_raw_parts_mut; -use self::btf::{BtfKind, FuncSecInfo, LineSecInfo}; +use self::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo}; const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE; /// The first five __u32 of `bpf_map_def` must be defined. @@ -830,14 +830,14 @@ impl Object { let btf = self.btf.as_ref().unwrap(); for t in btf.types() { - if let BtfType::DataSec(_, sec_info) = &t { + if let BtfType::DataSec(datasec) = &t { let type_name = match btf.type_name(t) { - Ok(Some(name)) => name, + Ok(name) => name, _ => continue, }; if type_name == section.name { // each btf_var_secinfo contains a map - for info in sec_info { + for info in &datasec.entries { let (map_name, def) = parse_btf_map_def(btf, info)?; let symbol_index = symbols .get(&map_name) @@ -1144,20 +1144,20 @@ fn get_map_field(btf: &Btf, type_id: u32) -> Result { BtfType::Ptr(pty) => pty, other => { return Err(BtfError::UnexpectedBtfType { - type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32, + type_id: other.btf_type().unwrap_or(0) as u32, }) } }; // Safety: union - let arr = match &btf.type_by_id(unsafe { pty.__bindgen_anon_1.type_ })? { - BtfType::Array(_, arr) => arr, + let arr = match &btf.type_by_id(pty.btf_type)? { + BtfType::Array(Array { array, .. }) => array, other => { return Err(BtfError::UnexpectedBtfType { - type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32, + type_id: other.btf_type().unwrap_or(0) as u32, }) } }; - Ok(arr.nelems) + Ok(arr.len) } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -1226,68 +1226,71 @@ fn parse_map_def(name: &str, data: &[u8]) -> Result { } } -fn parse_btf_map_def(btf: &Btf, info: &btf_var_secinfo) -> Result<(String, BtfMapDef), BtfError> { - let ty = match btf.type_by_id(info.type_)? { - BtfType::Var(ty, _) => ty, +fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDef), BtfError> { + let ty = match btf.type_by_id(info.btf_type)? { + BtfType::Var(var) => var, other => { return Err(BtfError::UnexpectedBtfType { - type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32, + type_id: other.btf_type().unwrap_or(0) as u32, }) } }; - let map_name = btf.string_at(ty.name_off)?; + let map_name = btf.string_at(ty.name_offset)?; let mut map_def = BtfMapDef::default(); // Safety: union - let root_type = btf.resolve_type(unsafe { ty.__bindgen_anon_1.type_ })?; - let members = match btf.type_by_id(root_type)? { - BtfType::Struct(_, members) => members, + let root_type = btf.resolve_type(ty.btf_type)?; + let s = match btf.type_by_id(root_type)? { + BtfType::Struct(s) => s, other => { return Err(BtfError::UnexpectedBtfType { - type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32, + type_id: other.btf_type().unwrap_or(0) as u32, }) } }; - for m in members { - match btf.string_at(m.name_off)?.as_ref() { + for m in &s.members { + match btf.string_at(m.name_offset)?.as_ref() { "type" => { - map_def.map_type = get_map_field(btf, m.type_)?; + map_def.map_type = get_map_field(btf, m.btf_type)?; } "key" => { - if let BtfType::Ptr(pty) = btf.type_by_id(m.type_)? { + if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? { // Safety: union - let t = unsafe { pty.__bindgen_anon_1.type_ }; + let t = pty.btf_type; map_def.key_size = btf.type_size(t)? as u32; map_def.btf_key_type_id = t; } else { - return Err(BtfError::UnexpectedBtfType { type_id: m.type_ }); + return Err(BtfError::UnexpectedBtfType { + type_id: m.btf_type, + }); } } "key_size" => { - map_def.key_size = get_map_field(btf, m.type_)?; + map_def.key_size = get_map_field(btf, m.btf_type)?; } "value" => { - if let BtfType::Ptr(pty) = btf.type_by_id(m.type_)? { - // Safety: union - let t = unsafe { pty.__bindgen_anon_1.type_ }; + if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? { + let t = pty.btf_type; map_def.value_size = btf.type_size(t)? as u32; map_def.btf_value_type_id = t; } else { - return Err(BtfError::UnexpectedBtfType { type_id: m.type_ }); + return Err(BtfError::UnexpectedBtfType { + type_id: m.btf_type, + }); } } "value_size" => { - map_def.value_size = get_map_field(btf, m.type_)?; + map_def.value_size = get_map_field(btf, m.btf_type)?; } "max_entries" => { - map_def.max_entries = get_map_field(btf, m.type_)?; + map_def.max_entries = get_map_field(btf, m.btf_type)?; } "map_flags" => { - map_def.map_flags = get_map_field(btf, m.type_)?; + map_def.map_flags = get_map_field(btf, m.btf_type)?; } "pinning" => { - let pinning = get_map_field(btf, m.type_)?; + let pinning = get_map_field(btf, m.btf_type)?; map_def.pinning = PinningType::try_from(pinning).unwrap_or_else(|_| { debug!("{} is not a valid pin type. using PIN_NONE", pinning); PinningType::None diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 9243c158..5da8d89f 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -1,8 +1,12 @@ use crate::{ - generated::{ - btf_func_linkage, btf_param, btf_var_secinfo, BPF_F_REPLACE, BTF_INT_SIGNED, BTF_VAR_STATIC, + generated::BPF_F_REPLACE, + obj::{ + btf::{ + BtfParam, BtfType, DataSec, DataSecEntry, DeclTag, Float, Func, FuncLinkage, FuncProto, + Int, IntEncoding, Ptr, TypeTag, Var, VarLinkage, + }, + copy_instructions, }, - obj::{btf::BtfType, copy_instructions}, Btf, }; use libc::{c_char, c_long, close, ENOENT, ENOSPC}; @@ -546,7 +550,7 @@ pub(crate) fn is_prog_name_supported() -> bool { pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); btf.add_type(int_type); let btf_bytes = btf.to_bytes(); @@ -568,26 +572,26 @@ pub(crate) fn is_btf_supported() -> bool { pub(crate) fn is_btf_func_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let a_name = btf.add_string("a".to_string()); let b_name = btf.add_string("b".to_string()); let params = vec![ - btf_param { - name_off: a_name, - type_: int_type_id, + BtfParam { + name_offset: a_name, + btf_type: int_type_id, }, - btf_param { - name_off: b_name, - type_: int_type_id, + BtfParam { + name_offset: b_name, + btf_type: int_type_id, }, ]; - let func_proto = BtfType::new_func_proto(params, int_type_id); + let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id)); let func_proto_type_id = btf.add_type(func_proto); let add = btf.add_string("inc".to_string()); - let func = BtfType::new_func(add, func_proto_type_id, btf_func_linkage::BTF_FUNC_STATIC); + let func = BtfType::Func(Func::new(add, func_proto_type_id, FuncLinkage::Static)); btf.add_type(func); let btf_bytes = btf.to_bytes(); @@ -610,26 +614,26 @@ pub(crate) fn is_btf_func_supported() -> bool { pub(crate) fn is_btf_func_global_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let a_name = btf.add_string("a".to_string()); let b_name = btf.add_string("b".to_string()); let params = vec![ - btf_param { - name_off: a_name, - type_: int_type_id, + BtfParam { + name_offset: a_name, + btf_type: int_type_id, }, - btf_param { - name_off: b_name, - type_: int_type_id, + BtfParam { + name_offset: b_name, + btf_type: int_type_id, }, ]; - let func_proto = BtfType::new_func_proto(params, int_type_id); + let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id)); let func_proto_type_id = btf.add_type(func_proto); let add = btf.add_string("inc".to_string()); - let func = BtfType::new_func(add, func_proto_type_id, btf_func_linkage::BTF_FUNC_GLOBAL); + let func = BtfType::Func(Func::new(add, func_proto_type_id, FuncLinkage::Global)); btf.add_type(func); let btf_bytes = btf.to_bytes(); @@ -652,20 +656,20 @@ pub(crate) fn is_btf_func_global_supported() -> bool { pub(crate) fn is_btf_datasec_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let name_offset = btf.add_string("foo".to_string()); - let var_type = BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC); + let var_type = BtfType::Var(Var::new(name_offset, int_type_id, VarLinkage::Static)); let var_type_id = btf.add_type(var_type); let name_offset = btf.add_string(".data".to_string()); - let variables = vec![btf_var_secinfo { - type_: var_type_id, + let variables = vec![DataSecEntry { + btf_type: var_type_id, offset: 0, size: 4, }]; - let datasec_type = BtfType::new_datasec(name_offset, variables, 4); + let datasec_type = BtfType::DataSec(DataSec::new(name_offset, variables, 4)); btf.add_type(datasec_type); let btf_bytes = btf.to_bytes(); @@ -688,7 +692,7 @@ pub(crate) fn is_btf_datasec_supported() -> bool { pub(crate) fn is_btf_float_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("float".to_string()); - let float_type = BtfType::new_float(name_offset, 16); + let float_type = BtfType::Float(Float::new(name_offset, 16)); btf.add_type(float_type); let btf_bytes = btf.to_bytes(); @@ -711,15 +715,15 @@ pub(crate) fn is_btf_float_supported() -> bool { pub(crate) fn is_btf_decl_tag_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); - let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let name_offset = btf.add_string("foo".to_string()); - let var_type = BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC); + let var_type = BtfType::Var(Var::new(name_offset, int_type_id, VarLinkage::Static)); let var_type_id = btf.add_type(var_type); let name_offset = btf.add_string("decl_tag".to_string()); - let decl_tag = BtfType::new_decl_tag(name_offset, var_type_id, -1); + let decl_tag = BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1)); btf.add_type(decl_tag); let btf_bytes = btf.to_bytes(); @@ -742,14 +746,14 @@ pub(crate) fn is_btf_decl_tag_supported() -> bool { pub(crate) fn is_btf_type_tag_supported() -> bool { let mut btf = Btf::new(); - let int_type = BtfType::new_int(0, 4, BTF_INT_SIGNED, 0); + let int_type = BtfType::Int(Int::new(0, 4, IntEncoding::Signed, 0)); let int_type_id = btf.add_type(int_type); let name_offset = btf.add_string("int".to_string()); - let type_tag = BtfType::new_type_tag(name_offset, int_type_id); + let type_tag = BtfType::TypeTag(TypeTag::new(name_offset, int_type_id)); let type_tag_type = btf.add_type(type_tag); - btf.add_type(BtfType::new_ptr(0, type_tag_type)); + btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type))); let btf_bytes = btf.to_bytes();