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 <dave@dtucker.co.uk>
pull/176/head
Dave Tucker 3 years ago
parent d9496df3a7
commit 5f38c066db

@ -309,8 +309,8 @@ impl<'a> BpfLoader<'a> {
// fixup btf // fixup btf
let section_data = obj.section_sizes.clone(); let section_data = obj.section_sizes.clone();
let symbol_offsets = obj.symbol_offset_by_name.clone(); let symbol_offsets = obj.symbol_offset_by_name.clone();
obj_btf.fixup(&section_data, &symbol_offsets)?; let btf =
let btf = obj_btf.sanitize(&self.features)?; obj_btf.fixup_and_sanitize(&section_data, &symbol_offsets, &self.features)?;
// load btf to the kernel // load btf to the kernel
let raw_btf = btf.to_bytes(); let raw_btf = btf.to_bytes();

@ -15,7 +15,9 @@ use object::Endianness;
use thiserror::Error; use thiserror::Error;
use crate::{ 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}, obj::btf::{relocation::Relocation, BtfKind, BtfType},
util::bytes_of, util::bytes_of,
Features, Features,
@ -430,35 +432,64 @@ impl Btf {
buf buf
} }
pub(crate) fn fixup( pub(crate) fn fixup_and_sanitize(
&mut self, &mut self,
section_sizes: &HashMap<String, u64>, section_sizes: &HashMap<String, u64>,
symbol_offsets: &HashMap<String, u64>, symbol_offsets: &HashMap<String, u64>,
) -> Result<(), BtfError> { features: &Features,
let mut types = self.types.split_off(0); ) -> Result<Btf, BtfError> {
for t in &mut types { 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(); 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 { match t {
BtfType::Ptr(mut ty) => { // Fixup PTR for Rust
// Rust emits names for pointer types, which the kernel doesn't like // 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 // While I figure out if this needs fixing in the Kernel or LLVM, we'll
// do a fixup here // do a fixup here
BtfType::Ptr(ty) => {
let mut ty = *ty;
ty.name_off = 0; 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 // Start DataSec Fixups
let sec_name = self.string_at(ty.name_off)?; let sec_name = self.string_at(ty.name_off)?;
let name = sec_name.to_string(); let name = sec_name.to_string();
// There are cases when the compiler does indeed populate the // There are some cases when the compiler does indeed populate the
// size. If we hit this case, push to the types vector and // size
// continue
if unsafe { ty.__bindgen_anon_1.size > 0 } { if unsafe { ty.__bindgen_anon_1.size > 0 } {
debug!("{} {}: fixup not required", kind, name); debug!("{} {}: fixup not required", kind, name);
btf.add_type(BtfType::DataSec(*ty, data.clone()));
continue; continue;
} }
let mut ty = *ty;
// We need to get the size of the section from the ELF file // We need to get the size of the section from the ELF file
// Fortunately, we cached these when parsing it initially // Fortunately, we cached these when parsing it initially
// and we can this up by name in section_sizes // 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. // we need to get the offset from the ELF file.
// This was also cached during initial parsing and // This was also cached during initial parsing and
// we can query by name in symbol_offsets // 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_type = self.type_by_id(d.type_)?;
let var_kind = var_type.kind()?.unwrap(); let var_kind = var_type.kind()?.unwrap();
if let BtfType::Var(vty, var) = var_type { if let BtfType::Var(vty, var) = var_type {
@ -501,129 +533,83 @@ impl Btf {
return Err(BtfError::InvalidDatasec); return Err(BtfError::InvalidDatasec);
} }
} }
btf.add_type(BtfType::DataSec(ty, data));
} }
BtfType::FuncProto(_ty, params) => { // Fixup FUNC_PROTO
for (i, mut param) in params.iter_mut().enumerate() { BtfType::FuncProto(ty, params) if features.btf_func => {
if param.name_off == 0 && param.type_ != 0 { let params = params
param.name_off = self.add_string(format!("param{}", i)); .iter()
} .enumerate()
} .map(|(i, p)| {
} let name_off = if p.name_off == 0 && p.type_ != 0 {
// The type does not need fixing up btf.add_string(format!("param{}", i))
_ => {} } else {
} p.name_off
} };
self.types = types; btf_param {
Ok(()) name_off,
} type_: p.type_,
}
pub(crate) fn sanitize(&self, features: &Features) -> Result<Btf, BtfError> { })
let mut btf = Btf::new(); .collect();
btf.add_type(BtfType::FuncProto(*ty, params));
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));
}
} }
BtfType::DataSec(ty, data) => { // Sanitize FUNC_PROTO
if !features.btf_datasec { BtfType::FuncProto(ty, vars) if features.btf_func => {
debug!("{}: not supported. replacing with STRUCT", kind); debug!("{}: not supported. replacing with ENUM", kind);
let members: Vec<btf_member> = data let members: Vec<btf_enum> = vars
.iter() .iter()
.map(|p| -> btf_member { .map(|p| -> btf_enum {
let mt = self.type_by_id(p.type_).unwrap(); btf_enum {
btf_member { name_off: p.name_off,
name_off: mt.btf_type().unwrap().name_off, val: p.type_ as i32,
type_: p.type_, }
offset: p.offset * 8, })
} .collect();
}) btf.add_type(BtfType::new_enum(ty.name_off, members));
.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()));
}
} }
BtfType::FuncProto(ty, vars) => { // Sanitize FUNC
if !features.btf_func { BtfType::Func(ty) if !features.btf_func => {
debug!("{}: not supported. replacing with ENUM", kind); debug!("{}: not supported. replacing with TYPEDEF", kind);
let members: Vec<btf_enum> = vars btf.add_type(BtfType::new_typedef(ty.name_off, unsafe {
.iter() ty.__bindgen_anon_1.type_
.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()));
}
} }
BtfType::Func(mut ty) => { // Sanitize BTF_FUNC_GLOBAL
if !features.btf_func { BtfType::Func(ty) if !features.btf_func_global => {
debug!("{}: not supported. replacing with TYPEDEF", kind); let info = if type_vlen(ty) == btf_func_linkage::BTF_FUNC_GLOBAL as usize {
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
{
debug!( debug!(
"{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC", "{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC",
kind kind
); );
ty.info = (ty.info & 0xFFFF0000) (ty.info & 0xFFFF0000) | (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF
| (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF;
btf.add_type(BtfType::Func(ty));
} else { } 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) => { // Sanitize FLOAT
if !features.btf_float { BtfType::Float(ty) if !features.btf_float => {
debug!("{}: not supported. replacing with STRUCT", kind); debug!("{}: not supported. replacing with STRUCT", kind);
let struct_ty = btf.add_type(BtfType::new_struct(0, vec![], unsafe {
BtfType::new_struct(0, vec![], unsafe { ty.__bindgen_anon_1.size }); ty.__bindgen_anon_1.size
btf.add_type(struct_ty); }));
} else {
btf.add_type(BtfType::Float(*ty));
}
} }
BtfType::DeclTag(ty, btf_decl_tag) => { // Sanitize DECL_TAG
if !features.btf_decl_tag { BtfType::DeclTag(ty, _) if !features.btf_decl_tag => {
debug!("{}: not supported. replacing with INT", kind); debug!("{}: not supported. replacing with INT", kind);
let int_type = BtfType::new_int(ty.name_off, 1, 0, 0); btf.add_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));
}
} }
BtfType::TypeTag(ty) => { // Sanitize TYPE_TAG
if !features.btf_type_tag { BtfType::TypeTag(ty) if !features.btf_type_tag => {
debug!("{}: not supported. replacing with CONST", kind); debug!("{}: not supported. replacing with CONST", kind);
let const_type = BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ }); btf.add_type(BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ }));
btf.add_type(const_type);
} else {
btf.add_type(BtfType::TypeTag(*ty));
}
} }
// The type does not need sanitizing // The type does not need fixing up or sanitization
ty => { ty => {
btf.add_type(ty.clone()); btf.add_type(ty.clone());
} }
@ -1162,7 +1148,9 @@ mod tests {
for (name, features) in cases { for (name, features) in cases {
println!("[CASE] Sanitize {}", name); 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(); let raw_new_btf = new_btf.to_bytes();
Btf::parse(&raw_new_btf, Endianness::default()).unwrap(); Btf::parse(&raw_new_btf, Endianness::default()).unwrap();
} }

Loading…
Cancel
Save