use crate::bindings::{bpf_raw_tracepoint_args, pt_regs};
mod sealed {
#[expect(unnameable_types, reason = "this is the sealed trait pattern")]
pub trait Argument {
fn from_register(value: u64) -> Self;
}
macro_rules! impl_argument {
($($( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )?),+ $(,)?) => {
$(
#[expect(clippy::allow_attributes, reason = "macro")]
#[allow(clippy::cast_lossless, trivial_numeric_casts, reason = "macro")]
impl$($($generics)*)? Argument for $ty $(where $($where)*)? {
fn from_register(value: u64) -> Self {
value as Self
}
}
)+
}
}
impl_argument!(
i8,
u8,
i16,
u16,
i32,
u32,
i64,
u64,
i128,
u128,
isize,
usize,
{<T>} *const T {where T: 'static},
{<T>} *mut T {where T: 'static},
);
}
pub trait Argument: sealed::Argument {}
impl<T: sealed::Argument> Argument for T {}
pub(crate) fn btf_arg<T: Argument>(ctx: &impl crate::EbpfContext, n: usize) -> T {
let ptr: *const usize = ctx.as_ptr().cast();
let ptr = unsafe { ptr.add(n) };
T::from_register(unsafe { *ptr as u64 })
}
trait PtRegsLayout {
type Reg;
fn arg_reg(&self, index: usize) -> Option<&Self::Reg>;
fn rc_reg(&self) -> &Self::Reg;
}
#[cfg(bpf_target_arch = "aarch64")]
impl PtRegsLayout for pt_regs {
type Reg = crate::bindings::__u64;
fn arg_reg(&self, index: usize) -> Option<&Self::Reg> {
match index {
0..=7 => Some(&self.regs[index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.regs[0]
}
}
#[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> {
match index {
0..=6 => Some(&self.uregs[index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.uregs[0]
}
}
#[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> {
match index {
0..=7 => Some(&self.regs[4 + index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.regs[4]
}
}
#[cfg(any(bpf_target_arch = "mips", bpf_target_arch = "mips64"))]
impl PtRegsLayout for pt_regs {
type Reg = crate::bindings::__u64;
fn arg_reg(&self, index: usize) -> Option<&Self::Reg> {
match index {
0..=7 => Some(&self.regs[4 + index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.regs[2]
}
}
#[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> {
match index {
0..=7 => Some(&self.gpr[3 + index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.gpr[3]
}
}
#[cfg(bpf_target_arch = "riscv64")]
impl PtRegsLayout for pt_regs {
type Reg = crate::cty::c_ulong;
fn arg_reg(&self, index: usize) -> Option<&Self::Reg> {
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 rc_reg(&self) -> &Self::Reg {
&self.a0
}
}
#[cfg(bpf_target_arch = "s390x")]
impl PtRegsLayout for pt_regs {
type Reg = crate::cty::c_ulong;
fn arg_reg(&self, index: usize) -> Option<&Self::Reg> {
match index {
0..=4 => Some(&self.gprs[2 + index]),
_ => None,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.gprs[2]
}
}
#[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> {
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,
}
}
fn rc_reg(&self) -> &Self::Reg {
&self.rax
}
}
pub(crate) fn arg<T: Argument>(ctx: &pt_regs, n: usize) -> Option<T> {
let reg = ctx.arg_reg(n)?;
#[expect(clippy::allow_attributes, reason = "architecture-specific")]
#[allow(
clippy::cast_sign_loss,
clippy::unnecessary_cast,
trivial_numeric_casts,
reason = "architecture-specific"
)]
Some(T::from_register((*reg) as u64))
}
pub(crate) fn ret<T: Argument>(ctx: &pt_regs) -> T {
let reg = ctx.rc_reg();
#[expect(clippy::allow_attributes, reason = "architecture-specific")]
#[allow(
clippy::cast_sign_loss,
clippy::unnecessary_cast,
trivial_numeric_casts,
reason = "architecture-specific"
)]
T::from_register((*reg) as u64)
}
pub(crate) fn raw_tracepoint_arg<T: Argument>(ctx: &bpf_raw_tracepoint_args, n: usize) -> T {
let ptr = ctx.args.as_ptr();
let ptr = unsafe { ptr.add(n) };
T::from_register(unsafe { *ptr })
}