Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ dialoguer = { version = "0.12", default-features = false }
diff = { version = "0.1.13", default-features = false }
env_logger = { version = "0.11", default-features = false }
epoll = { version = "4.3.3", default-features = false }
foldhash = { version = "0.2", default-features = false }
futures = { version = "0.3.28", default-features = false }
glob = { version = "0.3.0", default-features = false }
hashbrown = { version = "0.16.0", default-features = false }
Expand Down
4 changes: 4 additions & 0 deletions aya-obj/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ workspace = true

[dependencies]
bytes = { workspace = true }
# hashbrown uses foldhash for its `DefaultHasher` implementation. However,
# hashbrown doesn't expose any API allowing to create hashers with fixed seed,
# so we need to use `foldhash::FixedState` directly.
foldhash = { workspace = true }
hashbrown = { workspace = true, features = ["default-hasher", "equivalent"] }
log = { workspace = true }
object = { workspace = true, features = ["elf", "read_core"] }
Expand Down
109 changes: 108 additions & 1 deletion aya-obj/src/btf/btf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ use alloc::{
use core::{
cell::OnceCell,
ffi::{CStr, FromBytesUntilNulError},
fmt::Write as _,
hash::{BuildHasher as _, Hasher as _},
mem, ptr,
};

use bytes::BufMut as _;
use foldhash::fast::FixedState;
use log::debug;
use object::{Endianness, SectionIndex};

Expand Down Expand Up @@ -275,6 +278,42 @@ fn add_type(header: &mut btf_header, types: &mut BtfTypes, btf_type: BtfType) ->
type_id as u32
}

/// [The maximum length of a symbol accepted by the Linux kernel][name-limit]
/// according to the [`KSYM_NAME_LEN` constant][ksym-name-len]. That limit got
/// increased in [kernel 6.1][ksym-name-len-bump], but we keep the old value
/// for backwards compatibility.
///
/// [name-limit]: https://github.com/torvalds/linux/blob/v4.20/kernel/bpf/btf.c#L442-L449
/// [ksym-name-len]: https://github.com/torvalds/linux/blob/v4.20/include/linux/kallsyms.h#L17
/// [ksym-name-len-bump]: https://github.com/torvalds/linux/commit/b8a94bfb33952bb17fbc65f8903d242a721c533d
const MAX_NAME_LEN: usize = 128;

// Sanitize Rust type names to be valid C type names. Kernel does not accept
// other characters like `<`, `>` that Rust emits.
fn sanitize_type_name(name: &str) -> String {
let mut sanitized = String::with_capacity(name.len());
for byte in name.bytes() {
// Characters which are valid in C type names (alphanumeric and `_`).
if matches!(byte, b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'_') {
sanitized.push(byte as char);
} else {
write!(&mut sanitized, "_{:X}_", byte).unwrap();
}
}

if sanitized.len() > MAX_NAME_LEN {
let mut hasher = FixedState::default().build_hasher();
hasher.write(sanitized.as_bytes());
let hash = hasher.finish();
// leave space for underscore
let trim = MAX_NAME_LEN - 2 * size_of_val(&hash) - 1;
sanitized.truncate(trim);
write!(&mut sanitized, "_{:x}", hash).unwrap();
}

sanitized
}

impl Btf {
/// Creates a new empty instance with its header initialized
pub fn new() -> Self {
Expand Down Expand Up @@ -695,8 +734,16 @@ impl Btf {
}
// Sanitize FUNC.
BtfType::Func(ty) => {
// Sanitize the name.
let name = self.string_at(ty.name_offset)?;
// Sanitize FUNC.
let fixed_name = sanitize_type_name(&name);
let name = if fixed_name != name {
ty.name_offset = self.add_string(&fixed_name);
fixed_name.into()
} else {
name
};
// Adjust type and linkage according to features.
if !features.btf_func {
debug!("{kind}: not supported. replacing with TYPEDEF");
*t = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type));
Expand Down Expand Up @@ -805,6 +852,15 @@ impl Btf {
*t = BtfType::Union(Union::new(name_offset, size, members, Some(fallback)));
}
}
// Sanitize STRUCT.
BtfType::Struct(ty) => {
// Sanitize the name.
let name = self.string_at(ty.name_offset)?;
let fixed_name = sanitize_type_name(&name);
if fixed_name != name {
ty.name_offset = self.add_string(&fixed_name);
}
}
// The type does not need fixing up or sanitization.
_ => {}
}
Expand Down Expand Up @@ -1417,6 +1473,57 @@ mod tests {
assert_eq!(btf.string_at(5).unwrap(), "widget");
}

