use kbpf_basic::perf::{PerfProbeArgs, PerfProbeConfig};
use kprobe::ProbeBuilder;
use super::kprobe::{PROBE_CONFIG_ENTRY, PROBE_CONFIG_RETURN, ProbePerfEvent, ProbeTy};
use crate::{
StarryError, StarryResult,
kprobe::{KprobeAuxiliary, UprobeTargetLease},
task::UserTaskRef,
};
fn perf_probe_arg_to_uprobe_builder(
args: &PerfProbeArgs,
target_task: Option<&UserTaskRef>,
) -> StarryResult<(ProbeBuilder<KprobeAuxiliary>, UprobeTargetLease)> {
let elf = &args.name;
let offset = args.offset as usize;
let Some(target_task) = target_task else {
warn!("uprobe: all-process / shared-lib target is unsupported");
return Err(StarryError::Unsupported);
};
let target = UprobeTargetLease::register(target_task.as_thread().pid_identity())?;
let aspace = target_task.as_thread().proc_data.pin_aspace()?;
let mm = aspace.lock();
let mut virt_base = None;
for area in mm.vma_inspection_records()? {
if &area.file_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 target {target:?}");
return Err(StarryError::NotFound);
};
let virt_addr = virt_base.as_usize() + offset;
debug!(
"uprobe: target {target:?} 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(target.opaque_id()),
target,
))
}
pub fn perf_event_open_uprobe(
args: PerfProbeArgs,
target_task: Option<&UserTaskRef>,
) -> StarryResult<ProbePerfEvent> {
let (probe, target) = match args.config {
PerfProbeConfig::Raw(PROBE_CONFIG_ENTRY) => {
let (builder, target) = perf_probe_arg_to_uprobe_builder(&args, target_task)?;
(
ProbeTy::Uprobe(crate::uprobe::register_uprobe(builder)),
target,
)
}
PerfProbeConfig::Raw(PROBE_CONFIG_RETURN) => {
warn!("uprobe: uretprobe is not yet supported");
return Err(StarryError::Unsupported);
}
other => {
warn!("uprobe: unsupported perf probe config {other:?}");
return Err(StarryError::Unsupported);
}
};
Ok(ProbePerfEvent::new_uprobe(args, probe, target))
}