1*fae6e9adSlinfeng use alloc::sync::Arc; 2*fae6e9adSlinfeng use core::{ 3*fae6e9adSlinfeng arch::riscv64::sfence_vma_all, 4*fae6e9adSlinfeng fmt::Debug, 5*fae6e9adSlinfeng ops::{Deref, DerefMut}, 6*fae6e9adSlinfeng }; 7*fae6e9adSlinfeng 8*fae6e9adSlinfeng use crate::{KprobeBasic, KprobeBuilder, KprobeOps}; 9*fae6e9adSlinfeng const EBREAK_INST: u32 = 0x00100073; // ebreak 10*fae6e9adSlinfeng const C_EBREAK_INST: u32 = 0x9002; // c.ebreak 11*fae6e9adSlinfeng const INSN_LENGTH_MASK: u16 = 0x3; 12*fae6e9adSlinfeng const INSN_LENGTH_32: u16 = 0x3; 13*fae6e9adSlinfeng 14*fae6e9adSlinfeng #[derive(Debug)] 15*fae6e9adSlinfeng pub struct Kprobe { 16*fae6e9adSlinfeng basic: KprobeBasic, 17*fae6e9adSlinfeng point: Arc<Rv64KprobePoint>, 18*fae6e9adSlinfeng } 19*fae6e9adSlinfeng 20*fae6e9adSlinfeng #[derive(Debug)] 21*fae6e9adSlinfeng enum OpcodeTy { 22*fae6e9adSlinfeng Inst16(u16), 23*fae6e9adSlinfeng Inst32(u32), 24*fae6e9adSlinfeng } 25*fae6e9adSlinfeng #[derive(Debug)] 26*fae6e9adSlinfeng pub struct Rv64KprobePoint { 27*fae6e9adSlinfeng addr: usize, 28*fae6e9adSlinfeng old_instruction: OpcodeTy, 29*fae6e9adSlinfeng inst_tmp: [u8; 8], 30*fae6e9adSlinfeng } 31*fae6e9adSlinfeng 32*fae6e9adSlinfeng impl Deref for Kprobe { 33*fae6e9adSlinfeng type Target = KprobeBasic; 34*fae6e9adSlinfeng deref(&self) -> &Self::Target35*fae6e9adSlinfeng fn deref(&self) -> &Self::Target { 36*fae6e9adSlinfeng &self.basic 37*fae6e9adSlinfeng } 38*fae6e9adSlinfeng } 39*fae6e9adSlinfeng 40*fae6e9adSlinfeng impl DerefMut for Kprobe { deref_mut(&mut self) -> &mut Self::Target41*fae6e9adSlinfeng fn deref_mut(&mut self) -> &mut Self::Target { 42*fae6e9adSlinfeng &mut self.basic 43*fae6e9adSlinfeng } 44*fae6e9adSlinfeng } 45*fae6e9adSlinfeng 46*fae6e9adSlinfeng impl Kprobe { probe_point(&self) -> &Arc<Rv64KprobePoint>47*fae6e9adSlinfeng pub fn probe_point(&self) -> &Arc<Rv64KprobePoint> { 48*fae6e9adSlinfeng &self.point 49*fae6e9adSlinfeng } 50*fae6e9adSlinfeng } 51*fae6e9adSlinfeng 52*fae6e9adSlinfeng impl Drop for Rv64KprobePoint { drop(&mut self)53*fae6e9adSlinfeng fn drop(&mut self) { 54*fae6e9adSlinfeng let address = self.addr; 55*fae6e9adSlinfeng match self.old_instruction { 56*fae6e9adSlinfeng OpcodeTy::Inst16(inst_16) => unsafe { 57*fae6e9adSlinfeng core::ptr::write(address as *mut u16, inst_16); 58*fae6e9adSlinfeng }, 59*fae6e9adSlinfeng OpcodeTy::Inst32(inst_32) => unsafe { 60*fae6e9adSlinfeng core::ptr::write(address as *mut u32, inst_32); 61*fae6e9adSlinfeng }, 62*fae6e9adSlinfeng } 63*fae6e9adSlinfeng unsafe { 64*fae6e9adSlinfeng sfence_vma_all(); 65*fae6e9adSlinfeng } 66*fae6e9adSlinfeng log::trace!( 67*fae6e9adSlinfeng "Kprobe::uninstall: address: {:#x}, old_instruction: {:?}", 68*fae6e9adSlinfeng address, 69*fae6e9adSlinfeng self.old_instruction 70*fae6e9adSlinfeng ); 71*fae6e9adSlinfeng } 72*fae6e9adSlinfeng } 73*fae6e9adSlinfeng 74*fae6e9adSlinfeng impl KprobeBuilder { install(self) -> (Kprobe, Arc<Rv64KprobePoint>)75*fae6e9adSlinfeng pub fn install(self) -> (Kprobe, Arc<Rv64KprobePoint>) { 76*fae6e9adSlinfeng let probe_point = match &self.probe_point { 77*fae6e9adSlinfeng Some(point) => point.clone(), 78*fae6e9adSlinfeng None => self.replace_inst(), 79*fae6e9adSlinfeng }; 80*fae6e9adSlinfeng let kprobe = Kprobe { 81*fae6e9adSlinfeng basic: KprobeBasic::from(self), 82*fae6e9adSlinfeng point: probe_point.clone(), 83*fae6e9adSlinfeng }; 84*fae6e9adSlinfeng (kprobe, probe_point) 85*fae6e9adSlinfeng } 86*fae6e9adSlinfeng /// # 安装kprobe 87*fae6e9adSlinfeng /// 88*fae6e9adSlinfeng /// 不同的架构下需要保存原指令,然后替换为断点指令 replace_inst(&self) -> Arc<Rv64KprobePoint>89*fae6e9adSlinfeng fn replace_inst(&self) -> Arc<Rv64KprobePoint> { 90*fae6e9adSlinfeng let address = self.symbol_addr + self.offset; 91*fae6e9adSlinfeng let inst_16 = unsafe { core::ptr::read(address as *const u16) }; 92*fae6e9adSlinfeng // See https://elixir.bootlin.com/linux/v6.10.2/source/arch/riscv/kernel/probes/kprobes.c#L68 93*fae6e9adSlinfeng let is_inst_16 = if (inst_16 & INSN_LENGTH_MASK) == INSN_LENGTH_32 { 94*fae6e9adSlinfeng false 95*fae6e9adSlinfeng } else { 96*fae6e9adSlinfeng true 97*fae6e9adSlinfeng }; 98*fae6e9adSlinfeng let mut point = Rv64KprobePoint { 99*fae6e9adSlinfeng old_instruction: OpcodeTy::Inst16(0), 100*fae6e9adSlinfeng inst_tmp: [0; 8], 101*fae6e9adSlinfeng addr: address, 102*fae6e9adSlinfeng }; 103*fae6e9adSlinfeng let inst_tmp_ptr = point.inst_tmp.as_ptr() as usize; 104*fae6e9adSlinfeng if is_inst_16 { 105*fae6e9adSlinfeng point.old_instruction = OpcodeTy::Inst16(inst_16); 106*fae6e9adSlinfeng unsafe { 107*fae6e9adSlinfeng core::ptr::write(address as *mut u16, C_EBREAK_INST as u16); 108*fae6e9adSlinfeng // inst_16 :0-16 109*fae6e9adSlinfeng // c.ebreak:16-32 110*fae6e9adSlinfeng core::ptr::write(inst_tmp_ptr as *mut u16, inst_16); 111*fae6e9adSlinfeng core::ptr::write((inst_tmp_ptr + 2) as *mut u16, C_EBREAK_INST as u16); 112*fae6e9adSlinfeng } 113*fae6e9adSlinfeng } else { 114*fae6e9adSlinfeng let inst_32 = unsafe { core::ptr::read(address as *const u32) }; 115*fae6e9adSlinfeng point.old_instruction = OpcodeTy::Inst32(inst_32); 116*fae6e9adSlinfeng unsafe { 117*fae6e9adSlinfeng core::ptr::write(address as *mut u32, EBREAK_INST); 118*fae6e9adSlinfeng // inst_32 :0-32 119*fae6e9adSlinfeng // ebreak :32-64 120*fae6e9adSlinfeng core::ptr::write(inst_tmp_ptr as *mut u32, inst_32); 121*fae6e9adSlinfeng core::ptr::write((inst_tmp_ptr + 4) as *mut u32, EBREAK_INST); 122*fae6e9adSlinfeng } 123*fae6e9adSlinfeng } 124*fae6e9adSlinfeng unsafe { 125*fae6e9adSlinfeng sfence_vma_all(); 126*fae6e9adSlinfeng } 127*fae6e9adSlinfeng log::trace!( 128*fae6e9adSlinfeng "Kprobe::install: address: {:#x}, func_name: {:?}, opcode: {:x?}", 129*fae6e9adSlinfeng address, 130*fae6e9adSlinfeng self.symbol, 131*fae6e9adSlinfeng point.old_instruction 132*fae6e9adSlinfeng ); 133*fae6e9adSlinfeng Arc::new(point) 134*fae6e9adSlinfeng } 135*fae6e9adSlinfeng } 136*fae6e9adSlinfeng 137*fae6e9adSlinfeng impl KprobeOps for Rv64KprobePoint { return_address(&self) -> usize138*fae6e9adSlinfeng fn return_address(&self) -> usize { 139*fae6e9adSlinfeng let address = self.addr; 140*fae6e9adSlinfeng match self.old_instruction { 141*fae6e9adSlinfeng OpcodeTy::Inst16(_) => address + 2, 142*fae6e9adSlinfeng OpcodeTy::Inst32(_) => address + 4, 143*fae6e9adSlinfeng } 144*fae6e9adSlinfeng } single_step_address(&self) -> usize145*fae6e9adSlinfeng fn single_step_address(&self) -> usize { 146*fae6e9adSlinfeng self.inst_tmp.as_ptr() as usize 147*fae6e9adSlinfeng } debug_address(&self) -> usize148*fae6e9adSlinfeng fn debug_address(&self) -> usize { 149*fae6e9adSlinfeng match self.old_instruction { 150*fae6e9adSlinfeng OpcodeTy::Inst16(_) => self.inst_tmp.as_ptr() as usize + 2, 151*fae6e9adSlinfeng OpcodeTy::Inst32(_) => self.inst_tmp.as_ptr() as usize + 4, 152*fae6e9adSlinfeng } 153*fae6e9adSlinfeng } break_address(&self) -> usize154*fae6e9adSlinfeng fn break_address(&self) -> usize { 155*fae6e9adSlinfeng self.addr 156*fae6e9adSlinfeng } 157*fae6e9adSlinfeng } 158