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