use alloc::sync::Arc;
use lock_api::RawMutex;
use crate::{
KprobeAuxiliaryOps, KprobeOps, ProbeBuilder, ProbeManager, ProbePointList, PtRegs, UniProbe,
arch::Probe, clear_single_step, setup_single_step,
};
pub type Uprobe<L, F> = Probe<L, F>;
pub fn register_uprobe<L: RawMutex + 'static, F: KprobeAuxiliaryOps>(
manager: &mut ProbeManager<L, F>,
uprobe_point_list: &mut ProbePointList<F>,
uprobe_builder: ProbeBuilder<F>,
) -> Arc<Uprobe<L, F>> {
assert!(
uprobe_builder.user_pid.is_some(),
"The builder must be for uprobe"
);
let uprobe = crate::__register_kprobe(uprobe_point_list, uprobe_builder);
let uprobe = Arc::new(uprobe);
manager.insert_probe(UniProbe::Uprobe(uprobe.clone()));
uprobe
}
pub fn unregister_uprobe<L: RawMutex + 'static, F: KprobeAuxiliaryOps>(
manager: &mut ProbeManager<L, F>,
uprobe_point_list: &mut ProbePointList<F>,
uprobe: Arc<Uprobe<L, F>>,
) {
let uprobe_addr = uprobe.probe_point().break_address();
manager.remove_probe(UniProbe::Uprobe(uprobe));
if manager.kprobe_num(uprobe_addr) == 0 {
uprobe_point_list.remove(&uprobe_addr);
}
}
pub fn uprobe_handler_from_break<L: RawMutex + 'static, F: KprobeAuxiliaryOps>(
uprobe_manager: &mut ProbeManager<L, F>,
pt_regs: &mut PtRegs,
) -> Option<()> {
let break_addr = pt_regs.break_address();
let uprobe_list = uprobe_manager.get_break_list(break_addr);
if let Some(uprobe_list) = uprobe_list {
for uprobe in uprobe_list {
if uprobe.is_enabled() {
uprobe.call_pre_handler(pt_regs);
}
}
let point = uprobe_list[0].probe_point();
let dynamic_user_ptr = point.dynamic_user_ptr();
if dynamic_user_ptr != 0 {
setup_single_step(pt_regs, dynamic_user_ptr);
} else {
let old_instruction_len = point.old_instruction_len();
let single_step_address = point.single_step_address() as *mut u8;
let pid = point.pid();
let user_ptr = F::alloc_user_exec_memory(pid, |ptr| {
unsafe {
core::ptr::copy_nonoverlapping(single_step_address, ptr, old_instruction_len);
}
});
let old_debug_address = point.debug_address();
let new_debug_address = point.set_dynamic_user_ptr(user_ptr as usize);
uprobe_manager
.replace_debug_list_with_new_address(old_debug_address, new_debug_address);
setup_single_step(pt_regs, user_ptr as usize);
}
Some(())
} else {
uprobe_handler_from_debug(uprobe_manager, pt_regs)
}
}
pub fn uprobe_handler_from_debug<L: RawMutex + 'static, F: KprobeAuxiliaryOps>(
uprobe_manager: &mut ProbeManager<L, F>,
pt_regs: &mut PtRegs,
) -> Option<()> {
let pc = pt_regs.debug_address();
if let Some(uprobe_list) = uprobe_manager.get_debug_list(pc) {
for uprobe in uprobe_list {
if uprobe.is_enabled() {
uprobe.call_post_handler(pt_regs);
uprobe.call_event_callback(pt_regs);
}
}
let return_address = uprobe_list[0].probe_point().return_address();
clear_single_step(pt_regs, return_address);
Some(())
} else {
log::debug!("There is no uprobe on pc {pc:#x}");
None
}
}