From 5f38c066dbd97d71790e1b886894cea4e1764fa5 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Mon, 17 Jan 2022 17:10:53 +0000 Subject: [PATCH] aya: Merge BTF Sanitize and Fixup This combines both in to one iteration. It effectively copies the ELF BTF and applies sanitizations and fixups and the original is retained. The original may still be used for relocations. Signed-off-by: Dave Tucker --- aya/src/bpf.rs | 4 +- aya/src/obj/btf/btf.rs | 242 ++++++++++++++++++++--------------------- 2 files changed, 117 insertions(+), 129 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 4f417fc0..fa044fdb 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -309,8 +309,8 @@ impl<'a> BpfLoader<'a> { // fixup btf let section_data = obj.section_sizes.clone(); let symbol_offsets = obj.symbol_offset_by_name.clone(); - obj_btf.fixup(§ion_data, &symbol_offsets)?; - let btf = obj_btf.sanitize(&self.features)?; + let btf = + obj_btf.fixup_and_sanitize(§ion_data, &symbol_offsets, &self.features)?; // load btf to the kernel let raw_btf = btf.to_bytes(); diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index ced2fbe5..7b1dc61f 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -15,7 +15,9 @@ use object::Endianness; use thiserror::Error; use crate::{ - generated::{btf_enum, btf_ext_header, btf_func_linkage, btf_header, btf_member}, + generated::{ + btf_enum, btf_ext_header, btf_func_linkage, btf_header, btf_member, btf_param, btf_type, + }, obj::btf::{relocation::Relocation, BtfKind, BtfType}, util::bytes_of, Features, @@ -430,35 +432,64 @@ impl Btf { buf } - pub(crate) fn fixup( + pub(crate) fn fixup_and_sanitize( &mut self, section_sizes: &HashMap, symbol_offsets: &HashMap, - ) -> Result<(), BtfError> { - let mut types = self.types.split_off(0); - for t in &mut types { + features: &Features, + ) -> Result { + let mut btf = Btf::new(); + btf.strings = self.strings.to_vec(); + btf.header.str_len = btf.strings.len() as u32; + + // Skip the first type as it's only there + // to make type_by_id work + for t in self.types.iter().skip(1) { let kind = t.kind()?.unwrap_or_default(); - // datasec sizes aren't set by llvm - // we need to fix them here before loading the btf to the kernel match t { - BtfType::Ptr(mut ty) => { - // Rust emits names for 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 + // 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 ty = *ty; ty.name_off = 0; + btf.add_type(BtfType::Ptr(ty)); + } + // Sanitize VAR if they are not supported + BtfType::Var(ty, _) if !features.btf_datasec => { + btf.add_type(BtfType::new_int(ty.name_off, 1, 0, 0)); } - BtfType::DataSec(mut ty, data) => { + // Sanitize DATASEC if they are not supported + BtfType::DataSec(ty, data) if !features.btf_datasec => { + debug!("{}: not supported. replacing with STRUCT", kind); + let mut members = vec![]; + for member in data { + let mt = self.type_by_id(member.type_).unwrap(); + members.push(btf_member { + name_off: mt.btf_type().unwrap().name_off, + type_: member.type_, + offset: member.offset * 8, + }) + } + btf.add_type(BtfType::new_struct(ty.name_off, members, 0)); + } + // Fixup DATASEC + // DATASEC sizes aren't set by LLVM + // We need to fix them here before loading the BTF to the kernel + BtfType::DataSec(ty, data) if features.btf_datasec => { // Start DataSec Fixups let sec_name = self.string_at(ty.name_off)?; let name = sec_name.to_string(); - // There are cases when the compiler does indeed populate the - // size. If we hit this case, push to the types vector and - // continue + // There are some cases when the compiler does indeed populate the + // size if unsafe { ty.__bindgen_anon_1.size > 0 } { debug!("{} {}: fixup not required", kind, name); + btf.add_type(BtfType::DataSec(*ty, data.clone())); continue; } + let mut ty = *ty; // We need to get the size of the section from the ELF file // Fortunately, we cached these when parsing it initially // and we can this up by name in section_sizes @@ -474,7 +505,8 @@ impl Btf { // 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 data { + let mut data = data.clone(); + for d in data.iter_mut() { let var_type = self.type_by_id(d.type_)?; let var_kind = var_type.kind()?.unwrap(); if let BtfType::Var(vty, var) = var_type { @@ -501,129 +533,83 @@ impl Btf { return Err(BtfError::InvalidDatasec); } } + btf.add_type(BtfType::DataSec(ty, data)); } - BtfType::FuncProto(_ty, params) => { - 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)); - } - } - } - // The type does not need fixing up - _ => {} - } - } - self.types = types; - Ok(()) - } - - pub(crate) fn sanitize(&self, features: &Features) -> Result { - let mut btf = Btf::new(); - - btf.strings = self.strings.to_vec(); - btf.header.str_len = btf.strings.len() as u32; - - // Skip the first type as it's only there - // to make type_by_id work - for t in &self.types[1..] { - let kind = t.kind()?.unwrap_or_default(); - match t { - BtfType::Var(ty, vars) => { - if !features.btf_datasec { - debug!("{}: not supported. replacing with INT", kind); - let int_type = BtfType::new_int(ty.name_off, 1, 0, 0); - btf.add_type(int_type); - } else { - btf.add_type(BtfType::Var(*ty, *vars)); - } + // Fixup FUNC_PROTO + BtfType::FuncProto(ty, params) if features.btf_func => { + let params = params + .iter() + .enumerate() + .map(|(i, p)| { + let name_off = if p.name_off == 0 && p.type_ != 0 { + btf.add_string(format!("param{}", i)) + } else { + p.name_off + }; + btf_param { + name_off, + type_: p.type_, + } + }) + .collect(); + btf.add_type(BtfType::FuncProto(*ty, params)); } - BtfType::DataSec(ty, data) => { - if !features.btf_datasec { - debug!("{}: not supported. replacing with STRUCT", kind); - let members: Vec = data - .iter() - .map(|p| -> btf_member { - let mt = self.type_by_id(p.type_).unwrap(); - btf_member { - name_off: mt.btf_type().unwrap().name_off, - type_: p.type_, - offset: p.offset * 8, - } - }) - .collect(); - let struct_type = BtfType::new_struct(ty.name_off, members, 0); - btf.add_type(struct_type); - } else { - btf.add_type(BtfType::DataSec(*ty, data.to_vec())); - } + // Sanitize FUNC_PROTO + BtfType::FuncProto(ty, vars) if features.btf_func => { + debug!("{}: not supported. replacing with ENUM", kind); + let members: Vec = vars + .iter() + .map(|p| -> btf_enum { + btf_enum { + name_off: p.name_off, + val: p.type_ as i32, + } + }) + .collect(); + btf.add_type(BtfType::new_enum(ty.name_off, members)); } - BtfType::FuncProto(ty, vars) => { - if !features.btf_func { - debug!("{}: not supported. replacing with ENUM", kind); - let members: Vec = vars - .iter() - .map(|p| -> btf_enum { - btf_enum { - name_off: p.name_off, - val: p.type_ as i32, - } - }) - .collect(); - let enum_type = BtfType::new_enum(ty.name_off, members); - btf.add_type(enum_type); - } else { - btf.add_type(BtfType::FuncProto(*ty, vars.to_vec())); - } + // Sanitize FUNC + BtfType::Func(ty) if !features.btf_func => { + debug!("{}: not supported. replacing with TYPEDEF", kind); + btf.add_type(BtfType::new_typedef(ty.name_off, unsafe { + ty.__bindgen_anon_1.type_ + })); } - BtfType::Func(mut 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_ }); - btf.add_type(typedef_type); - } else if type_vlen(&ty) == btf_func_linkage::BTF_FUNC_GLOBAL as usize - && !features.btf_func_global - { + // Sanitize BTF_FUNC_GLOBAL + BtfType::Func(ty) if !features.btf_func_global => { + let info = if type_vlen(ty) == btf_func_linkage::BTF_FUNC_GLOBAL as usize { debug!( "{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC", kind ); - ty.info = (ty.info & 0xFFFF0000) - | (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF; - btf.add_type(BtfType::Func(ty)); + (ty.info & 0xFFFF0000) | (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF } else { - btf.add_type(BtfType::Func(ty)); - } + ty.info + }; + btf.add_type(BtfType::Func(btf_type { + name_off: ty.name_off, + info, + __bindgen_anon_1: ty.__bindgen_anon_1, + })); } - 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 }); - btf.add_type(struct_ty); - } else { - btf.add_type(BtfType::Float(*ty)); - } + // Sanitize FLOAT + BtfType::Float(ty) if !features.btf_float => { + debug!("{}: not supported. replacing with STRUCT", kind); + btf.add_type(BtfType::new_struct(0, vec![], unsafe { + ty.__bindgen_anon_1.size + })); } - BtfType::DeclTag(ty, btf_decl_tag) => { - if !features.btf_decl_tag { - debug!("{}: not supported. replacing with INT", kind); - let int_type = BtfType::new_int(ty.name_off, 1, 0, 0); - btf.add_type(int_type); - } else { - btf.add_type(BtfType::DeclTag(*ty, *btf_decl_tag)); - } + // Sanitize DECL_TAG + BtfType::DeclTag(ty, _) if !features.btf_decl_tag => { + debug!("{}: not supported. replacing with INT", kind); + btf.add_type(BtfType::new_int(ty.name_off, 1, 0, 0)); } - 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_ }); - btf.add_type(const_type); - } else { - btf.add_type(BtfType::TypeTag(*ty)); - } + // Sanitize TYPE_TAG + BtfType::TypeTag(ty) if !features.btf_type_tag => { + debug!("{}: not supported. replacing with CONST", kind); + btf.add_type(BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ })); } - // The type does not need sanitizing + // The type does not need fixing up or sanitization ty => { btf.add_type(ty.clone()); } @@ -1162,7 +1148,9 @@ mod tests { for (name, features) in cases { println!("[CASE] Sanitize {}", name); - let new_btf = btf.sanitize(&features).unwrap(); + let new_btf = btf + .fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) + .unwrap(); let raw_new_btf = new_btf.to_bytes(); Btf::parse(&raw_new_btf, Endianness::default()).unwrap(); }