diff --git a/ebpf/aya-ebpf/src/args.rs b/ebpf/aya-ebpf/src/args.rs index c67be51c..8b7f84e6 100644 --- a/ebpf/aya-ebpf/src/args.rs +++ b/ebpf/aya-ebpf/src/args.rs @@ -1,3 +1,4 @@ +use crate::bindings::bpf_raw_tracepoint_args; #[cfg(any( bpf_target_arch = "arm", bpf_target_arch = "mips", @@ -13,619 +14,305 @@ use crate::bindings::pt_regs; use crate::bindings::user_pt_regs as pt_regs; #[cfg(bpf_target_arch = "riscv64")] use crate::bindings::user_regs_struct as pt_regs; -use crate::{bindings::bpf_raw_tracepoint_args, cty::c_void, helpers::bpf_probe_read}; -/// A trait that indicates a valid type for an argument which can be coerced from a BTF -/// context. -/// -/// Users should not implement this trait. -/// -/// # Safety -/// -/// This trait is _only_ safe to implement on primitive types that can fit into -/// a `u64`. For example, integers and raw pointers may be coerced from a BTF context. -pub unsafe trait FromBtfArgument: Sized { - /// Coerces a `T` from the `n`th argument from a BTF context where `n` starts - /// at 0 and increases by 1 for each successive argument. - /// - /// # Safety - /// - /// This function is deeply unsafe, as we are reading raw pointers into kernel - /// memory. In particular, the value of `n` must not exceed the number of function - /// arguments. Moreover, `ctx` must be a valid pointer to a BTF context, and `T` must - /// be the right type for the given argument. - unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self; -} - -unsafe impl FromBtfArgument for *const T { - unsafe fn from_argument(ctx: *const c_void, n: usize) -> *const T { - // BTF arguments are exposed as an array of `usize` where `usize` can - // either be treated as a pointer or a primitive type - let ctx: *const usize = ctx.cast(); - (unsafe { *ctx.add(n) }) as _ +mod sealed { + #[expect(clippy::missing_safety_doc)] + pub unsafe trait Argument { + fn from_register(value: u64) -> Self; } -} -/// Helper macro to implement [`FromBtfArgument`] for a primitive type. -macro_rules! unsafe_impl_from_btf_argument { - ($type:ident) => { - unsafe impl FromBtfArgument for $type { - #[allow(trivial_numeric_casts)] - unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self { - // BTF arguments are exposed as an array of `usize` where `usize` can - // either be treated as a pointer or a primitive type - let ctx: *const usize = ctx.cast(); - (unsafe { *ctx.add(n) }) as _ - } + macro_rules! unsafe_impl_argument { + ($($( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )?),+ $(,)?) => { + $( + #[allow(clippy::cast_lossless, trivial_numeric_casts)] + unsafe impl$($($generics)*)? Argument for $ty $(where $($where)*)? { + fn from_register(value: u64) -> Self { + value as Self + } + } + )+ } - }; -} - -unsafe_impl_from_btf_argument!(u8); -unsafe_impl_from_btf_argument!(u16); -unsafe_impl_from_btf_argument!(u32); -unsafe_impl_from_btf_argument!(u64); -unsafe_impl_from_btf_argument!(i8); -unsafe_impl_from_btf_argument!(i16); -unsafe_impl_from_btf_argument!(i32); -unsafe_impl_from_btf_argument!(i64); -unsafe_impl_from_btf_argument!(usize); -unsafe_impl_from_btf_argument!(isize); - -pub struct PtRegs { - regs: *mut pt_regs, -} - -/// A portable wrapper around pt_regs, user_pt_regs and user_regs_struct. -impl PtRegs { - pub fn new(regs: *mut pt_regs) -> Self { - Self { regs } - } - - /// Returns the value of the register used to pass arg `n`. - pub fn arg(&self, n: usize) -> Option { - T::from_argument(unsafe { &*self.regs }, n) - } - - /// Returns the value of the register used to pass the return value. - pub fn ret(&self) -> Option { - T::from_retval(unsafe { &*self.regs }) } - /// Returns a pointer to the wrapped value. - pub fn as_ptr(&self) -> *mut pt_regs { - self.regs - } + unsafe_impl_argument!( + i8, + u8, + i16, + u16, + i32, + u32, + i64, + u64, + i128, + u128, + isize, + usize, + {} *const T {where T: 'static}, + {} *mut T {where T: 'static}, + ); } -/// A trait that indicates a valid type for an argument which can be coerced from -/// a pt_regs context. -/// -/// Any implementation of this trait is strictly architecture-specific and depends on the -/// layout of the underlying pt_regs struct and the target processor's calling -/// conventions. Users should not implement this trait. -pub trait FromPtRegs: Sized { - /// Coerces a `T` from the `n`th argument of a pt_regs context where `n` starts - /// at 0 and increases by 1 for each successive argument. - fn from_argument(ctx: &pt_regs, n: usize) -> Option; - - /// Coerces a `T` from the return value of a pt_regs context. - fn from_retval(ctx: &pt_regs) -> Option; -} +pub trait Argument: sealed::Argument {} -#[cfg(bpf_target_arch = "x86_64")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => unsafe { bpf_probe_read(&ctx.rdi).map(|v| v as *const _).ok() }, - 1 => unsafe { bpf_probe_read(&ctx.rsi).map(|v| v as *const _).ok() }, - 2 => unsafe { bpf_probe_read(&ctx.rdx).map(|v| v as *const _).ok() }, - 3 => unsafe { bpf_probe_read(&ctx.rcx).map(|v| v as *const _).ok() }, - 4 => unsafe { bpf_probe_read(&ctx.r8).map(|v| v as *const _).ok() }, - 5 => unsafe { bpf_probe_read(&ctx.r9).map(|v| v as *const _).ok() }, - _ => None, - } - } +impl Argument for T {} - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.rax).map(|v| v as *const _).ok() } - } +/// Coerces a `T` from the `n`th argument from a BTF context where `n` starts +/// at 0 and increases by 1 for each successive argument. +pub(crate) fn btf_arg(ctx: &impl crate::EbpfContext, n: usize) -> T { + // BTF arguments are exposed as an array of `usize` where `usize` can + // either be treated as a pointer or a primitive type + let ptr: *const usize = ctx.as_ptr().cast(); + let ptr = unsafe { ptr.add(n) }; + T::from_register(unsafe { *ptr as u64 }) } -#[cfg(bpf_target_arch = "arm")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 6 { - unsafe { bpf_probe_read(&ctx.uregs[n]).map(|v| v as *const _).ok() } - } else { - None - } - } +trait PtRegsLayout { + type Reg; - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.uregs[0]).map(|v| v as *const _).ok() } - } + fn arg_reg(&self, index: usize) -> Option<&Self::Reg>; + fn rc_reg(&self) -> &Self::Reg; } #[cfg(bpf_target_arch = "aarch64")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[n]).map(|v| v as *const _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[0]).map(|v| v as *const _).ok() } - } -} - -#[cfg(bpf_target_arch = "loongarch64")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[4 + n]).map(|v| v as *const _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[4]).map(|v| v as *const _).ok() } - } -} - -#[cfg(bpf_target_arch = "riscv64")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => unsafe { bpf_probe_read(&ctx.a0).map(|v| v as *const _).ok() }, - 1 => unsafe { bpf_probe_read(&ctx.a1).map(|v| v as *const _).ok() }, - 2 => unsafe { bpf_probe_read(&ctx.a2).map(|v| v as *const _).ok() }, - 3 => unsafe { bpf_probe_read(&ctx.a3).map(|v| v as *const _).ok() }, - 4 => unsafe { bpf_probe_read(&ctx.a4).map(|v| v as *const _).ok() }, - 5 => unsafe { bpf_probe_read(&ctx.a5).map(|v| v as *const _).ok() }, - 6 => unsafe { bpf_probe_read(&ctx.a6).map(|v| v as *const _).ok() }, - 7 => unsafe { bpf_probe_read(&ctx.a7).map(|v| v as *const _).ok() }, +impl PtRegsLayout for pt_regs { + type Reg = crate::bindings::__u64; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // AArch64 arguments align with libbpf's __PT_PARM{1..8}_REG (regs[0..7]). + // https://github.com/torvalds/linux/blob/v6.17/arch/arm64/include/uapi/asm/ptrace.h#L88-L93 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L229-L244 + match index { + 0..=7 => Some(&self.regs[index]), _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.ra).map(|v| v as *const _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (regs[0]/x0). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L248-L251 + &self.regs[0] } } -#[cfg(bpf_target_arch = "powerpc64")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.gpr[3 + n]).map(|v| v as *const _).ok() } - } else { - None +#[cfg(bpf_target_arch = "arm")] +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_long; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // ARM arguments follow libbpf's __PT_PARM{1..7}_REG mapping (uregs[0..6]). + // https://github.com/torvalds/linux/blob/v6.17/arch/arm/include/uapi/asm/ptrace.h#L124-L152 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L198-L210 + match index { + 0..=6 => Some(&self.uregs[index]), + _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.gpr[3]).map(|v| v as *const _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (uregs[0]). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L211-L214 + &self.uregs[0] } } -#[cfg(bpf_target_arch = "s390x")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 4 { - unsafe { bpf_probe_read(&ctx.gprs[2 + n]).map(|v| v as *const _).ok() } - } else { - None +#[cfg(bpf_target_arch = "loongarch64")] +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_ulong; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // LoongArch arguments correspond to libbpf's __PT_PARM{1..8}_REG (regs[4..11]). + // https://github.com/torvalds/linux/blob/v6.17/arch/loongarch/include/asm/ptrace.h#L20-L33 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L427-L444 + match index { + 0..=7 => Some(&self.regs[4 + index]), + _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.gprs[2]).map(|v| v as *const _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (regs[4], a0). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L445-L447 + &self.regs[4] } } #[cfg(bpf_target_arch = "mips")] -impl FromPtRegs for *const T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - // Assume N64 ABI like libbpf does. - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[n + 4]).map(|v| v as *const _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[31]).map(|v| v as *const _).ok() } - } -} - -#[cfg(bpf_target_arch = "x86_64")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => unsafe { bpf_probe_read(&ctx.rdi).map(|v| v as *mut _).ok() }, - 1 => unsafe { bpf_probe_read(&ctx.rsi).map(|v| v as *mut _).ok() }, - 2 => unsafe { bpf_probe_read(&ctx.rdx).map(|v| v as *mut _).ok() }, - 3 => unsafe { bpf_probe_read(&ctx.rcx).map(|v| v as *mut _).ok() }, - 4 => unsafe { bpf_probe_read(&ctx.r8).map(|v| v as *mut _).ok() }, - 5 => unsafe { bpf_probe_read(&ctx.r9).map(|v| v as *mut _).ok() }, +impl PtRegsLayout for pt_regs { + type Reg = crate::bindings::__u64; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // MIPS N64 arguments correspond to libbpf's __PT_PARM{1..8}_REG (regs[4..11]). + // https://github.com/torvalds/linux/blob/v6.17/arch/mips/include/asm/ptrace.h#L28-L52 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L261-L275 + match index { + 0..=7 => Some(&self.regs[4 + index]), _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.rax).map(|v| v as *mut _).ok() } - } -} - -#[cfg(bpf_target_arch = "arm")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 6 { - unsafe { bpf_probe_read(&ctx.uregs[n]).map(|v| v as *mut _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.uregs[0]).map(|v| v as *mut _).ok() } - } -} - -#[cfg(bpf_target_arch = "aarch64")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[n]).map(|v| v as *mut _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[0]).map(|v| v as *mut _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (regs[2], which aliases MIPS $v0). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L277-L279 + &self.regs[2] } } -#[cfg(bpf_target_arch = "loongarch64")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[4 + n]).map(|v| v as *mut _).ok() } - } else { - None +#[cfg(bpf_target_arch = "powerpc64")] +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_ulong; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // PowerPC64 arguments follow libbpf's __PT_PARM{1..8}_REG (gpr[3..10]). + // https://github.com/torvalds/linux/blob/v6.17/arch/powerpc/include/asm/ptrace.h#L28-L56 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L290-L308 + match index { + 0..=7 => Some(&self.gpr[3 + index]), + _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[4]).map(|v| v as *mut _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (gpr[3]). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L311-L314 + &self.gpr[3] } } #[cfg(bpf_target_arch = "riscv64")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => unsafe { bpf_probe_read(&ctx.a0).map(|v| v as *mut _).ok() }, - 1 => unsafe { bpf_probe_read(&ctx.a1).map(|v| v as *mut _).ok() }, - 2 => unsafe { bpf_probe_read(&ctx.a2).map(|v| v as *mut _).ok() }, - 3 => unsafe { bpf_probe_read(&ctx.a3).map(|v| v as *mut _).ok() }, - 4 => unsafe { bpf_probe_read(&ctx.a4).map(|v| v as *mut _).ok() }, - 5 => unsafe { bpf_probe_read(&ctx.a5).map(|v| v as *mut _).ok() }, - 6 => unsafe { bpf_probe_read(&ctx.a6).map(|v| v as *mut _).ok() }, - 7 => unsafe { bpf_probe_read(&ctx.a7).map(|v| v as *mut _).ok() }, +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_ulong; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // RISC-V arguments track libbpf's __PT_PARM{1..8}_REG (a0-a7). + // https://github.com/torvalds/linux/blob/v6.17/arch/riscv/include/asm/ptrace.h#L15-L55 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L360-L376 + match index { + 0 => Some(&self.a0), + 1 => Some(&self.a1), + 2 => Some(&self.a2), + 3 => Some(&self.a3), + 4 => Some(&self.a4), + 5 => Some(&self.a5), + 6 => Some(&self.a6), + 7 => Some(&self.a7), _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.ra).map(|v| v as *mut _).ok() } - } -} - -#[cfg(bpf_target_arch = "powerpc64")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - unsafe { bpf_probe_read(&ctx.gpr[3 + n]).map(|v| v as *mut _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.gpr[3]).map(|v| v as *mut _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (a0). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L379-L382 + &self.a0 } } #[cfg(bpf_target_arch = "s390x")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 4 { - unsafe { bpf_probe_read(&ctx.gprs[2 + n]).map(|v| v as *mut _).ok() } - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.gprs[2]).map(|v| v as *mut _).ok() } - } -} - -#[cfg(bpf_target_arch = "mips")] -impl FromPtRegs for *mut T { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - // Assume N64 ABI like libbpf does. - if n <= 7 { - unsafe { bpf_probe_read(&ctx.regs[n + 4]).map(|v| v as *mut _).ok() } - } else { - None +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_ulong; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // s390 arguments match libbpf's __PT_PARM{1..5}_REG (gprs[2..6]). + // https://github.com/torvalds/linux/blob/v6.17/arch/s390/include/asm/ptrace.h#L111-L131 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L170-L181 + match index { + 0..=4 => Some(&self.gprs[2 + index]), + _ => None, } } - fn from_retval(ctx: &pt_regs) -> Option { - unsafe { bpf_probe_read(&ctx.regs[31]).map(|v| v as *mut _).ok() } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (gprs[2]). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L186-L188 + &self.gprs[2] } } -/// Helper macro to implement [`FromPtRegs`] for a primitive type. -macro_rules! impl_from_pt_regs { - ($type:ident) => { - #[cfg(bpf_target_arch = "x86_64")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => Some(ctx.rdi as *const $type as _), - 1 => Some(ctx.rsi as *const $type as _), - 2 => Some(ctx.rdx as *const $type as _), - 3 => Some(ctx.rcx as *const $type as _), - 4 => Some(ctx.r8 as *const $type as _), - 5 => Some(ctx.r9 as *const $type as _), - _ => None, - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.rax as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "arm")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 6 { - Some(ctx.uregs[n] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.uregs[0] as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "aarch64")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - Some(ctx.regs[n] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.regs[0] as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "loongarch64")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - Some(ctx.regs[4 + n] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.regs[4] as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "riscv64")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - match n { - 0 => Some(ctx.a0 as *const $type as _), - 1 => Some(ctx.a1 as *const $type as _), - 2 => Some(ctx.a2 as *const $type as _), - 3 => Some(ctx.a3 as *const $type as _), - 4 => Some(ctx.a4 as *const $type as _), - 5 => Some(ctx.a5 as *const $type as _), - 6 => Some(ctx.a6 as *const $type as _), - 7 => Some(ctx.a7 as *const $type as _), - _ => None, - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.ra as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "powerpc64")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - Some(ctx.gpr[3 + n] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.gpr[3] as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "s390x")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 4 { - Some(ctx.gprs[2 + n] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.gprs[2] as *const $type as _) - } - } - - #[cfg(bpf_target_arch = "mips")] - impl FromPtRegs for $type { - fn from_argument(ctx: &pt_regs, n: usize) -> Option { - if n <= 7 { - Some(ctx.regs[n + 4] as *const $type as _) - } else { - None - } - } - - fn from_retval(ctx: &pt_regs) -> Option { - Some(ctx.regs[31] as *const $type as _) - } +#[cfg(bpf_target_arch = "x86_64")] +impl PtRegsLayout for pt_regs { + type Reg = crate::cty::c_ulong; + + fn arg_reg(&self, index: usize) -> Option<&Self::Reg> { + // x86-64 arguments mirror libbpf's __PT_PARM{1..6}_REG mapping (rdi, rsi, rdx, rcx, r8, r9). + // https://github.com/torvalds/linux/blob/v6.17/arch/x86/include/asm/ptrace.h#L103-L155 + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L134-L152 + match index { + 0 => Some(&self.rdi), + 1 => Some(&self.rsi), + 2 => Some(&self.rdx), + 3 => Some(&self.rcx), + 4 => Some(&self.r8), + 5 => Some(&self.r9), + _ => None, } - }; -} - -impl_from_pt_regs!(u8); -impl_from_pt_regs!(u16); -impl_from_pt_regs!(u32); -impl_from_pt_regs!(u64); -impl_from_pt_regs!(i8); -impl_from_pt_regs!(i16); -impl_from_pt_regs!(i32); -impl_from_pt_regs!(i64); -impl_from_pt_regs!(usize); -impl_from_pt_regs!(isize); - -/// A Rust wrapper on `bpf_raw_tracepoint_args`. -pub struct RawTracepointArgs { - args: *mut bpf_raw_tracepoint_args, -} - -impl RawTracepointArgs { - /// Creates a new instance of `RawTracepointArgs` from the given - /// `bpf_raw_tracepoint_args` raw pointer to allow easier access - /// to raw tracepoint argumetns. - pub fn new(args: *mut bpf_raw_tracepoint_args) -> Self { - Self { args } } - /// Returns the n-th argument of the raw tracepoint. - /// - /// # Safety - /// - /// This method is unsafe because it performs raw pointer conversion and makes assumptions - /// about the structure of the `bpf_raw_tracepoint_args` type. The tracepoint arguments are - /// represented as an array of `__u64` values. To be precise, the wrapped - /// `bpf_raw_tracepoint_args` binding defines it as `__IncompleteArrayField<__u64>` and the - /// original C type as `__u64 args[0]`. This method provides a way to access these arguments - /// conveniently in Rust using `__IncompleteArrayField::as_slice` to represent that array - /// as a slice of length n and then retrieve the n-th element of it. - /// - /// However, the method does not check the total number of available arguments for a given - /// tracepoint and assumes that the slice has at least `n` elements, leading to undefined - /// behavior if this condition is not met. Such check is impossible to do, because the - /// tracepoint context doesn't contain any information about number of arguments. - /// - /// This method also cannot guarantee that the requested type matches the actual value type. - /// Wrong assumptions about types can lead to undefined behavior. The tracepoint context - /// doesn't provide any type information. - /// - /// The caller is responsible for ensuring they have accurate knowledge of the arguments - /// and their respective types for the accessed tracepoint context. - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(&*self.args, n) } + fn rc_reg(&self) -> &Self::Reg { + // Return codes use libbpf's __PT_RC_REG (rax). + // https://github.com/torvalds/linux/blob/v6.17/tools/lib/bpf/bpf_tracing.h#L148-L152 + &self.rax } } -#[expect(clippy::missing_safety_doc)] -pub unsafe trait FromRawTracepointArgs: Sized { - /// Returns the n-th argument of the raw tracepoint. - /// - /// # Safety - /// - /// This method is unsafe because it performs raw pointer conversion and makes assumptions - /// about the structure of the `bpf_raw_tracepoint_args` type. The tracepoint arguments are - /// represented as an array of `__u64` values. To be precise, the wrapped - /// `bpf_raw_tracepoint_args` binding defines it as `__IncompleteArrayField<__u64>` and the - /// original C type as `__u64 args[0]`. This method provides a way to access these arguments - /// conveniently in Rust using `__IncompleteArrayField::as_slice` to represent that array - /// as a slice of length n and then retrieve the n-th element of it. - /// - /// However, the method does not check the total number of available arguments for a given - /// tracepoint and assumes that the slice has at least `n` elements, leading to undefined - /// behavior if this condition is not met. Such check is impossible to do, because the - /// tracepoint context doesn't contain any information about number of arguments. - /// - /// This method also cannot guarantee that the requested type matches the actual value type. - /// Wrong assumptions about types can lead to undefined behavior. The tracepoint context - /// doesn't provide any type information. - /// - /// The caller is responsible for ensuring they have accurate knowledge of the arguments - /// and their respective types for the accessed tracepoint context. - unsafe fn from_argument(ctx: &bpf_raw_tracepoint_args, n: usize) -> Self; +/// Coerces a `T` from the `n`th argument of a pt_regs context where `n` starts +/// at 0 and increases by 1 for each successive argument. +pub(crate) fn arg(ctx: &pt_regs, n: usize) -> Option { + let reg = ctx.arg_reg(n)?; + #[allow( + clippy::cast_sign_loss, + clippy::unnecessary_cast, + trivial_numeric_casts + )] + Some(T::from_register((*reg) as u64)) } -unsafe impl FromRawTracepointArgs for *const T { - unsafe fn from_argument(ctx: &bpf_raw_tracepoint_args, n: usize) -> *const T { - // Raw tracepoint arguments are exposed as `__u64 args[0]`. - // https://elixir.bootlin.com/linux/v6.5.5/source/include/uapi/linux/bpf.h#L6829 - // They are represented as `__IncompleteArrayField` in the Rust - // wraapper. - // - // The most convenient way of accessing such type in Rust is to use - // `__IncompleteArrayField::as_slice` to represent that array as a - // slice of length n and then retrieve the n-th element of it. - // - // We don't know how many arguments are there for the given tracepoint, - // so we just assume that the slice has at least n elements. The whole - // assumntion and implementation is unsafe. - (unsafe { ctx.args.as_slice(n + 1) })[n] as _ - } +/// Coerces a `T` from the return value of a pt_regs context. +pub(crate) fn ret(ctx: &pt_regs) -> T { + let reg = ctx.rc_reg(); + #[allow( + clippy::cast_sign_loss, + clippy::unnecessary_cast, + trivial_numeric_casts + )] + T::from_register((*reg) as u64) } -macro_rules! unsafe_impl_from_raw_tracepoint_args { - ($type:ident) => { - unsafe impl FromRawTracepointArgs for $type { - #[allow(trivial_numeric_casts)] - unsafe fn from_argument(ctx: &bpf_raw_tracepoint_args, n: usize) -> Self { - (unsafe { ctx.args.as_slice(n + 1) })[n] as _ - } - } - }; +/// Returns the n-th argument of the raw tracepoint. +/// +/// # Safety +/// +/// This method is unsafe because it performs raw pointer conversion and makes assumptions +/// about the structure of the `bpf_raw_tracepoint_args` type. The tracepoint arguments are +/// represented as an array of `__u64` values. To be precise, the wrapped +/// `bpf_raw_tracepoint_args` binding defines it as `__IncompleteArrayField<__u64>` and the +/// original C type as `__u64 args[0]`. This method provides a way to access these arguments +/// conveniently in Rust using `__IncompleteArrayField::as_slice` to represent that array +/// as a slice of length n and then retrieve the n-th element of it. +/// +/// However, the method does not check the total number of available arguments for a given +/// tracepoint and assumes that the slice has at least `n` elements, leading to undefined +/// behavior if this condition is not met. Such check is impossible to do, because the +/// tracepoint context doesn't contain any information about number of arguments. +/// +/// This method also cannot guarantee that the requested type matches the actual value type. +/// Wrong assumptions about types can lead to undefined behavior. The tracepoint context +/// doesn't provide any type information. +/// +/// The caller is responsible for ensuring they have accurate knowledge of the arguments +/// and their respective types for the accessed tracepoint context. +pub(crate) fn raw_tracepoint_arg(ctx: &bpf_raw_tracepoint_args, n: usize) -> T { + // Raw tracepoint arguments are exposed as `__u64 args[0]`. + // https://github.com/torvalds/linux/blob/v6.17/include/uapi/linux/bpf.h#L7231-L7233 + // They are represented as `__IncompleteArrayField` in the Rust + // wrapper. + // + // The most convenient way of accessing such type in Rust is to use + // `__IncompleteArrayField::as_slice` to represent that array as a + // slice of length n and then retrieve the n-th element of it. + // + // We don't know how many arguments are there for the given tracepoint, + // so we just assume that the slice has at least n elements. The whole + // assumption and implementation is unsafe. + let ptr = ctx.args.as_ptr(); + let ptr = unsafe { ptr.add(n) }; + T::from_register(unsafe { *ptr }) } - -unsafe_impl_from_raw_tracepoint_args!(u8); -unsafe_impl_from_raw_tracepoint_args!(u16); -unsafe_impl_from_raw_tracepoint_args!(u32); -unsafe_impl_from_raw_tracepoint_args!(u64); -unsafe_impl_from_raw_tracepoint_args!(i8); -unsafe_impl_from_raw_tracepoint_args!(i16); -unsafe_impl_from_raw_tracepoint_args!(i32); -unsafe_impl_from_raw_tracepoint_args!(i64); -unsafe_impl_from_raw_tracepoint_args!(usize); -unsafe_impl_from_raw_tracepoint_args!(isize); diff --git a/ebpf/aya-ebpf/src/lib.rs b/ebpf/aya-ebpf/src/lib.rs index da969290..9b0d14c2 100644 --- a/ebpf/aya-ebpf/src/lib.rs +++ b/ebpf/aya-ebpf/src/lib.rs @@ -26,7 +26,7 @@ pub use aya_ebpf_bindings::bindings; mod args; -pub use args::{PtRegs, RawTracepointArgs}; +pub use args::Argument; pub mod btf_maps; #[expect(clippy::missing_safety_doc, unsafe_op_in_unsafe_fn)] pub mod helpers; diff --git a/ebpf/aya-ebpf/src/programs/fentry.rs b/ebpf/aya-ebpf/src/programs/fentry.rs index 99355264..b67fb35c 100644 --- a/ebpf/aya-ebpf/src/programs/fentry.rs +++ b/ebpf/aya-ebpf/src/programs/fentry.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use crate::{EbpfContext, args::FromBtfArgument}; +use crate::{Argument, EbpfContext, args::btf_arg}; pub struct FEntryContext { ctx: *mut c_void, @@ -31,9 +31,8 @@ impl FEntryContext { /// Ok(0) /// } /// ``` - #[expect(clippy::missing_safety_doc)] - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(self.ctx.cast(), n) } + pub fn arg(&self, n: usize) -> T { + btf_arg(self, n) } } diff --git a/ebpf/aya-ebpf/src/programs/fexit.rs b/ebpf/aya-ebpf/src/programs/fexit.rs index f752ffb9..20a4c3b5 100644 --- a/ebpf/aya-ebpf/src/programs/fexit.rs +++ b/ebpf/aya-ebpf/src/programs/fexit.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use crate::{EbpfContext, args::FromBtfArgument}; +use crate::{Argument, EbpfContext, args::btf_arg}; pub struct FExitContext { ctx: *mut c_void, @@ -31,9 +31,8 @@ impl FExitContext { /// Ok(0) /// } /// ``` - #[expect(clippy::missing_safety_doc)] - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(self.ctx.cast(), n) } + pub fn arg(&self, n: usize) -> T { + btf_arg(self, n) } } diff --git a/ebpf/aya-ebpf/src/programs/lsm.rs b/ebpf/aya-ebpf/src/programs/lsm.rs index 4395f4b1..741aa1b6 100644 --- a/ebpf/aya-ebpf/src/programs/lsm.rs +++ b/ebpf/aya-ebpf/src/programs/lsm.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use crate::{EbpfContext, args::FromBtfArgument}; +use crate::{Argument, EbpfContext, args::btf_arg}; pub struct LsmContext { ctx: *mut c_void, @@ -22,12 +22,6 @@ impl LsmContext { /// this code path, or 0 if this is the first LSM program to be called. This phony /// argument is always last in the argument list. /// - /// # Safety - /// - /// This function is deeply unsafe, as we are reading raw pointers into kernel memory. - /// In particular, the value of `n` must not exceed the number of function arguments. - /// Luckily, the BPF verifier will catch this for us. - /// /// # Examples /// /// ```no_run @@ -52,8 +46,8 @@ impl LsmContext { /// ``` /// /// [1]: https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hook_defs.h - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(self.ctx.cast(), n) } + pub fn arg(&self, n: usize) -> T { + btf_arg(self, n) } } diff --git a/ebpf/aya-ebpf/src/programs/probe.rs b/ebpf/aya-ebpf/src/programs/probe.rs index 461164fd..19390931 100644 --- a/ebpf/aya-ebpf/src/programs/probe.rs +++ b/ebpf/aya-ebpf/src/programs/probe.rs @@ -15,7 +15,7 @@ use crate::bindings::pt_regs; use crate::bindings::user_pt_regs as pt_regs; #[cfg(bpf_target_arch = "riscv64")] use crate::bindings::user_regs_struct as pt_regs; -use crate::{EbpfContext, args::FromPtRegs}; +use crate::{Argument, EbpfContext, args::arg}; pub struct ProbeContext { pub regs: *mut pt_regs, @@ -47,8 +47,8 @@ impl ProbeContext { /// Ok(0) /// } /// ``` - pub fn arg(&self, n: usize) -> Option { - T::from_argument(unsafe { &*self.regs }, n) + pub fn arg(&self, n: usize) -> Option { + arg(unsafe { &*self.regs }, n) } } diff --git a/ebpf/aya-ebpf/src/programs/raw_tracepoint.rs b/ebpf/aya-ebpf/src/programs/raw_tracepoint.rs index 3a1b1746..81bcf54c 100644 --- a/ebpf/aya-ebpf/src/programs/raw_tracepoint.rs +++ b/ebpf/aya-ebpf/src/programs/raw_tracepoint.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use crate::{EbpfContext, args::FromRawTracepointArgs, bindings::bpf_raw_tracepoint_args}; +use crate::{Argument, EbpfContext, args::raw_tracepoint_arg, bindings::bpf_raw_tracepoint_args}; pub struct RawTracePointContext { ctx: *mut bpf_raw_tracepoint_args, @@ -11,9 +11,8 @@ impl RawTracePointContext { Self { ctx: ctx.cast() } } - #[expect(clippy::missing_safety_doc)] - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(&*self.ctx, n) } + pub fn arg(&self, n: usize) -> T { + raw_tracepoint_arg(unsafe { &*self.ctx }, n) } } diff --git a/ebpf/aya-ebpf/src/programs/retprobe.rs b/ebpf/aya-ebpf/src/programs/retprobe.rs index e3d83ad6..5902033d 100644 --- a/ebpf/aya-ebpf/src/programs/retprobe.rs +++ b/ebpf/aya-ebpf/src/programs/retprobe.rs @@ -15,7 +15,7 @@ use crate::bindings::pt_regs; use crate::bindings::user_pt_regs as pt_regs; #[cfg(bpf_target_arch = "riscv64")] use crate::bindings::user_regs_struct as pt_regs; -use crate::{EbpfContext, args::FromPtRegs}; +use crate::{Argument, EbpfContext, args::ret}; pub struct RetProbeContext { pub regs: *mut pt_regs, @@ -34,15 +34,15 @@ impl RetProbeContext { /// # #![expect(dead_code)] /// # use aya_ebpf::{programs::RetProbeContext, cty::c_int}; /// unsafe fn try_kretprobe_try_to_wake_up(ctx: RetProbeContext) -> Result { - /// let retval: c_int = ctx.ret().ok_or(1u32)?; + /// let retval: c_int = ctx.ret(); /// /// // Do something with retval /// /// Ok(0) /// } /// ``` - pub fn ret(&self) -> Option { - T::from_retval(unsafe { &*self.regs }) + pub fn ret(&self) -> T { + ret(unsafe { &*self.regs }) } } diff --git a/ebpf/aya-ebpf/src/programs/tp_btf.rs b/ebpf/aya-ebpf/src/programs/tp_btf.rs index 43b72da7..9e39f2f0 100644 --- a/ebpf/aya-ebpf/src/programs/tp_btf.rs +++ b/ebpf/aya-ebpf/src/programs/tp_btf.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; -use crate::{EbpfContext, args::FromBtfArgument}; +use crate::{Argument, EbpfContext, args::btf_arg}; pub struct BtfTracePointContext { ctx: *mut c_void, @@ -16,12 +16,6 @@ impl BtfTracePointContext { /// You can use the tplist tool provided by bcc to get a list of tracepoints and their /// arguments. TODO: document this better, possibly add a tplist alternative to aya. /// - /// # Safety - /// - /// This function is deeply unsafe, as we are reading raw pointers into kernel memory. - /// In particular, the value of `n` must not exceed the number of function arguments. - /// Luckily, the BPF verifier will catch this for us. - /// /// # Examples /// /// ```no_run @@ -42,8 +36,8 @@ impl BtfTracePointContext { /// ``` /// /// [1]: https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hook_defs.h - pub unsafe fn arg(&self, n: usize) -> T { - unsafe { T::from_argument(self.ctx.cast(), n) } + pub fn arg(&self, n: usize) -> T { + btf_arg(self, n) } } diff --git a/test/integration-ebpf/src/raw_tracepoint.rs b/test/integration-ebpf/src/raw_tracepoint.rs index 1590a8a0..1c371c6a 100644 --- a/test/integration-ebpf/src/raw_tracepoint.rs +++ b/test/integration-ebpf/src/raw_tracepoint.rs @@ -16,8 +16,8 @@ static RESULT: Array = Array::with_max_entries(1, 0); #[raw_tracepoint(tracepoint = "sys_enter")] fn sys_enter(ctx: RawTracePointContext) -> i32 { - let common_type: u16 = unsafe { ctx.arg(0) }; - let common_flags: u8 = unsafe { ctx.arg(1) }; + let common_type: u16 = ctx.arg(0); + let common_flags: u8 = ctx.arg(1); if let Some(ptr) = RESULT.get_ptr_mut(0) { unsafe { diff --git a/xtask/public-api/aya-ebpf.txt b/xtask/public-api/aya-ebpf.txt index ea62c132..a181601e 100644 --- a/xtask/public-api/aya-ebpf.txt +++ b/xtask/public-api/aya-ebpf.txt @@ -1603,7 +1603,7 @@ pub fn aya_ebpf::programs::device::DeviceContext::from(t: T) -> T pub mod aya_ebpf::programs::fentry pub struct aya_ebpf::programs::fentry::FEntryContext impl aya_ebpf::programs::fentry::FEntryContext -pub unsafe fn aya_ebpf::programs::fentry::FEntryContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::fentry::FEntryContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::fentry::FEntryContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::fentry::FEntryContext pub fn aya_ebpf::programs::fentry::FEntryContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -1632,7 +1632,7 @@ pub fn aya_ebpf::programs::fentry::FEntryContext::from(t: T) -> T pub mod aya_ebpf::programs::fexit pub struct aya_ebpf::programs::fexit::FExitContext impl aya_ebpf::programs::fexit::FExitContext -pub unsafe fn aya_ebpf::programs::fexit::FExitContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::fexit::FExitContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::fexit::FExitContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::fexit::FExitContext pub fn aya_ebpf::programs::fexit::FExitContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -1693,7 +1693,7 @@ pub fn aya_ebpf::programs::flow_dissector::FlowDissectorContext::from(t: T) -> T pub mod aya_ebpf::programs::lsm pub struct aya_ebpf::programs::lsm::LsmContext impl aya_ebpf::programs::lsm::LsmContext -pub unsafe fn aya_ebpf::programs::lsm::LsmContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::lsm::LsmContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::lsm::LsmContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::lsm::LsmContext pub fn aya_ebpf::programs::lsm::LsmContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -1751,7 +1751,7 @@ pub mod aya_ebpf::programs::probe pub struct aya_ebpf::programs::probe::ProbeContext pub aya_ebpf::programs::probe::ProbeContext::regs: *mut aya_ebpf_bindings::x86_64::bindings::pt_regs impl aya_ebpf::programs::probe::ProbeContext -pub fn aya_ebpf::programs::probe::ProbeContext::arg(&self, n: usize) -> core::option::Option +pub fn aya_ebpf::programs::probe::ProbeContext::arg(&self, n: usize) -> core::option::Option pub fn aya_ebpf::programs::probe::ProbeContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::probe::ProbeContext pub fn aya_ebpf::programs::probe::ProbeContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -1780,7 +1780,7 @@ pub fn aya_ebpf::programs::probe::ProbeContext::from(t: T) -> T pub mod aya_ebpf::programs::raw_tracepoint pub struct aya_ebpf::programs::raw_tracepoint::RawTracePointContext impl aya_ebpf::programs::raw_tracepoint::RawTracePointContext -pub unsafe fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::raw_tracepoint::RawTracePointContext pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -1811,7 +1811,7 @@ pub struct aya_ebpf::programs::retprobe::RetProbeContext pub aya_ebpf::programs::retprobe::RetProbeContext::regs: *mut aya_ebpf_bindings::x86_64::bindings::pt_regs impl aya_ebpf::programs::retprobe::RetProbeContext pub fn aya_ebpf::programs::retprobe::RetProbeContext::new(ctx: *mut core::ffi::c_void) -> Self -pub fn aya_ebpf::programs::retprobe::RetProbeContext::ret(&self) -> core::option::Option +pub fn aya_ebpf::programs::retprobe::RetProbeContext::ret(&self) -> T impl aya_ebpf::EbpfContext for aya_ebpf::programs::retprobe::RetProbeContext pub fn aya_ebpf::programs::retprobe::RetProbeContext::as_ptr(&self) -> *mut core::ffi::c_void impl core::marker::Freeze for aya_ebpf::programs::retprobe::RetProbeContext @@ -2197,7 +2197,7 @@ pub fn aya_ebpf::programs::tc::TcContext::from(t: T) -> T pub mod aya_ebpf::programs::tp_btf pub struct aya_ebpf::programs::tp_btf::BtfTracePointContext impl aya_ebpf::programs::tp_btf::BtfTracePointContext -pub unsafe fn aya_ebpf::programs::tp_btf::BtfTracePointContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::tp_btf::BtfTracePointContext pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2289,7 +2289,7 @@ impl core::convert::From for aya_ebpf::programs::xdp::XdpContext pub fn aya_ebpf::programs::xdp::XdpContext::from(t: T) -> T pub struct aya_ebpf::programs::BtfTracePointContext impl aya_ebpf::programs::tp_btf::BtfTracePointContext -pub unsafe fn aya_ebpf::programs::tp_btf::BtfTracePointContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::tp_btf::BtfTracePointContext pub fn aya_ebpf::programs::tp_btf::BtfTracePointContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2345,7 +2345,7 @@ impl core::convert::From for aya_ebpf::programs::device::DeviceContext pub fn aya_ebpf::programs::device::DeviceContext::from(t: T) -> T pub struct aya_ebpf::programs::FEntryContext impl aya_ebpf::programs::fentry::FEntryContext -pub unsafe fn aya_ebpf::programs::fentry::FEntryContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::fentry::FEntryContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::fentry::FEntryContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::fentry::FEntryContext pub fn aya_ebpf::programs::fentry::FEntryContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2373,7 +2373,7 @@ impl core::convert::From for aya_ebpf::programs::fentry::FEntryContext pub fn aya_ebpf::programs::fentry::FEntryContext::from(t: T) -> T pub struct aya_ebpf::programs::FExitContext impl aya_ebpf::programs::fexit::FExitContext -pub unsafe fn aya_ebpf::programs::fexit::FExitContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::fexit::FExitContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::fexit::FExitContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::fexit::FExitContext pub fn aya_ebpf::programs::fexit::FExitContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2432,7 +2432,7 @@ impl core::convert::From for aya_ebpf::programs::flow_dissector::FlowDisse pub fn aya_ebpf::programs::flow_dissector::FlowDissectorContext::from(t: T) -> T pub struct aya_ebpf::programs::LsmContext impl aya_ebpf::programs::lsm::LsmContext -pub unsafe fn aya_ebpf::programs::lsm::LsmContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::lsm::LsmContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::lsm::LsmContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::lsm::LsmContext pub fn aya_ebpf::programs::lsm::LsmContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2488,7 +2488,7 @@ pub fn aya_ebpf::programs::perf_event::PerfEventContext::from(t: T) -> T pub struct aya_ebpf::programs::ProbeContext pub aya_ebpf::programs::ProbeContext::regs: *mut aya_ebpf_bindings::x86_64::bindings::pt_regs impl aya_ebpf::programs::probe::ProbeContext -pub fn aya_ebpf::programs::probe::ProbeContext::arg(&self, n: usize) -> core::option::Option +pub fn aya_ebpf::programs::probe::ProbeContext::arg(&self, n: usize) -> core::option::Option pub fn aya_ebpf::programs::probe::ProbeContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::probe::ProbeContext pub fn aya_ebpf::programs::probe::ProbeContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2516,7 +2516,7 @@ impl core::convert::From for aya_ebpf::programs::probe::ProbeContext pub fn aya_ebpf::programs::probe::ProbeContext::from(t: T) -> T pub struct aya_ebpf::programs::RawTracePointContext impl aya_ebpf::programs::raw_tracepoint::RawTracePointContext -pub unsafe fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::arg(&self, n: usize) -> T +pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::arg(&self, n: usize) -> T pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::new(ctx: *mut core::ffi::c_void) -> Self impl aya_ebpf::EbpfContext for aya_ebpf::programs::raw_tracepoint::RawTracePointContext pub fn aya_ebpf::programs::raw_tracepoint::RawTracePointContext::as_ptr(&self) -> *mut core::ffi::c_void @@ -2546,7 +2546,7 @@ pub struct aya_ebpf::programs::RetProbeContext pub aya_ebpf::programs::RetProbeContext::regs: *mut aya_ebpf_bindings::x86_64::bindings::pt_regs impl aya_ebpf::programs::retprobe::RetProbeContext pub fn aya_ebpf::programs::retprobe::RetProbeContext::new(ctx: *mut core::ffi::c_void) -> Self -pub fn aya_ebpf::programs::retprobe::RetProbeContext::ret(&self) -> core::option::Option +pub fn aya_ebpf::programs::retprobe::RetProbeContext::ret(&self) -> T impl aya_ebpf::EbpfContext for aya_ebpf::programs::retprobe::RetProbeContext pub fn aya_ebpf::programs::retprobe::RetProbeContext::as_ptr(&self) -> *mut core::ffi::c_void impl core::marker::Freeze for aya_ebpf::programs::retprobe::RetProbeContext @@ -2935,61 +2935,9 @@ impl core::convert::From for aya_ebpf::programs::xdp::XdpContext pub fn aya_ebpf::programs::xdp::XdpContext::from(t: T) -> T pub macro aya_ebpf::bpf_printk! pub macro aya_ebpf::btf_map_def! -pub struct aya_ebpf::PtRegs -impl aya_ebpf::PtRegs -pub fn aya_ebpf::PtRegs::arg(&self, n: usize) -> core::option::Option -pub fn aya_ebpf::PtRegs::as_ptr(&self) -> *mut aya_ebpf_bindings::x86_64::bindings::pt_regs -pub fn aya_ebpf::PtRegs::new(regs: *mut aya_ebpf_bindings::x86_64::bindings::pt_regs) -> Self -pub fn aya_ebpf::PtRegs::ret(&self) -> core::option::Option -impl core::marker::Freeze for aya_ebpf::PtRegs -impl !core::marker::Send for aya_ebpf::PtRegs -impl !core::marker::Sync for aya_ebpf::PtRegs -impl core::marker::Unpin for aya_ebpf::PtRegs -impl core::panic::unwind_safe::RefUnwindSafe for aya_ebpf::PtRegs -impl core::panic::unwind_safe::UnwindSafe for aya_ebpf::PtRegs -impl core::convert::Into for aya_ebpf::PtRegs where U: core::convert::From -pub fn aya_ebpf::PtRegs::into(self) -> U -impl core::convert::TryFrom for aya_ebpf::PtRegs where U: core::convert::Into -pub type aya_ebpf::PtRegs::Error = core::convert::Infallible -pub fn aya_ebpf::PtRegs::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya_ebpf::PtRegs where U: core::convert::TryFrom -pub type aya_ebpf::PtRegs::Error = >::Error -pub fn aya_ebpf::PtRegs::try_into(self) -> core::result::Result>::Error> -impl core::any::Any for aya_ebpf::PtRegs where T: 'static + ?core::marker::Sized -pub fn aya_ebpf::PtRegs::type_id(&self) -> core::any::TypeId -impl core::borrow::Borrow for aya_ebpf::PtRegs where T: ?core::marker::Sized -pub fn aya_ebpf::PtRegs::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya_ebpf::PtRegs where T: ?core::marker::Sized -pub fn aya_ebpf::PtRegs::borrow_mut(&mut self) -> &mut T -impl core::convert::From for aya_ebpf::PtRegs -pub fn aya_ebpf::PtRegs::from(t: T) -> T -pub struct aya_ebpf::RawTracepointArgs -impl aya_ebpf::RawTracepointArgs -pub unsafe fn aya_ebpf::RawTracepointArgs::arg(&self, n: usize) -> T -pub fn aya_ebpf::RawTracepointArgs::new(args: *mut aya_ebpf_bindings::x86_64::bindings::bpf_raw_tracepoint_args) -> Self -impl core::marker::Freeze for aya_ebpf::RawTracepointArgs -impl !core::marker::Send for aya_ebpf::RawTracepointArgs -impl !core::marker::Sync for aya_ebpf::RawTracepointArgs -impl core::marker::Unpin for aya_ebpf::RawTracepointArgs -impl core::panic::unwind_safe::RefUnwindSafe for aya_ebpf::RawTracepointArgs -impl core::panic::unwind_safe::UnwindSafe for aya_ebpf::RawTracepointArgs -impl core::convert::Into for aya_ebpf::RawTracepointArgs where U: core::convert::From -pub fn aya_ebpf::RawTracepointArgs::into(self) -> U -impl core::convert::TryFrom for aya_ebpf::RawTracepointArgs where U: core::convert::Into -pub type aya_ebpf::RawTracepointArgs::Error = core::convert::Infallible -pub fn aya_ebpf::RawTracepointArgs::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya_ebpf::RawTracepointArgs where U: core::convert::TryFrom -pub type aya_ebpf::RawTracepointArgs::Error = >::Error -pub fn aya_ebpf::RawTracepointArgs::try_into(self) -> core::result::Result>::Error> -impl core::any::Any for aya_ebpf::RawTracepointArgs where T: 'static + ?core::marker::Sized -pub fn aya_ebpf::RawTracepointArgs::type_id(&self) -> core::any::TypeId -impl core::borrow::Borrow for aya_ebpf::RawTracepointArgs where T: ?core::marker::Sized -pub fn aya_ebpf::RawTracepointArgs::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya_ebpf::RawTracepointArgs where T: ?core::marker::Sized -pub fn aya_ebpf::RawTracepointArgs::borrow_mut(&mut self) -> &mut T -impl core::convert::From for aya_ebpf::RawTracepointArgs -pub fn aya_ebpf::RawTracepointArgs::from(t: T) -> T pub const aya_ebpf::TASK_COMM_LEN: usize +pub trait aya_ebpf::Argument: aya_ebpf::args::sealed::Argument +impl aya_ebpf::Argument for T pub trait aya_ebpf::EbpfContext pub fn aya_ebpf::EbpfContext::as_ptr(&self) -> *mut aya_ebpf_cty::c_void pub fn aya_ebpf::EbpfContext::command(&self) -> core::result::Result<[u8; 16], aya_ebpf_cty::od::c_long>