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