aya: ProbeKind is Entry/Return

We already have separate types for KProbe and UProbe.
reviewable/pr1393/r10
Tamir Duberstein 6 days ago
parent a4a3c1641f
commit 72810f095f
No known key found for this signature in database

@ -598,11 +598,11 @@ impl<'a> EbpfLoader<'a> {
match &section { match &section {
ProgramSection::KProbe => Program::KProbe(KProbe { ProgramSection::KProbe => Program::KProbe(KProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
kind: ProbeKind::KProbe, kind: ProbeKind::Entry,
}), }),
ProgramSection::KRetProbe => Program::KProbe(KProbe { ProgramSection::KRetProbe => Program::KProbe(KProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
kind: ProbeKind::KRetProbe, kind: ProbeKind::Return,
}), }),
ProgramSection::UProbe { sleepable } => { ProgramSection::UProbe { sleepable } => {
let mut data = let mut data =
@ -612,7 +612,7 @@ impl<'a> EbpfLoader<'a> {
} }
Program::UProbe(UProbe { Program::UProbe(UProbe {
data, data,
kind: ProbeKind::UProbe, kind: ProbeKind::Entry,
}) })
} }
ProgramSection::URetProbe { sleepable } => { ProgramSection::URetProbe { sleepable } => {
@ -623,7 +623,7 @@ impl<'a> EbpfLoader<'a> {
} }
Program::UProbe(UProbe { Program::UProbe(UProbe {
data, data,
kind: ProbeKind::URetProbe, kind: ProbeKind::Return,
}) })
} }
ProgramSection::TracePoint => Program::TracePoint(TracePoint { ProgramSection::TracePoint => Program::TracePoint(TracePoint {

@ -1,6 +1,7 @@
//! Kernel space probes. //! Kernel space probes.
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fmt::{self, Write},
io, io,
os::fd::AsFd as _, os::fd::AsFd as _,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -15,7 +16,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper,
impl_try_into_fdlink, load_program, impl_try_into_fdlink, load_program,
perf_attach::{PerfLinkIdInner, PerfLinkInner}, perf_attach::{PerfLinkIdInner, PerfLinkInner},
probe::{ProbeKind, attach}, probe::{Probe, ProbeKind, attach},
}, },
sys::bpf_link_get_info_by_fd, sys::bpf_link_get_info_by_fd,
}; };
@ -59,8 +60,8 @@ impl KProbe {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data) load_program(BPF_PROG_TYPE_KPROBE, &mut self.data)
} }
/// Returns `KProbe` if the program is a `kprobe`, or `KRetProbe` if the /// Returns [`ProbeKind::Entry`] if the program is a `kprobe`, or
/// program is a `kretprobe`. /// [`ProbeKind::Return`] if the program is a `kretprobe`.
pub fn kind(&self) -> ProbeKind { pub fn kind(&self) -> ProbeKind {
self.kind self.kind
} }
@ -81,9 +82,10 @@ impl KProbe {
fn_name: T, fn_name: T,
offset: u64, offset: u64,
) -> Result<KProbeLinkId, ProgramError> { ) -> Result<KProbeLinkId, ProgramError> {
attach( let Self { data, kind } = self;
&mut self.data, attach::<Self, _>(
self.kind, data,
*kind,
fn_name.as_ref(), fn_name.as_ref(),
offset, offset,
None, // pid 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: Write>(w: &mut W, kind: ProbeKind, offset: u64) -> fmt::Result {
match kind {
ProbeKind::Entry => write!(w, "+{offset}"),
ProbeKind::Return => Ok(()),
}
}
}
define_link_wrapper!( define_link_wrapper!(
KProbeLink, KProbeLink,
KProbeLinkId, KProbeLinkId,

@ -8,10 +8,7 @@ use aya_obj::generated::bpf_attach_type::BPF_PERF_EVENT;
use crate::{ use crate::{
FEATURES, FEATURES,
programs::{ programs::{FdLink, Link, ProgramError, id_as_key, probe::ProbeEvent},
FdLink, Link, ProgramError, id_as_key,
probe::{ProbeEvent, detach_debug_fs},
},
sys::{ sys::{
BpfLinkCreateArgs, LinkTarget, PerfEventIoctlRequest, SyscallError, bpf_link_create, BpfLinkCreateArgs, LinkTarget, PerfEventIoctlRequest, SyscallError, bpf_link_create,
is_bpf_cookie_supported, perf_event_ioctl, is_bpf_cookie_supported, perf_event_ioctl,
@ -72,7 +69,7 @@ impl Link for PerfLink {
let Self { perf_fd, event } = self; let Self { perf_fd, event } = self;
let _: io::Result<()> = perf_event_ioctl(perf_fd.as_fd(), PerfEventIoctlRequest::Disable); let _: io::Result<()> = perf_event_ioctl(perf_fd.as_fd(), PerfEventIoctlRequest::Disable);
if let Some(event) = event { if let Some(event) = event {
let _: Result<_, _> = detach_debug_fs(event); let _: Result<(), ProgramError> = event.detach();
} }
Ok(()) Ok(())

@ -1,6 +1,6 @@
use std::{ use std::{
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
fmt::Write as _, fmt::{self, Write},
fs::{self, OpenOptions}, fs::{self, OpenOptions},
io::{self, Write as _}, io::{self, Write as _},
os::fd::AsFd as _, os::fd::AsFd as _,
@ -11,9 +11,8 @@ use std::{
use crate::{ use crate::{
programs::{ programs::{
Link, ProgramData, ProgramError, kprobe::KProbeError, perf_attach, Link, ProgramData, ProgramError, perf_attach, perf_attach::PerfLinkInner,
perf_attach::PerfLinkInner, perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, utils::find_tracefs_path,
uprobe::UProbeError, utils::find_tracefs_path,
}, },
sys::{SyscallError, perf_event_open_probe, perf_event_open_trace_point}, sys::{SyscallError, perf_event_open_probe, perf_event_open_trace_point},
util::KernelVersion, util::KernelVersion,
@ -24,23 +23,20 @@ static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0);
/// Kind of probe program /// Kind of probe program
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum ProbeKind { pub enum ProbeKind {
/// Kernel probe /// Probe the entry of the function
KProbe, Entry,
/// Kernel return probe /// Probe the return of the function
KRetProbe, Return,
/// User space probe
UProbe,
/// User space return probe
URetProbe,
} }
impl ProbeKind { pub(crate) trait Probe {
fn pmu(&self) -> &'static str { const PMU: &'static str;
match *self {
Self::KProbe | Self::KRetProbe => "kprobe", type Error: Into<ProgramError>;
Self::UProbe | Self::URetProbe => "uprobe",
} fn file_error(filename: PathBuf, io_error: io::Error) -> Self::Error;
}
fn write_offset<W: Write>(w: &mut W, kind: ProbeKind, offset: u64) -> fmt::Result;
} }
pub(crate) fn lines(bytes: &[u8]) -> impl Iterator<Item = &OsStr> { pub(crate) fn lines(bytes: &[u8]) -> impl Iterator<Item = &OsStr> {
@ -94,11 +90,21 @@ impl OsStringExt for OsStr {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ProbeEvent { pub(crate) struct ProbeEvent {
kind: ProbeKind,
event_alias: OsString, 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<T: Link + From<PerfLinkInner>>( pub(crate) fn attach<P: Probe, T: Link + From<PerfLinkInner>>(
program_data: &mut ProgramData<T>, program_data: &mut ProgramData<T>,
kind: ProbeKind, kind: ProbeKind,
// NB: the meaning of this argument is different for kprobe/kretprobe and uprobe/uretprobe; in // NB: the meaning of this argument is different for kprobe/kretprobe and uprobe/uretprobe; in
@ -120,58 +126,44 @@ pub(crate) fn attach<T: Link + From<PerfLinkInner>>(
if cookie.is_some() { if cookie.is_some() {
return Err(ProgramError::AttachCookieNotSupported); return Err(ProgramError::AttachCookieNotSupported);
} }
let (perf_fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; let (perf_fd, event_alias) = create_as_trace_point::<P>(kind, fn_name, offset, pid)?;
perf_attach_debugfs(prog_fd, perf_fd, ProbeEvent { kind, event_alias }) perf_attach_debugfs(
prog_fd,
perf_fd,
ProbeEvent {
event_alias,
detach_debug_fs: detach_debug_fs::<P>,
},
)
} else { } else {
let perf_fd = create_as_probe(kind, fn_name, offset, pid)?; let perf_fd = create_as_probe::<P>(kind, fn_name, offset, pid)?;
perf_attach(prog_fd, perf_fd, cookie) perf_attach(prog_fd, perf_fd, cookie)
}?; }?;
program_data.links.insert(T::from(link)) program_data.links.insert(T::from(link))
} }
pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> { fn detach_debug_fs<P: Probe>(event_alias: &OsStr) -> Result<(), ProgramError> {
let tracefs = find_tracefs_path()?; let tracefs = find_tracefs_path()?;
let ProbeEvent { delete_probe_event(tracefs, P::PMU, event_alias)
kind, .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())
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()
}
})
} }
fn create_as_probe( fn create_as_probe<P: Probe>(
kind: ProbeKind, kind: ProbeKind,
fn_name: &OsStr, fn_name: &OsStr,
offset: u64, offset: u64,
pid: Option<u32>, pid: Option<u32>,
) -> Result<crate::MockableFd, ProgramError> { ) -> Result<crate::MockableFd, ProgramError> {
let perf_ty = match kind { let perf_ty = read_sys_fs_perf_type(P::PMU)
ProbeKind::KProbe | ProbeKind::KRetProbe => read_sys_fs_perf_type(kind.pmu()) .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?;
.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 ret_bit = match kind { let ret_bit = match kind {
ProbeKind::KRetProbe => Some( ProbeKind::Return => Some(
read_sys_fs_perf_ret_probe(kind.pmu()) read_sys_fs_perf_ret_probe(P::PMU)
.map_err(|(filename, io_error)| KProbeError::FileError { filename, io_error })?, .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?,
), ),
ProbeKind::URetProbe => Some( ProbeKind::Entry => None,
read_sys_fs_perf_ret_probe(kind.pmu())
.map_err(|(filename, io_error)| UProbeError::FileError { filename, io_error })?,
),
ProbeKind::UProbe | ProbeKind::KProbe => None,
}; };
perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid) perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid)
@ -182,7 +174,7 @@ fn create_as_probe(
.map_err(Into::into) .map_err(Into::into)
} }
fn create_as_trace_point( fn create_as_trace_point<P: Probe>(
kind: ProbeKind, kind: ProbeKind,
name: &OsStr, name: &OsStr,
offset: u64, offset: u64,
@ -190,14 +182,10 @@ fn create_as_trace_point(
) -> Result<(crate::MockableFd, OsString), ProgramError> { ) -> Result<(crate::MockableFd, OsString), ProgramError> {
let tracefs = find_tracefs_path()?; let tracefs = find_tracefs_path()?;
let event_alias = match kind { let event_alias = create_probe_event::<P>(tracefs, kind, name, offset)
ProbeKind::KProbe | ProbeKind::KRetProbe => create_probe_event(tracefs, kind, name, offset) .map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?;
.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 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 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 { let perf_fd = perf_event_open_trace_point(tpid, pid).map_err(|io_error| SyscallError {
call: "perf_event_open", call: "perf_event_open",
@ -207,7 +195,7 @@ fn create_as_trace_point(
Ok((perf_fd, event_alias)) Ok((perf_fd, event_alias))
} }
fn create_probe_event( fn create_probe_event<P: Probe>(
tracefs: &Path, tracefs: &Path,
kind: ProbeKind, kind: ProbeKind,
fn_name: &OsStr, fn_name: &OsStr,
@ -216,8 +204,8 @@ fn create_probe_event(
use std::os::unix::ffi::OsStrExt as _; use std::os::unix::ffi::OsStrExt as _;
let probe_type_prefix = match kind { let probe_type_prefix = match kind {
ProbeKind::KProbe | ProbeKind::UProbe => 'p', ProbeKind::Entry => 'p',
ProbeKind::KRetProbe | ProbeKind::URetProbe => 'r', ProbeKind::Return => 'r',
}; };
let mut event_alias = OsString::new(); let mut event_alias = OsString::new();
@ -244,18 +232,14 @@ fn create_probe_event(
.unwrap(); .unwrap();
let mut probe = OsString::new(); 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(&event_alias);
probe.push(" "); probe.push(" ");
probe.push(fn_name); probe.push(fn_name);
match kind { P::write_offset(&mut probe, kind, offset).unwrap();
ProbeKind::KProbe => write!(&mut probe, "+{offset}").unwrap(),
ProbeKind::UProbe | ProbeKind::URetProbe => write!(&mut probe, ":{offset:#x}").unwrap(),
ProbeKind::KRetProbe => {}
};
probe.push("\n"); 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() OpenOptions::new()
.append(true) .append(true)
.open(&events_file_name) .open(&events_file_name)
@ -265,11 +249,14 @@ fn create_probe_event(
Ok(event_alias) 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 _; use std::os::unix::ffi::OsStrExt as _;
let ProbeEvent { kind, event_alias } = event; let events_file_name = tracefs.join(format!("{}_events", pmu));
let events_file_name = tracefs.join(format!("{}_events", kind.pmu()));
fs::read(&events_file_name) fs::read(&events_file_name)
.and_then(|events| { .and_then(|events| {

@ -2,6 +2,7 @@
use std::{ use std::{
error::Error, error::Error,
ffi::{CStr, OsStr, OsString}, ffi::{CStr, OsStr, OsString},
fmt::{self, Write},
fs, fs,
io::{self, BufRead as _, Cursor, Read as _}, io::{self, BufRead as _, Cursor, Read as _},
mem, mem,
@ -20,7 +21,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper,
impl_try_into_fdlink, load_program, impl_try_into_fdlink, load_program,
perf_attach::{PerfLinkIdInner, PerfLinkInner}, perf_attach::{PerfLinkIdInner, PerfLinkInner},
probe::{OsStringExt as _, ProbeKind, attach}, probe::{OsStringExt as _, Probe, ProbeKind, attach},
}, },
sys::bpf_link_get_info_by_fd, sys::bpf_link_get_info_by_fd,
util::MMap, util::MMap,
@ -80,8 +81,8 @@ impl UProbe {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data) load_program(BPF_PROG_TYPE_KPROBE, &mut self.data)
} }
/// Returns `UProbe` if the program is a `uprobe`, or `URetProbe` if the /// Returns [`ProbeKind::Entry`] if the program is a `uprobe`, or
/// program is a `uretprobe`. /// [`ProbeKind::Return`] if the program is a `uretprobe`.
pub fn kind(&self) -> ProbeKind { pub fn kind(&self) -> ProbeKind {
self.kind self.kind
} }
@ -129,8 +130,9 @@ impl UProbe {
offset offset
}; };
let Self { data, kind } = self;
let path = path.as_os_str(); let path = path.as_os_str();
attach(&mut self.data, self.kind, path, offset, pid, cookie) attach::<Self, _>(data, *kind, path, offset, pid, cookie)
} }
/// Creates a program from a pinned entry on a bpffs. /// 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: Write>(w: &mut W, _: ProbeKind, offset: u64) -> fmt::Result {
write!(w, ":{offset:#x}")
}
}
fn resolve_attach_path<'a, 'b, 'c, T>( fn resolve_attach_path<'a, 'b, 'c, T>(
target: &'a Path, target: &'a Path,
proc_map: Option<&'b ProcMap<T>>, proc_map: Option<&'b ProcMap<T>>,

@ -60,7 +60,7 @@ fn test_loaded_programs() {
.unwrap(); .unwrap();
let mut p: UProbe = unsafe { 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() .unwrap()
}; };

@ -557,7 +557,7 @@ fn pin_lifecycle_kprobe() {
let attach = |prog: &mut P| prog.attach("try_to_wake_up", 0).unwrap(); let attach = |prog: &mut P| prog.attach("try_to_wake_up", 0).unwrap();
let program_pin = "/sys/fs/bpf/aya-kprobe-test-prog"; let program_pin = "/sys/fs/bpf/aya-kprobe-test-prog";
let link_pin = "/sys/fs/bpf/aya-kprobe-test-try-to-wake-up"; 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( run_pin_program_lifecycle_test(
crate::TEST, crate::TEST,
program_name, program_name,
@ -587,7 +587,7 @@ fn pin_lifecycle_uprobe() {
}; };
let program_pin = "/sys/fs/bpf/aya-uprobe-test-prog"; let program_pin = "/sys/fs/bpf/aya-uprobe-test-prog";
let link_pin = "/sys/fs/bpf/aya-uprobe-test-uprobe-function"; 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( run_pin_program_lifecycle_test(
crate::TEST, crate::TEST,
program_name, program_name,

@ -8014,10 +8014,8 @@ pub unsafe fn aya::programs::LsmAttachType::clone_to_uninit(&self, dest: *mut u8
impl<T> core::convert::From<T> for aya::programs::LsmAttachType impl<T> core::convert::From<T> for aya::programs::LsmAttachType
pub fn aya::programs::LsmAttachType::from(t: T) -> T pub fn aya::programs::LsmAttachType::from(t: T) -> T
pub enum aya::programs::ProbeKind pub enum aya::programs::ProbeKind
pub aya::programs::ProbeKind::KProbe pub aya::programs::ProbeKind::Entry
pub aya::programs::ProbeKind::KRetProbe pub aya::programs::ProbeKind::Return
pub aya::programs::ProbeKind::UProbe
pub aya::programs::ProbeKind::URetProbe
impl core::clone::Clone for aya::programs::ProbeKind impl core::clone::Clone for aya::programs::ProbeKind
pub fn aya::programs::ProbeKind::clone(&self) -> aya::programs::ProbeKind pub fn aya::programs::ProbeKind::clone(&self) -> aya::programs::ProbeKind
impl core::fmt::Debug for aya::programs::ProbeKind impl core::fmt::Debug for aya::programs::ProbeKind

Loading…
Cancel
Save