|
|
@@ -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<T> 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<T: FromPtRegs>(&self, n: usize) -> Option<T> {
|
|
|
- T::from_argument(unsafe { &*self.regs }, n)
|
|
|
- }
|
|
|
-
|
|
|
- /// Returns the value of the register used to pass the return value.
|
|
|
- pub fn ret<T: FromPtRegs>(&self) -> Option<T> {
|
|
|
- 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,
|
|
|
+ {<T>} *const T {where T: 'static},
|
|
|
+ {<T>} *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<Self>;
|
|
|
-
|
|
|
- /// Coerces a `T` from the return value of a pt_regs context.
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self>;
|
|
|
-}
|
|
|
+pub trait Argument: sealed::Argument {}
|
|
|
|
|
|
-#[cfg(bpf_target_arch = "x86_64")]
|
|
|
-impl<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<T: sealed::Argument> Argument for T {}
|
|
|
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<T: Argument>(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<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.regs[0]).map(|v| v as *const _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "loongarch64")]
|
|
|
-impl<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.regs[4]).map(|v| v as *const _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "riscv64")]
|
|
|
-impl<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *const T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- // 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.regs[31]).map(|v| v as *const _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "x86_64")]
|
|
|
-impl<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.rax).map(|v| v as *mut _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "arm")]
|
|
|
-impl<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.uregs[0]).map(|v| v as *mut _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "aarch64")]
|
|
|
-impl<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.ra).map(|v| v as *mut _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "powerpc64")]
|
|
|
-impl<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- unsafe { bpf_probe_read(&ctx.gprs[2]).map(|v| v as *mut _).ok() }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(bpf_target_arch = "mips")]
|
|
|
-impl<T> FromPtRegs for *mut T {
|
|
|
- fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
|
|
- // 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<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 6 {
|
|
|
- Some(ctx.uregs[n] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 7 {
|
|
|
- Some(ctx.regs[n] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 7 {
|
|
|
- Some(ctx.regs[4 + n] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 7 {
|
|
|
- Some(ctx.gpr[3 + n] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 4 {
|
|
|
- Some(ctx.gprs[2 + n] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<Self> {
|
|
|
- if n <= 7 {
|
|
|
- Some(ctx.regs[n + 4] as *const $type as _)
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
|
|
- 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<T>::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<T: FromRawTracepointArgs>(&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<T>::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<T: Argument>(ctx: &pt_regs, n: usize) -> Option<T> {
|
|
|
+ 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<T> 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<T>` in the Rust
|
|
|
- // wraapper.
|
|
|
- //
|
|
|
- // The most convenient way of accessing such type in Rust is to use
|
|
|
- // `__IncompleteArrayField<T>::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<T: Argument>(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<T>::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<T: Argument>(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<T>` in the Rust
|
|
|
+ // wrapper.
|
|
|
+ //
|
|
|
+ // The most convenient way of accessing such type in Rust is to use
|
|
|
+ // `__IncompleteArrayField<T>::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);
|