xref: /DragonOS/kernel/crates/kprobe/src/arch/rv64/mod.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
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