1use alloc::{sync::Arc, vec::Vec};
21
22use ax_kspin::{RawSpinNoIrq, SpinNoIrq};
23use ax_memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr, VirtAddrRange};
24use ax_runtime::hal::{
25 cpu::{KernelTrapFrame, UserRegisters},
26 paging::MappingFlags,
27};
28use kprobe::{
29 KprobeAuxiliaryOps, KretprobeBuilder, ProbeBuilder, ProbePointList,
30 register_kprobe as kprobe_crate_register_kprobe,
31 register_kretprobe as kprobe_crate_register_kretprobe, retprobe::RetprobeInstance,
32 unregister_kprobe as kprobe_crate_unregister_kprobe,
33 unregister_kretprobe as kprobe_crate_unregister_kretprobe,
34};
35
36use crate::task::AsThread;
37
38pub type KernelRawMutex = RawSpinNoIrq;
50
51#[derive(Debug)]
52pub struct KernelKprobeOps;
53
54impl KprobeAuxiliaryOps for KernelKprobeOps {
55 fn copy_memory(src: *const u8, dst: *mut u8, len: usize, user_pid: Option<i32>) {
56 if let Some(pid) = user_pid {
57 let task = crate::task::get_task(pid as _).expect("Failed to get task for uprobe");
66 let aspace = task.as_thread().proc_data.aspace();
67 let mm = aspace.lock();
68 let pt = mm.page_table();
69 let mut copied = 0;
70 while copied < len {
71 let vaddr = VirtAddr::from(src as usize + copied);
72 let Ok((paddr, ..)) = pt.query(vaddr) else {
73 warn!(
74 "kprobe copy_memory: user addr {:#x} not mapped",
75 vaddr.as_usize()
76 );
77 return;
78 };
79 let page_off = vaddr.as_usize() & (PAGE_SIZE_4K - 1);
80 let chunk = core::cmp::min(len - copied, PAGE_SIZE_4K - page_off);
81 let kvaddr = ax_runtime::hal::mem::phys_to_virt(paddr);
82 unsafe {
83 core::ptr::copy_nonoverlapping(kvaddr.as_ptr(), dst.add(copied), chunk);
84 }
85 copied += chunk;
86 }
87 } else {
88 unsafe {
89 core::ptr::copy_nonoverlapping(src, dst, len);
90 }
91 }
92 }
93
94 fn set_writeable_for_address<F: FnOnce(*mut u8)>(
95 address: usize,
96 len: usize,
97 user_pid: Option<i32>,
98 action: F,
99 ) {
100 if let Some(pid) = user_pid {
101 let task = crate::task::get_task(pid as _).expect("uprobe: target task gone");
110 let aspace = task.as_thread().proc_data.aspace();
111 let mm = aspace.lock();
112 let vaddr = VirtAddr::from(address);
113 let (paddr, ..) = mm
114 .page_table()
115 .query(vaddr)
116 .expect("uprobe: target address not mapped");
117 let kvaddr = ax_runtime::hal::mem::phys_to_virt(paddr);
118 action(kvaddr.as_mut_ptr());
119 ax_runtime::hal::cache::sync_kernel_text(vaddr.align_down_4k(), PAGE_SIZE_4K);
120 return;
121 }
122 let addr = VirtAddr::from(address);
123 crate::mm::patch_kernel_text(addr, len, action)
124 .expect("kprobe: set_writeable: patch kernel text failed");
125 }
126
127 fn alloc_kernel_exec_memory() -> *mut u8 {
128 let mut guard = ax_mm::kernel_aspace().lock();
129 let range = VirtAddrRange::new(guard.base(), guard.end());
130 let vaddr = guard
131 .find_free_area(guard.base(), PAGE_SIZE_4K, range)
132 .expect("kprobe: no free virtual address for exec memory");
133 guard
134 .map_alloc(
135 vaddr,
136 PAGE_SIZE_4K,
137 MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE,
138 true,
139 )
140 .expect("kprobe: map_alloc for exec memory failed");
141 vaddr.as_mut_ptr()
142 }
143
144 fn free_kernel_exec_memory(ptr: *mut u8) {
145 let vaddr = VirtAddr::from(ptr as usize);
146 let mut guard = ax_mm::kernel_aspace().lock();
147 guard
148 .unmap(vaddr, PAGE_SIZE_4K)
149 .expect("kprobe: unmap exec memory failed");
150 }
151
152 fn alloc_user_exec_memory<F: FnOnce(*mut u8)>(pid: Option<i32>, action: F) -> *mut u8 {
153 let pid = pid.expect("uprobe: alloc_user_exec_memory needs a pid");
158 let task = crate::task::get_task(pid as _).expect("uprobe: target task gone");
159 let aspace = task.as_thread().proc_data.aspace();
160 let mut mm = aspace.lock();
161 let range = VirtAddrRange::new(mm.base(), mm.end());
162 let vaddr = mm
163 .find_free_area(mm.base(), PAGE_SIZE_4K, range, PAGE_SIZE_4K)
164 .expect("uprobe: no free user va for exec memory");
165 let backend = crate::mm::Backend::new_alloc(vaddr, PAGE_SIZE_4K, "uprobe-ols");
166 mm.map(
167 vaddr,
168 PAGE_SIZE_4K,
169 MappingFlags::READ | MappingFlags::EXECUTE | MappingFlags::USER,
170 true,
171 backend,
172 )
173 .expect("uprobe: map user exec memory failed");
174 let (paddr, ..) = mm
175 .page_table()
176 .query(vaddr)
177 .expect("uprobe: exec page not mapped after populate");
178 let kvaddr = ax_runtime::hal::mem::phys_to_virt(paddr);
179 action(kvaddr.as_mut_ptr());
180 ax_runtime::hal::cache::sync_kernel_text(vaddr, PAGE_SIZE_4K);
181 vaddr.as_mut_ptr()
182 }
183
184 fn free_user_exec_memory(pid: Option<i32>, ptr: *mut u8) {
185 let pid = pid.expect("uprobe: free_user_exec_memory needs a pid");
186 let task = crate::task::get_task(pid as _).expect("uprobe: target task gone");
187 let aspace = task.as_thread().proc_data.aspace();
188 let mut mm = aspace.lock();
189 mm.unmap(VirtAddr::from(ptr as usize), PAGE_SIZE_4K)
190 .expect("uprobe: unmap user exec memory failed");
191 }
192
193 fn insert_kretprobe_instance_to_task(instance: RetprobeInstance) {
194 let task = ax_task::current_may_uninit();
195 if let Some(task) = task {
196 let thread = task.try_as_thread();
197 if let Some(thread) = thread {
198 let mut kretprobe_instances = thread.kretprobe_stack.lock();
199 kretprobe_instances.push(instance);
200 return;
201 }
202 }
203 let mut instances = INSTANCE.lock();
205 instances.push(instance);
206 }
207
208 fn pop_kretprobe_instance_from_task() -> RetprobeInstance {
209 let task = ax_task::current_may_uninit();
210 if let Some(task) = task {
211 let thread = task.try_as_thread();
212 if let Some(thread) = thread {
213 let mut kretprobe_instances = thread.kretprobe_stack.lock();
214 return kretprobe_instances
215 .pop()
216 .expect("kretprobe instance stack underflow");
217 }
218 }
219 let mut instances = INSTANCE.lock();
221 instances.pop().unwrap()
222 }
223}
224
225pub(crate) type KprobeManager = kprobe::ProbeManager<KernelRawMutex, KernelKprobeOps>;
226pub(crate) type KprobePointList = ProbePointList<KernelKprobeOps>;
227
228pub type KernelKprobe = kprobe::Kprobe<KernelRawMutex, KernelKprobeOps>;
231pub type KernelKretprobe = kprobe::Kretprobe<KernelRawMutex, KernelKprobeOps>;
233pub type KprobeAuxiliary = KernelKprobeOps;
235
236static KPROBE_MANAGER: KprobeManager = KprobeManager::new();
237static KPROBE_POINT_LIST: SpinNoIrq<KprobePointList> = SpinNoIrq::new(KprobePointList::new());
238static INSTANCE: SpinNoIrq<Vec<RetprobeInstance>> = SpinNoIrq::new(Vec::new());
239
240fn with_manager<F, R>(f: F) -> R
241where
242 F: FnOnce(&KprobeManager) -> R,
243{
244 f(&KPROBE_MANAGER)
245}
246
247fn with_manager_and_list<F, R>(f: F) -> R
248where
249 F: FnOnce(&KprobeManager, &mut KprobePointList) -> R,
250{
251 let mut list = KPROBE_POINT_LIST.try_lock().unwrap();
252 f(&KPROBE_MANAGER, &mut list)
253}
254
255#[inline(never)]
257pub fn register_kprobe(builder: ProbeBuilder<KernelKprobeOps>) -> Arc<KernelKprobe> {
258 with_manager_and_list(|mgr, list| {
259 kprobe_crate_register_kprobe(mgr, list, builder).expect("Failed to register kprobe")
260 })
261}
262
263#[inline(never)]
265pub fn unregister_kprobe(kprobe: Arc<KernelKprobe>) {
266 with_manager_and_list(|mgr, list| kprobe_crate_unregister_kprobe(mgr, list, kprobe));
267}
268
269#[inline(never)]
271pub fn register_kretprobe(builder: KretprobeBuilder<KernelRawMutex>) -> Arc<KernelKretprobe> {
272 with_manager_and_list(|mgr, list| {
273 kprobe_crate_register_kretprobe(mgr, list, builder).expect("Failed to register kretprobe")
274 })
275}
276
277#[inline(never)]
279pub fn unregister_kretprobe(kretprobe: Arc<KernelKretprobe>) {
280 with_manager_and_list(|mgr, list| kprobe_crate_unregister_kretprobe(mgr, list, kretprobe));
281}
282
283pub(crate) fn trapframe_to_ptregs(tf: &UserRegisters) -> kprobe::PtRegs {
284 #[cfg(target_arch = "x86_64")]
285 {
286 kprobe::PtRegs {
287 r15: tf.r15 as usize,
288 r14: tf.r14 as usize,
289 r13: tf.r13 as usize,
290 r12: tf.r12 as usize,
291 rbp: tf.rbp as usize,
292 rbx: tf.rbx as usize,
293 r11: tf.r11 as usize,
294 r10: tf.r10 as usize,
295 r9: tf.r9 as usize,
296 r8: tf.r8 as usize,
297 rax: tf.rax as usize,
298 rcx: tf.rcx as usize,
299 rdx: tf.rdx as usize,
300 rsi: tf.rsi as usize,
301 rdi: tf.rdi as usize,
302 orig_rax: tf.vector as usize,
303 rip: tf.rip as usize,
304 cs: tf.cs as usize,
305 rflags: tf.rflags as usize,
306 rsp: tf.rsp as usize,
307 ss: tf.ss as usize,
308 }
309 }
310 #[cfg(target_arch = "riscv64")]
311 {
312 kprobe::PtRegs {
313 epc: tf.sepc,
314 ra: tf.regs.ra,
315 sp: tf.regs.sp,
316 gp: tf.regs.gp,
317 tp: tf.regs.tp,
318 t0: tf.regs.t0,
319 t1: tf.regs.t1,
320 t2: tf.regs.t2,
321 s0: tf.regs.s0,
322 s1: tf.regs.s1,
323 a0: tf.regs.a0,
324 a1: tf.regs.a1,
325 a2: tf.regs.a2,
326 a3: tf.regs.a3,
327 a4: tf.regs.a4,
328 a5: tf.regs.a5,
329 a6: tf.regs.a6,
330 a7: tf.regs.a7,
331 s2: tf.regs.s2,
332 s3: tf.regs.s3,
333 s4: tf.regs.s4,
334 s5: tf.regs.s5,
335 s6: tf.regs.s6,
336 s7: tf.regs.s7,
337 s8: tf.regs.s8,
338 s9: tf.regs.s9,
339 s10: tf.regs.s10,
340 s11: tf.regs.s11,
341 t3: tf.regs.t3,
342 t4: tf.regs.t4,
343 t5: tf.regs.t5,
344 t6: tf.regs.t6,
345 status: tf.sstatus.bits(),
346 badaddr: 0,
347 cause: 0,
348 orig_a0: tf.regs.a0,
349 }
350 }
351 #[cfg(target_arch = "aarch64")]
352 {
353 kprobe::PtRegs {
354 regs: tf.x,
355 sp: 0, pc: tf.elr,
357 pstate: tf.spsr,
358 orig_x0: tf.x[0],
359 syscallno: -1,
360 unused2: 0,
361 }
362 }
363 #[cfg(target_arch = "loongarch64")]
364 {
365 kprobe::PtRegs {
366 regs: [
367 tf.regs.zero,
368 tf.regs.ra,
369 tf.regs.tp,
370 tf.regs.sp,
371 tf.regs.a0,
372 tf.regs.a1,
373 tf.regs.a2,
374 tf.regs.a3,
375 tf.regs.a4,
376 tf.regs.a5,
377 tf.regs.a6,
378 tf.regs.a7,
379 tf.regs.t0,
380 tf.regs.t1,
381 tf.regs.t2,
382 tf.regs.t3,
383 tf.regs.t4,
384 tf.regs.t5,
385 tf.regs.t6,
386 tf.regs.t7,
387 tf.regs.t8,
388 tf.regs.u0,
389 tf.regs.fp,
390 tf.regs.s0,
391 tf.regs.s1,
392 tf.regs.s2,
393 tf.regs.s3,
394 tf.regs.s4,
395 tf.regs.s5,
396 tf.regs.s6,
397 tf.regs.s7,
398 tf.regs.s8,
399 ],
400 orig_a0: 0,
401 csr_era: tf.era,
402 csr_badvaddr: 0,
403 csr_crmd: 0,
404 csr_prmd: tf.prmd,
405 csr_euen: 0,
406 csr_ecfg: 0,
407 csr_estat: 0,
408 }
409 }
410}
411
412pub(crate) fn ptregs_write_back(pt: &kprobe::PtRegs, tf: &mut UserRegisters) {
413 #[cfg(target_arch = "x86_64")]
414 {
415 tf.r15 = pt.r15 as u64;
416 tf.r14 = pt.r14 as u64;
417 tf.r13 = pt.r13 as u64;
418 tf.r12 = pt.r12 as u64;
419 tf.rbp = pt.rbp as u64;
420 tf.rbx = pt.rbx as u64;
421 tf.r11 = pt.r11 as u64;
422 tf.r10 = pt.r10 as u64;
423 tf.r9 = pt.r9 as u64;
424 tf.r8 = pt.r8 as u64;
425 tf.rax = pt.rax as u64;
426 tf.rcx = pt.rcx as u64;
427 tf.rdx = pt.rdx as u64;
428 tf.rsi = pt.rsi as u64;
429 tf.rdi = pt.rdi as u64;
430 tf.rip = pt.rip as u64;
431 tf.cs = pt.cs as u64;
432 tf.vector = pt.orig_rax as u64;
433 tf.rflags = pt.rflags as u64;
434 tf.rsp = pt.rsp as u64;
435 tf.ss = pt.ss as u64;
436 }
437 #[cfg(target_arch = "riscv64")]
438 {
439 tf.sepc = pt.epc;
440 tf.regs.ra = pt.ra;
441 tf.regs.sp = pt.sp;
442 tf.regs.gp = pt.gp;
443 tf.regs.tp = pt.tp;
444 tf.regs.t0 = pt.t0;
445 tf.regs.t1 = pt.t1;
446 tf.regs.t2 = pt.t2;
447 tf.regs.s0 = pt.s0;
448 tf.regs.s1 = pt.s1;
449 tf.regs.a0 = pt.a0;
450 tf.regs.a1 = pt.a1;
451 tf.regs.a2 = pt.a2;
452 tf.regs.a3 = pt.a3;
453 tf.regs.a4 = pt.a4;
454 tf.regs.a5 = pt.a5;
455 tf.regs.a6 = pt.a6;
456 tf.regs.a7 = pt.a7;
457 tf.regs.s2 = pt.s2;
458 tf.regs.s3 = pt.s3;
459 tf.regs.s4 = pt.s4;
460 tf.regs.s5 = pt.s5;
461 tf.regs.s6 = pt.s6;
462 tf.regs.s7 = pt.s7;
463 tf.regs.s8 = pt.s8;
464 tf.regs.s9 = pt.s9;
465 tf.regs.s10 = pt.s10;
466 tf.regs.s11 = pt.s11;
467 tf.regs.t3 = pt.t3;
468 tf.regs.t4 = pt.t4;
469 tf.regs.t5 = pt.t5;
470 tf.regs.t6 = pt.t6;
471 }
472 #[cfg(target_arch = "aarch64")]
473 {
474 tf.x = pt.regs;
475 tf.elr = pt.pc;
476 tf.spsr = pt.pstate;
477 }
478 #[cfg(target_arch = "loongarch64")]
479 {
480 tf.regs.zero = pt.regs[0];
481 tf.regs.ra = pt.regs[1];
482 tf.regs.tp = pt.regs[2];
483 tf.regs.sp = pt.regs[3];
484 tf.regs.a0 = pt.regs[4];
485 tf.regs.a1 = pt.regs[5];
486 tf.regs.a2 = pt.regs[6];
487 tf.regs.a3 = pt.regs[7];
488 tf.regs.a4 = pt.regs[8];
489 tf.regs.a5 = pt.regs[9];
490 tf.regs.a6 = pt.regs[10];
491 tf.regs.a7 = pt.regs[11];
492 tf.regs.t0 = pt.regs[12];
493 tf.regs.t1 = pt.regs[13];
494 tf.regs.t2 = pt.regs[14];
495 tf.regs.t3 = pt.regs[15];
496 tf.regs.t4 = pt.regs[16];
497 tf.regs.t5 = pt.regs[17];
498 tf.regs.t6 = pt.regs[18];
499 tf.regs.t7 = pt.regs[19];
500 tf.regs.t8 = pt.regs[20];
501 tf.regs.u0 = pt.regs[21];
502 tf.regs.fp = pt.regs[22];
503 tf.regs.s0 = pt.regs[23];
504 tf.regs.s1 = pt.regs[24];
505 tf.regs.s2 = pt.regs[25];
506 tf.regs.s3 = pt.regs[26];
507 tf.regs.s4 = pt.regs[27];
508 tf.regs.s5 = pt.regs[28];
509 tf.regs.s6 = pt.regs[29];
510 tf.regs.s7 = pt.regs[30];
511 tf.regs.s8 = pt.regs[31];
512 tf.era = pt.csr_era;
513 tf.prmd = pt.csr_prmd;
514 }
515}
516
517pub fn handle_breakpoint(tf: &mut KernelTrapFrame<'_>) -> bool {
518 let mut updated = tf.snapshot();
519 let mut pt_regs = trapframe_to_ptregs(&updated);
520 let handled = with_manager(|manager| kprobe::kprobe_handler_from_break(manager, &mut pt_regs));
521 if handled.is_some() {
522 ptregs_write_back(&pt_regs, &mut updated);
523 tf.apply_registers(&updated);
524 return true;
525 }
526 false
527}
528
529#[cfg(target_arch = "x86_64")]
530pub fn handle_debug(tf: &mut KernelTrapFrame<'_>) -> bool {
531 let mut updated = tf.snapshot();
532 let mut pt_regs = trapframe_to_ptregs(&updated);
533 let handled = with_manager(|manager| kprobe::kprobe_handler_from_debug(manager, &mut pt_regs));
534 if handled.is_some() {
535 ptregs_write_back(&pt_regs, &mut updated);
536 tf.apply_registers(&updated);
537 return true;
538 }
539 false
540}