#[test]
fn test_sanitize_type_name() {
let name = "MyStruct<u64>";
assert_eq!(sanitize_type_name(name), "MyStruct_3C_u64_3E_");

let name = "MyStruct<u64, u64>";
assert_eq!(sanitize_type_name(name), "MyStruct_3C_u64_2C__20_u64_3E_");

let name = "my_function<aya_bpf::BpfContext>";
assert_eq!(
sanitize_type_name(name),
"my_function_3C_aya_bpf_3A__3A_BpfContext_3E_"
);

let name = "my_function<aya_bpf::BpfContext, aya_log_ebpf::WriteToBuf>";
assert_eq!(
sanitize_type_name(name),
"my_function_3C_aya_bpf_3A__3A_BpfContext_2C__20_aya_log_ebpf_3A__3A_WriteToBuf_3E_"
);

let name = "PerfEventArray<[u8; 32]>";
assert_eq!(
sanitize_type_name(name),
"PerfEventArray_3C__5B_u8_3B__20_32_5D__3E_"
);

let name = "my_function<aya_bpf::this::is::a::very::long::namespace::BpfContext, aya_log_ebpf::this::is::a::very::long::namespace::WriteToBuf>";
let san = sanitize_type_name(name);

#[cfg(any(
target_arch = "aarch64",
target_arch = "loongarch64",
target_arch = "powerpc64",
target_arch = "riscv64",
target_arch = "x86_64"
))]
let expected_hash = "f6a9dc7f4a53c91d";
#[cfg(target_arch = "arm")]
let expected_hash = "e203c1e6145df4dd";
#[cfg(target_arch = "s390x")]
let expected_hash = "6609fba3a8753dce";

assert_eq!(san.len(), 128);
assert_eq!(
san,
format!(
"my_function_3C_aya_bpf_3A__3A_this_3A__3A_is_3A__3A_a_3A__3A_very_3A__3A_long_3A__3A_namespace_3A__3A_BpfContex_{expected_hash}"
)
);
}

#[test]
fn test_fixup_ptr() {
let mut btf = Btf::new();
Expand Down
17 changes: 0 additions & 17 deletions ebpf/aya-ebpf/src/btf_maps/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
use core::marker::PhantomData;

pub mod array;
pub mod sk_storage;

pub use array::Array;
pub use sk_storage::SkStorage;

/// A marker used to remove names of annotated types in LLVM debug info and
/// therefore also in BTF.
#[repr(transparent)]
pub(crate) struct AyaBtfMapMarker(PhantomData<()>);

impl AyaBtfMapMarker {
pub(crate) const fn new() -> Self {
Self(PhantomData)
}
}

#[macro_export]
macro_rules! btf_map_def {
($name:ident, $t:ident) => {
Expand All @@ -30,9 +17,6 @@ macro_rules! btf_map_def {
value: *const V,
max_entries: *const [i32; M],
map_flags: *const [i32; F],

// Anonymize the struct.
_anon: $crate::btf_maps::AyaBtfMapMarker,
}

#[expect(
Expand All @@ -47,7 +31,6 @@ macro_rules! btf_map_def {
value: ::core::ptr::null(),
max_entries: ::core::ptr::null(),
map_flags: ::core::ptr::null(),
_anon: $crate::btf_maps::AyaBtfMapMarker::new(),
}
}
}
Expand Down
Loading