1 use alloc::sync::Arc; 2 use core::ops::{Deref, DerefMut}; 3 4 use crate::{KprobeBasic, KprobeBuilder, KprobeOps}; 5 6 const BRK_KPROBE_BP: u64 = 10; 7 const BRK_KPROBE_SSTEPBP: u64 = 11; 8 const EBREAK_INST: u32 = 0x002a0000; 9 10 #[derive(Debug)] 11 pub struct Kprobe { 12 basic: KprobeBasic, 13 point: Arc<LA64KprobePoint>, 14 } 15 #[derive(Debug)] 16 pub struct LA64KprobePoint { 17 addr: usize, 18 inst_tmp: [u8; 8], 19 } 20 21 impl Deref for Kprobe { 22 type Target = KprobeBasic; 23 24 fn deref(&self) -> &Self::Target { 25 &self.basic 26 } 27 } 28 29 impl DerefMut for Kprobe { 30 fn deref_mut(&mut self) -> &mut Self::Target { 31 &mut self.basic 32 } 33 } 34 35 impl Kprobe { 36 pub fn probe_point(&self) -> &Arc<LA64KprobePoint> { 37 &self.point 38 } 39 } 40 41 impl Drop for LA64KprobePoint { 42 fn drop(&mut self) { 43 let address = self.addr; 44 let inst_tmp_ptr = self.inst_tmp.as_ptr() as usize; 45 let inst_32 = unsafe { core::ptr::read(inst_tmp_ptr as *const u32) }; 46 unsafe { 47 core::ptr::write(address as *mut u32, inst_32); 48 } 49 log::trace!( 50 "Kprobe::uninstall: address: {:#x}, old_instruction: {:?}", 51 address, 52 inst_32 53 ); 54 } 55 } 56 57 impl KprobeBuilder { 58 pub fn install(self) -> (Kprobe, Arc<LA64KprobePoint>) { 59 let probe_point = match &self.probe_point { 60 Some(point) => point.clone(), 61 None => self.replace_inst(), 62 }; 63 let kprobe = Kprobe { 64 basic: KprobeBasic::from(self), 65 point: probe_point.clone(), 66 }; 67 (kprobe, probe_point) 68 } 69 /// # 安装kprobe 70 /// 71 /// 不同的架构下需要保存原指令,然后替换为断点指令 72 fn replace_inst(&self) -> Arc<LA64KprobePoint> { 73 let address = self.symbol_addr + self.offset; 74 let point = LA64KprobePoint { 75 addr: address, 76 inst_tmp: [0u8; 8], 77 }; 78 let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize; 79 let inst_32 = unsafe { core::ptr::read(address as *const u32) }; 80 unsafe { 81 core::ptr::write(address as *mut u32, EBREAK_INST); 82 // inst_32 :0-32 83 // ebreak :32-64 84 core::ptr::write(inst_tmp_ptr as *mut u32, inst_32); 85 core::ptr::write((inst_tmp_ptr + 4) as *mut u32, EBREAK_INST); 86 } 87 log::trace!( 88 "Kprobe::install: address: {:#x}, func_name: {:?}, opcode: {:x?}", 89 address, 90 self.symbol, 91 inst_32 92 ); 93 } 94 } 95 96 impl KprobeOps for LA64KprobePoint { 97 fn return_address(&self) -> usize { 98 self.addr + 4 99 } 100 101 fn single_step_address(&self) -> usize { 102 self.inst_tmp.as_ptr() as usize 103 } 104 105 fn debug_address(&self) -> usize { 106 self.inst_tmp.as_ptr() as usize + 4 107 } 108 109 fn break_address(&self) -> usize { 110 self.addr 111 } 112 } 113