From 72810f095f1461d5d254d37e7174bb47bd15f691 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 11 Nov 2025 10:28:54 -0500 Subject: [PATCH] aya: ProbeKind is Entry/Return We already have separate types for KProbe and UProbe. --- aya/src/bpf.rs | 8 +- aya/src/programs/kprobe.rs | 31 +++++- aya/src/programs/perf_attach.rs | 7 +- aya/src/programs/probe.rs | 139 +++++++++++------------- aya/src/programs/uprobe.rs | 24 +++- test/integration-test/src/tests/info.rs | 2 +- test/integration-test/src/tests/load.rs | 4 +- xtask/public-api/aya.txt | 6 +- 8 files changed, 119 insertions(+), 102 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 90ad428a..3e1d4404 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -598,11 +598,11 @@ impl<'a> EbpfLoader<'a> { match §ion { ProgramSection::KProbe => Program::KProbe(KProbe { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), - kind: ProbeKind::KProbe, + kind: ProbeKind::Entry, }), ProgramSection::KRetProbe => Program::KProbe(KProbe { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), - kind: ProbeKind::KRetProbe, + kind: ProbeKind::Return, }), ProgramSection::UProbe { sleepable } => { let mut data = @@ -612,7 +612,7 @@ impl<'a> EbpfLoader<'a> { } Program::UProbe(UProbe { data, - kind: ProbeKind::UProbe, + kind: ProbeKind::Entry, }) } ProgramSection::URetProbe { sleepable } => { @@ -623,7 +623,7 @@ impl<'a> EbpfLoader<'a> { } Program::UProbe(UProbe { data, - kind: ProbeKind::URetProbe, + kind: ProbeKind::Return, }) } ProgramSection::TracePoint => Program::TracePoint(TracePoint { diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index 46158ce6..3e30be27 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -1,6 +1,7 @@ //! Kernel space probes. use std::{ ffi::OsStr, + fmt::{self, Write}, io, os::fd::AsFd as _, path::{Path, PathBuf}, @@ -15,7 +16,7 @@ use crate::{ FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_into_fdlink, load_program, perf_attach::{PerfLinkIdInner, PerfLinkInner}, - probe::{ProbeKind, attach}, + probe::{Probe, ProbeKind, attach}, }, sys::bpf_link_get_info_by_fd, }; @@ -59,8 +60,8 @@ impl KProbe { load_program(BPF_PROG_TYPE_KPROBE, &mut self.data) } - /// Returns `KProbe` if the program is a `kprobe`, or `KRetProbe` if the - /// program is a `kretprobe`. + /// Returns [`ProbeKind::Entry`] if the program is a `kprobe`, or + /// [`ProbeKind::Return`] if the program is a `kretprobe`. pub fn kind(&self) -> ProbeKind { self.kind } @@ -81,9 +82,10 @@ impl KProbe { fn_name: T, offset: u64, ) -> Result { - attach( - &mut self.data, - self.kind, + let Self { data, kind } = self; + attach::( + data, + *kind, fn_name.as_ref(), offset, None, // pid @@ -103,6 +105,23 @@ impl KProbe { } } +impl Probe for KProbe { + const PMU: &'static str = "kprobe"; + + type Error = KProbeError; + + fn file_error(filename: PathBuf, io_error: io::Error) -> Self::Error { + KProbeError::FileError { filename, io_error } + } + + fn write_offset(w: &mut W, kind: ProbeKind, offset: u64) -> fmt::Result { + match kind { + ProbeKind::Entry => write!(w, "+{offset}"), + ProbeKind::Return => Ok(()), + } + } +} + define_link_wrapper!( KProbeLink, KProbeLinkId, diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index 5118321f..7391031c 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -8,10 +8,7 @@ use aya_obj::generated::bpf_attach_type::BPF_PERF_EVENT; use crate::{ FEATURES, - programs::{ - FdLink, Link, ProgramError, id_as_key, - probe::{ProbeEvent, detach_debug_fs}, - }, + programs::{FdLink, Link, ProgramError, id_as_key, probe::ProbeEvent}, sys::{ BpfLinkCreateArgs, LinkTarget, PerfEventIoctlRequest, SyscallError, bpf_link_create, is_bpf_cookie_supported, perf_event_ioctl, @@ -72,7 +69,7 @@ impl Link for PerfLink { let Self { perf_fd, event } = self; let _: io::Result<()> = perf_event_ioctl(perf_fd.as_fd(), PerfEventIoctlRequest::Disable); if let Some(event) = event { - let _: Result<_, _> = detach_debug_fs(event); + let _: Result<(), ProgramError> = event.detach(); } Ok(()) diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index 62ffedc8..3925be9f 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -1,6 +1,6 @@ use std::{ ffi::{OsStr, OsString}, - fmt::Write as _, + fmt::{self, Write}, fs::{self, OpenOptions}, io::{self, Write as _}, os::fd::AsFd as _, @@ -11,9 +11,8 @@ use std::{ use crate::{ programs::{ - Link, ProgramData, ProgramError, kprobe::KProbeError, perf_attach, - perf_attach::PerfLinkInner, perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, - uprobe::UProbeError, utils::find_tracefs_path, + Link, ProgramData, ProgramError, perf_attach, perf_attach::PerfLinkInner, + perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, utils::find_tracefs_path, }, sys::{SyscallError, perf_event_open_probe, perf_event_open_trace_point}, util::KernelVersion, @@ -24,23 +23,20 @@ static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0); /// Kind of probe program #[derive(Debug, Copy, Clone)] pub enum ProbeKind { - /// Kernel probe - KProbe, - /// Kernel return probe - KRetProbe, - /// User space probe - UProbe, - /// User space return probe - URetProbe, + /// Probe the entry of the function + Entry, + /// Probe the return of the function + Return, } -impl ProbeKind { - fn pmu(&self) -> &'static str { - match *self { - Self::KProbe | Self::KRetProbe => "kprobe", - Self::UProbe | Self::URetProbe => "uprobe", - } - } +pub(crate) trait Probe { + const PMU: &'static str; + + type Error: Into; + + fn file_error(filename: PathBuf, io_error: io::Error) -> Self::Error; + + fn write_offset(w: &mut W, kind: ProbeKind, offset: u64) -> fmt::Result; } pub(crate) fn lines(bytes: &[u8]) -> impl Iterator { @@ -94,11 +90,21 @@ impl OsStringExt for OsStr { #[derive(Debug)] pub(crate) struct ProbeEvent { - kind: ProbeKind, event_alias: OsString, + detach_debug_fs: fn(&OsStr) -> Result<(), ProgramError>, +} + +impl ProbeEvent { + pub(crate) fn detach(self) -> Result<(), ProgramError> { + let Self { + event_alias, + detach_debug_fs, + } = self; + detach_debug_fs(&event_alias) + } } -pub(crate) fn attach>( +pub(crate) fn attach>( program_data: &mut ProgramData, kind: ProbeKind, // NB: the meaning of this argument is different for kprobe/kretprobe and uprobe/uretprobe; in @@ -120,58 +126,44 @@ pub(crate) fn attach>( if cookie.is_some() { return Err(ProgramError::AttachCookieNotSupported); } - let (perf_fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; - perf_attach_debugfs(prog_fd, perf_fd, ProbeEvent { kind, event_alias }) + let (perf_fd, event_alias) = create_as_trace_point::

(kind, fn_name, offset, pid)?; + perf_attach_debugfs( + prog_fd, + perf_fd, + ProbeEvent { + event_alias, + detach_debug_fs: detach_debug_fs::

, + }, + ) } else { - let perf_fd = create_as_probe(kind, fn_name, offset, pid)?; + let perf_fd = create_as_probe::

(kind, fn_name, offset, pid)?; perf_attach(prog_fd, perf_fd, cookie) }?; program_data.links.insert(T::from(link)) } -pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> { +fn detach_debug_fs(event_alias: &OsStr) -> Result<(), ProgramError> { let tracefs = find_tracefs_path()?; - let ProbeEvent { - kind, - event_alias: _, - } = &event; - let kind = *kind; - let result = delete_probe_event(tracefs, event); - - result.map_err(|(filename, io_error)| match kind { - ProbeKind::KProbe | ProbeKind::KRetProbe => { - KProbeError::FileError { filename, io_error }.into() - } - ProbeKind::UProbe | ProbeKind::URetProbe => { - UProbeError::FileError { filename, io_error }.into() - } - }) + delete_probe_event(tracefs, P::PMU, event_alias) + .map_err(|(filename, io_error)| P::file_error(filename, io_error).into()) } -fn create_as_probe( +fn create_as_probe( kind: ProbeKind, fn_name: &OsStr, offset: u64, pid: Option, ) -> Result { - let perf_ty = match kind { - ProbeKind::KProbe | ProbeKind::KRetProbe => read_sys_fs_perf_type(kind.pmu()) - .map_err(|(filename, io_error)| KProbeError::FileError { filename, io_error })?, - ProbeKind::UProbe | ProbeKind::URetProbe => read_sys_fs_perf_type(kind.pmu()) - .map_err(|(filename, io_error)| UProbeError::FileError { filename, io_error })?, - }; + let perf_ty = read_sys_fs_perf_type(P::PMU) + .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?; let ret_bit = match kind { - ProbeKind::KRetProbe => Some( - read_sys_fs_perf_ret_probe(kind.pmu()) - .map_err(|(filename, io_error)| KProbeError::FileError { filename, io_error })?, + ProbeKind::Return => Some( + read_sys_fs_perf_ret_probe(P::PMU) + .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?, ), - ProbeKind::URetProbe => Some( - read_sys_fs_perf_ret_probe(kind.pmu()) - .map_err(|(filename, io_error)| UProbeError::FileError { filename, io_error })?, - ), - ProbeKind::UProbe | ProbeKind::KProbe => None, + ProbeKind::Entry => None, }; perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid) @@ -182,7 +174,7 @@ fn create_as_probe( .map_err(Into::into) } -fn create_as_trace_point( +fn create_as_trace_point( kind: ProbeKind, name: &OsStr, offset: u64, @@ -190,14 +182,10 @@ fn create_as_trace_point( ) -> Result<(crate::MockableFd, OsString), ProgramError> { let tracefs = find_tracefs_path()?; - let event_alias = match kind { - ProbeKind::KProbe | ProbeKind::KRetProbe => create_probe_event(tracefs, kind, name, offset) - .map_err(|(filename, io_error)| KProbeError::FileError { filename, io_error })?, - ProbeKind::UProbe | ProbeKind::URetProbe => create_probe_event(tracefs, kind, name, offset) - .map_err(|(filename, io_error)| UProbeError::FileError { filename, io_error })?, - }; + let event_alias = create_probe_event::

(tracefs, kind, name, offset) + .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?; - let category = format!("{}s", kind.pmu()); + let category = format!("{}s", P::PMU); let tpid = read_sys_fs_trace_point_id(tracefs, &category, event_alias.as_ref())?; let perf_fd = perf_event_open_trace_point(tpid, pid).map_err(|io_error| SyscallError { call: "perf_event_open", @@ -207,7 +195,7 @@ fn create_as_trace_point( Ok((perf_fd, event_alias)) } -fn create_probe_event( +fn create_probe_event( tracefs: &Path, kind: ProbeKind, fn_name: &OsStr, @@ -216,8 +204,8 @@ fn create_probe_event( use std::os::unix::ffi::OsStrExt as _; let probe_type_prefix = match kind { - ProbeKind::KProbe | ProbeKind::UProbe => 'p', - ProbeKind::KRetProbe | ProbeKind::URetProbe => 'r', + ProbeKind::Entry => 'p', + ProbeKind::Return => 'r', }; let mut event_alias = OsString::new(); @@ -244,18 +232,14 @@ fn create_probe_event( .unwrap(); let mut probe = OsString::new(); - write!(&mut probe, "{}:{}s/", probe_type_prefix, kind.pmu()).unwrap(); + write!(&mut probe, "{}:{}s/", probe_type_prefix, P::PMU).unwrap(); probe.push(&event_alias); probe.push(" "); probe.push(fn_name); - match kind { - ProbeKind::KProbe => write!(&mut probe, "+{offset}").unwrap(), - ProbeKind::UProbe | ProbeKind::URetProbe => write!(&mut probe, ":{offset:#x}").unwrap(), - ProbeKind::KRetProbe => {} - }; + P::write_offset(&mut probe, kind, offset).unwrap(); probe.push("\n"); - let events_file_name = tracefs.join(format!("{}_events", kind.pmu())); + let events_file_name = tracefs.join(format!("{}_events", P::PMU)); OpenOptions::new() .append(true) .open(&events_file_name) @@ -265,11 +249,14 @@ fn create_probe_event( Ok(event_alias) } -fn delete_probe_event(tracefs: &Path, event: ProbeEvent) -> Result<(), (PathBuf, io::Error)> { +fn delete_probe_event( + tracefs: &Path, + pmu: &str, + event_alias: &OsStr, +) -> Result<(), (PathBuf, io::Error)> { use std::os::unix::ffi::OsStrExt as _; - let ProbeEvent { kind, event_alias } = event; - let events_file_name = tracefs.join(format!("{}_events", kind.pmu())); + let events_file_name = tracefs.join(format!("{}_events", pmu)); fs::read(&events_file_name) .and_then(|events| { diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 16899c35..0e15fc39 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -2,6 +2,7 @@ use std::{ error::Error, ffi::{CStr, OsStr, OsString}, + fmt::{self, Write}, fs, io::{self, BufRead as _, Cursor, Read as _}, mem, @@ -20,7 +21,7 @@ use crate::{ FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_into_fdlink, load_program, perf_attach::{PerfLinkIdInner, PerfLinkInner}, - probe::{OsStringExt as _, ProbeKind, attach}, + probe::{OsStringExt as _, Probe, ProbeKind, attach}, }, sys::bpf_link_get_info_by_fd, util::MMap, @@ -80,8 +81,8 @@ impl UProbe { load_program(BPF_PROG_TYPE_KPROBE, &mut self.data) } - /// Returns `UProbe` if the program is a `uprobe`, or `URetProbe` if the - /// program is a `uretprobe`. + /// Returns [`ProbeKind::Entry`] if the program is a `uprobe`, or + /// [`ProbeKind::Return`] if the program is a `uretprobe`. pub fn kind(&self) -> ProbeKind { self.kind } @@ -129,8 +130,9 @@ impl UProbe { offset }; + let Self { data, kind } = self; let path = path.as_os_str(); - attach(&mut self.data, self.kind, path, offset, pid, cookie) + attach::(data, *kind, path, offset, pid, cookie) } /// Creates a program from a pinned entry on a bpffs. @@ -145,6 +147,20 @@ impl UProbe { } } +impl Probe for UProbe { + const PMU: &'static str = "uprobe"; + + type Error = UProbeError; + + fn file_error(filename: PathBuf, io_error: io::Error) -> Self::Error { + UProbeError::FileError { filename, io_error } + } + + fn write_offset(w: &mut W, _: ProbeKind, offset: u64) -> fmt::Result { + write!(w, ":{offset:#x}") + } +} + fn resolve_attach_path<'a, 'b, 'c, T>( target: &'a Path, proc_map: Option<&'b ProcMap>, diff --git a/test/integration-test/src/tests/info.rs b/test/integration-test/src/tests/info.rs index 9a4740c3..20c92c75 100644 --- a/test/integration-test/src/tests/info.rs +++ b/test/integration-test/src/tests/info.rs @@ -60,7 +60,7 @@ fn test_loaded_programs() { .unwrap(); let mut p: UProbe = unsafe { - UProbe::from_program_info(info, "test_uprobe".into(), aya::programs::ProbeKind::UProbe) + UProbe::from_program_info(info, "test_uprobe".into(), aya::programs::ProbeKind::Entry) .unwrap() }; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index dd50fe2d..26046824 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -557,7 +557,7 @@ fn pin_lifecycle_kprobe() { let attach = |prog: &mut P| prog.attach("try_to_wake_up", 0).unwrap(); let program_pin = "/sys/fs/bpf/aya-kprobe-test-prog"; let link_pin = "/sys/fs/bpf/aya-kprobe-test-try-to-wake-up"; - let from_pin = |program_pin: &str| P::from_pin(program_pin, ProbeKind::KProbe).unwrap(); + let from_pin = |program_pin: &str| P::from_pin(program_pin, ProbeKind::Entry).unwrap(); run_pin_program_lifecycle_test( crate::TEST, program_name, @@ -587,7 +587,7 @@ fn pin_lifecycle_uprobe() { }; let program_pin = "/sys/fs/bpf/aya-uprobe-test-prog"; let link_pin = "/sys/fs/bpf/aya-uprobe-test-uprobe-function"; - let from_pin = |program_pin: &str| P::from_pin(program_pin, ProbeKind::UProbe).unwrap(); + let from_pin = |program_pin: &str| P::from_pin(program_pin, ProbeKind::Entry).unwrap(); run_pin_program_lifecycle_test( crate::TEST, program_name, diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index fce3d730..3b6618be 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -8014,10 +8014,8 @@ pub unsafe fn aya::programs::LsmAttachType::clone_to_uninit(&self, dest: *mut u8 impl core::convert::From for aya::programs::LsmAttachType pub fn aya::programs::LsmAttachType::from(t: T) -> T pub enum aya::programs::ProbeKind -pub aya::programs::ProbeKind::KProbe -pub aya::programs::ProbeKind::KRetProbe -pub aya::programs::ProbeKind::UProbe -pub aya::programs::ProbeKind::URetProbe +pub aya::programs::ProbeKind::Entry +pub aya::programs::ProbeKind::Return impl core::clone::Clone for aya::programs::ProbeKind pub fn aya::programs::ProbeKind::clone(&self) -> aya::programs::ProbeKind impl core::fmt::Debug for aya::programs::ProbeKind