use ax_errno::{AxError, AxResult};
use kbpf_basic::perf::{PerfProbeArgs, PerfProbeConfig};
use kprobe::ProbeBuilder;
use super::kprobe::{ProbePerfEvent, ProbeTy};
use crate::{
kprobe::KprobeAuxiliary,
task::{AsThread, get_task},
};
fn perf_probe_arg_to_uprobe_builder(
args: &PerfProbeArgs,
) -> AxResult<ProbeBuilder<KprobeAuxiliary>> {
let elf = &args.name;
let offset = args.offset as usize;
let pid = args.pid;
if pid < 0 {
warn!("uprobe: pid == -1 (all-process / shared-lib uprobe) is unsupported");
return Err(AxError::Unsupported);
}
let task = get_task(pid as _)?;
let aspace = task.as_thread().proc_data.aspace();
let mm = aspace.lock();
let mut virt_base = None;
for area in mm.areas() {
if let Ok(info) = area.backend().file_info()
&& &info.path == elf
{
virt_base = Some(area.start());
break;
}
}
drop(mm);
let Some(virt_base) = virt_base else {
warn!("uprobe: ELF {elf} is not mapped in pid {pid}");
return Err(AxError::NotFound);
};
let virt_addr = virt_base.as_usize() + offset;
debug!(
"uprobe: pid {pid} ELF {elf} base {:#x} + offset {:#x} = {virt_addr:#x}",
virt_base.as_usize(),
offset
);
Ok(ProbeBuilder::new()
.with_symbol(elf.clone())
.with_symbol_addr(virt_addr)
.with_offset(0)
.with_user_mode(pid))
}
pub fn perf_event_open_uprobe(args: PerfProbeArgs) -> AxResult<ProbePerfEvent> {
let probe = match args.config {
PerfProbeConfig::Raw(0) => {
let builder = perf_probe_arg_to_uprobe_builder(&args)?;
ProbeTy::Uprobe(crate::uprobe::register_uprobe(builder))
}
PerfProbeConfig::Raw(1) => {
warn!("uprobe: uretprobe (config=1) is not yet supported");
return Err(AxError::Unsupported);
}
other => {
warn!("uprobe: unsupported perf probe config {other:?}");
return Err(AxError::Unsupported);
}
};
Ok(ProbePerfEvent::new(args, probe))
}