aya-obj: patch up 0-size datasec

Use OnceCell for ENUM64 while I'm here as well.
reviewable/pr1251/r58
Tamir Duberstein 7 days ago
parent 166ad2f40f
commit 7224efcad8
No known key found for this signature in database

@ -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.
_ => {}

@ -30,9 +30,9 @@ use crate::{
},
sys::{
bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_enum64_supported,
is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported,
is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported,
is_btf_datasec_supported, is_btf_datasec_zero_supported, is_btf_decl_tag_supported,
is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported,
is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported,
is_probe_read_kernel_supported, is_prog_id_supported, is_prog_name_supported,
retry_with_verifier_logs,
},
@ -66,6 +66,7 @@ fn detect_features() -> Features {
is_btf_func_supported(),
is_btf_func_global_supported(),
is_btf_datasec_supported(),
is_btf_datasec_zero_supported(),
is_btf_float_supported(),
is_btf_decl_tag_supported(),
is_btf_type_tag_supported(),

@ -1103,6 +1103,15 @@ pub(crate) fn is_btf_datasec_supported() -> bool {
bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok()
}
pub(crate) fn is_btf_datasec_zero_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string(".empty");
let datasec_type = BtfType::DataSec(DataSec::new(name_offset, Vec::new(), 0));
btf.add_type(datasec_type);
bpf_load_btf(btf.to_bytes().as_slice(), &mut [], Default::default()).is_ok()
}
pub(crate) fn is_btf_enum64_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("enum64");

@ -506,6 +506,7 @@ pub fn aya_obj::btf::BtfExt::from(t: T) -> T
pub struct aya_obj::btf::BtfFeatures
impl aya_obj::btf::BtfFeatures
pub fn aya_obj::btf::BtfFeatures::btf_datasec(&self) -> bool
pub fn aya_obj::btf::BtfFeatures::btf_datasec_zero(&self) -> bool
pub fn aya_obj::btf::BtfFeatures::btf_decl_tag(&self) -> bool
pub fn aya_obj::btf::BtfFeatures::btf_enum64(&self) -> bool
pub fn aya_obj::btf::BtfFeatures::btf_float(&self) -> bool

Loading…
Cancel
Save