|
|
|
@ -6,6 +6,7 @@ use alloc::{
|
|
|
|
|
vec::Vec,
|
|
|
|
|
};
|
|
|
|
|
use core::{
|
|
|
|
|
cell::OnceCell,
|
|
|
|
|
ffi::{CStr, FromBytesUntilNulError},
|
|
|
|
|
mem, ptr,
|
|
|
|
|
};
|
|
|
|
@ -17,8 +18,8 @@ use object::{Endianness, SectionIndex};
|
|
|
|
|
use crate::{
|
|
|
|
|
Object,
|
|
|
|
|
btf::{
|
|
|
|
|
Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int,
|
|
|
|
|
IntEncoding, LineInfo, Struct, Typedef, Union, VarLinkage,
|
|
|
|
|
Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, DataSec, DataSecEntry, Enum, Enum64,
|
|
|
|
|
FuncInfo, FuncLinkage, Int, IntEncoding, LineInfo, Struct, Typedef, Union, Var, VarLinkage,
|
|
|
|
|
info::{FuncSecInfo, LineSecInfo},
|
|
|
|
|
relocation::Relocation,
|
|
|
|
|
},
|
|
|
|
@ -170,6 +171,7 @@ pub struct BtfFeatures {
|
|
|
|
|
btf_func: bool,
|
|
|
|
|
btf_func_global: bool,
|
|
|
|
|
btf_datasec: bool,
|
|
|
|
|
btf_datasec_zero: bool,
|
|
|
|
|
btf_float: bool,
|
|
|
|
|
btf_decl_tag: bool,
|
|
|
|
|
btf_type_tag: bool,
|
|
|
|
@ -178,10 +180,12 @@ pub struct BtfFeatures {
|
|
|
|
|
|
|
|
|
|
impl BtfFeatures {
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
|
#[expect(clippy::too_many_arguments, reason = "this interface is terrible")]
|
|
|
|
|
pub fn new(
|
|
|
|
|
btf_func: bool,
|
|
|
|
|
btf_func_global: bool,
|
|
|
|
|
btf_datasec: bool,
|
|
|
|
|
btf_datasec_zero: bool,
|
|
|
|
|
btf_float: bool,
|
|
|
|
|
btf_decl_tag: bool,
|
|
|
|
|
btf_type_tag: bool,
|
|
|
|
@ -191,6 +195,7 @@ impl BtfFeatures {
|
|
|
|
|
btf_func,
|
|
|
|
|
btf_func_global,
|
|
|
|
|
btf_datasec,
|
|
|
|
|
btf_datasec_zero,
|
|
|
|
|
btf_float,
|
|
|
|
|
btf_decl_tag,
|
|
|
|
|
btf_type_tag,
|
|
|
|
@ -213,6 +218,11 @@ impl BtfFeatures {
|
|
|
|
|
self.btf_datasec
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns true if zero-length DATASec entries are accepted.
|
|
|
|
|
pub fn btf_datasec_zero(&self) -> bool {
|
|
|
|
|
self.btf_datasec_zero
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns true if the BTF_FLOAT is supported.
|
|
|
|
|
pub fn btf_float(&self) -> bool {
|
|
|
|
|
self.btf_float
|
|
|
|
@ -255,6 +265,15 @@ pub struct Btf {
|
|
|
|
|
_endianness: Endianness,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_type(header: &mut btf_header, types: &mut BtfTypes, btf_type: BtfType) -> u32 {
|
|
|
|
|
let size = btf_type.type_info_size() as u32;
|
|
|
|
|
let type_id = types.len();
|
|
|
|
|
types.push(btf_type);
|
|
|
|
|
header.type_len += size;
|
|
|
|
|
header.str_off += size;
|
|
|
|
|
type_id as u32
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Btf {
|
|
|
|
|
/// Creates a new empty instance with its header initialized
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
@ -295,12 +314,7 @@ impl Btf {
|
|
|
|
|
|
|
|
|
|
/// Adds a type to BTF metadata, returning a type id
|
|
|
|
|
pub 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(btf_type);
|
|
|
|
|
self.header.type_len += size;
|
|
|
|
|
self.header.str_off += size;
|
|
|
|
|
type_id as u32
|
|
|
|
|
add_type(&mut self.header, &mut self.types, btf_type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Loads BTF metadata from `/sys/kernel/btf/vmlinux`.
|
|
|
|
@ -486,19 +500,8 @@ impl Btf {
|
|
|
|
|
symbol_offsets: &HashMap<String, u64>,
|
|
|
|
|
features: &BtfFeatures,
|
|
|
|
|
) -> Result<(), BtfError> {
|
|
|
|
|
// ENUM64 placeholder type needs to be added before we take ownership of
|
|
|
|
|
// self.types to ensure that the offsets in the BtfHeader are correct.
|
|
|
|
|
let placeholder_name = self.add_string("enum64_placeholder");
|
|
|
|
|
let enum64_placeholder_id = (!features.btf_enum64
|
|
|
|
|
&& self.types().any(|t| t.kind() == BtfKind::Enum64))
|
|
|
|
|
.then(|| {
|
|
|
|
|
self.add_type(BtfType::Int(Int::new(
|
|
|
|
|
placeholder_name,
|
|
|
|
|
1,
|
|
|
|
|
IntEncoding::None,
|
|
|
|
|
0,
|
|
|
|
|
)))
|
|
|
|
|
});
|
|
|
|
|
let enum64_placeholder_id = OnceCell::new();
|
|
|
|
|
let filler_var_id = OnceCell::new();
|
|
|
|
|
let mut types = mem::take(&mut self.types);
|
|
|
|
|
for i in 0..types.types.len() {
|
|
|
|
|
let t = &mut types.types[i];
|
|
|
|
@ -586,8 +589,51 @@ 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.
|
|
|
|
|
let old_size = d.type_info_size();
|
|
|
|
|
let mut entries = mem::take(&mut d.entries);
|
|
|
|
|
let mut fixed_section = d.clone();
|
|
|
|
|
let mut section_size = d.size;
|
|
|
|
|
let name_offset = d.name_offset;
|
|
|
|
|
|
|
|
|
|
// Kernels before 5.12 reject zero-length DATASEC. See
|
|
|
|
|
// https://github.com/torvalds/linux/commit/13ca51d5eb358edcb673afccb48c3440b9fda21b.
|
|
|
|
|
if entries.is_empty() && !features.btf_datasec_zero {
|
|
|
|
|
let filler_var_id = *filler_var_id.get_or_init(|| {
|
|
|
|
|
let filler_type_name = self.add_string("__aya_datasec_filler_type");
|
|
|
|
|
let filler_type_id = add_type(
|
|
|
|
|
&mut self.header,
|
|
|
|
|
&mut types,
|
|
|
|
|
BtfType::Int(Int::new(
|
|
|
|
|
filler_type_name,
|
|
|
|
|
1,
|
|
|
|
|
IntEncoding::None,
|
|
|
|
|
0,
|
|
|
|
|
)),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let filler_var_name = self.add_string("__aya_datasec_filler");
|
|
|
|
|
add_type(
|
|
|
|
|
&mut self.header,
|
|
|
|
|
&mut types,
|
|
|
|
|
BtfType::Var(Var::new(
|
|
|
|
|
filler_var_name,
|
|
|
|
|
filler_type_id,
|
|
|
|
|
VarLinkage::Static,
|
|
|
|
|
)),
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
let filler_len = section_size.max(1);
|
|
|
|
|
debug!(
|
|
|
|
|
"{kind} {name}: injecting filler entry for zero-length DATASEC (len={filler_len})"
|
|
|
|
|
);
|
|
|
|
|
entries.push(DataSecEntry {
|
|
|
|
|
btf_type: filler_var_id,
|
|
|
|
|
offset: 0,
|
|
|
|
|
size: filler_len,
|
|
|
|
|
});
|
|
|
|
|
if section_size == 0 {
|
|
|
|
|
section_size = filler_len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for e in entries.iter_mut() {
|
|
|
|
|
if let BtfType::Var(var) = types.type_by_id(e.btf_type)? {
|
|
|
|
@ -611,9 +657,15 @@ impl Btf {
|
|
|
|
|
return Err(BtfError::InvalidDatasec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fixed_section.entries = entries;
|
|
|
|
|
let fixed_section = DataSec::new(name_offset, entries, section_size);
|
|
|
|
|
let new_size = fixed_section.type_info_size();
|
|
|
|
|
if new_size != old_size {
|
|
|
|
|
self.header.type_len =
|
|
|
|
|
self.header.type_len - old_size as u32 + new_size as u32;
|
|
|
|
|
self.header.str_off = self.header.type_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Must reborrow here because we borrow `types` immutably above.
|
|
|
|
|
// Must reborrow here because we borrow `types` above.
|
|
|
|
|
let t = &mut types.types[i];
|
|
|
|
|
*t = BtfType::DataSec(fixed_section);
|
|
|
|
|
}
|
|
|
|
@ -691,20 +743,44 @@ impl Btf {
|
|
|
|
|
ty.set_signed(false);
|
|
|
|
|
}
|
|
|
|
|
// Sanitize ENUM64.
|
|
|
|
|
BtfType::Enum64(ty) if !features.btf_enum64 => {
|
|
|
|
|
BtfType::Enum64(ty) => {
|
|
|
|
|
// Kernels before 6.0 do not support ENUM64. See
|
|
|
|
|
// https://github.com/torvalds/linux/commit/6089fb325cf737eeb2c4d236c94697112ca860da.
|
|
|
|
|
if !features.btf_enum64 {
|
|
|
|
|
debug!("{kind}: not supported. replacing with UNION");
|
|
|
|
|
let placeholder_id =
|
|
|
|
|
enum64_placeholder_id.expect("enum64_placeholder_id must be set");
|
|
|
|
|
let members: Vec<BtfMember> = ty
|
|
|
|
|
.variants
|
|
|
|
|
|
|
|
|
|
// `ty` is borrowed from `types` and we use that borrow
|
|
|
|
|
// below, so we must not borrow it again in the
|
|
|
|
|
// get_or_init closure.
|
|
|
|
|
let Enum64 {
|
|
|
|
|
name_offset,
|
|
|
|
|
size,
|
|
|
|
|
variants,
|
|
|
|
|
..
|
|
|
|
|
} = ty;
|
|
|
|
|
let (name_offset, size, variants) =
|
|
|
|
|
(*name_offset, *size, mem::take(variants));
|
|
|
|
|
let placeholder_id = enum64_placeholder_id.get_or_init(|| {
|
|
|
|
|
let placeholder_name = self.add_string("enum64_placeholder");
|
|
|
|
|
add_type(
|
|
|
|
|
&mut self.header,
|
|
|
|
|
&mut types,
|
|
|
|
|
BtfType::Int(Int::new(placeholder_name, 1, IntEncoding::None, 0)),
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
let members: Vec<BtfMember> = variants
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|v| BtfMember {
|
|
|
|
|
name_offset: v.name_offset,
|
|
|
|
|
btf_type: placeholder_id,
|
|
|
|
|
btf_type: *placeholder_id,
|
|
|
|
|
offset: 0,
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
*t = BtfType::Union(Union::new(ty.name_offset, members.len() as u32, members));
|
|
|
|
|
|
|
|
|
|
// Must reborrow here because we borrow `types` above.
|
|
|
|
|
let t = &mut types.types[i];
|
|
|
|
|
*t = BtfType::Union(Union::new(name_offset, size, members));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// The type does not need fixing up or sanitization.
|
|
|
|
|
_ => {}
|
|
|
|
|