xref: /DragonOS/kernel/src/debug/kprobe/mod.rs (revision 7b0ef10895108a0de5ff5ef3d2f93f40cf2e33a5)
1 use crate::debug::kprobe::args::KprobeInfo;
2 use crate::libs::rwlock::RwLock;
3 use crate::libs::spinlock::SpinLock;
4 use alloc::collections::BTreeMap;
5 use alloc::sync::Arc;
6 use alloc::vec::Vec;
7 use kprobe::{Kprobe, KprobeBuilder, KprobeOps, KprobePoint};
8 use system_error::SystemError;
9 
10 pub mod args;
11 #[cfg(feature = "kprobe_test")]
12 mod test;
13 
14 pub type LockKprobe = Arc<RwLock<Kprobe>>;
15 pub static KPROBE_MANAGER: SpinLock<KprobeManager> = SpinLock::new(KprobeManager::new());
16 static KPROBE_POINT_LIST: SpinLock<BTreeMap<usize, Arc<KprobePoint>>> =
17     SpinLock::new(BTreeMap::new());
18 
19 /// 管理所有的kprobe探测点
20 #[derive(Debug, Default)]
21 pub struct KprobeManager {
22     break_list: BTreeMap<usize, Vec<LockKprobe>>,
23     debug_list: BTreeMap<usize, Vec<LockKprobe>>,
24 }
25 
26 impl KprobeManager {
27     pub const fn new() -> Self {
28         KprobeManager {
29             break_list: BTreeMap::new(),
30             debug_list: BTreeMap::new(),
31         }
32     }
33     /// # 插入一个kprobe
34     ///
35     /// ## 参数
36     /// - `kprobe`: kprobe的实例
37     pub fn insert_kprobe(&mut self, kprobe: LockKprobe) {
38         let probe_point = kprobe.read().probe_point().clone();
39         self.insert_break_point(probe_point.break_address(), kprobe.clone());
40         self.insert_debug_point(probe_point.debug_address(), kprobe);
41     }
42 
43     /// # 向break_list中插入一个kprobe
44     ///
45     /// ## 参数
46     /// - `address`: kprobe的地址, 由`KprobePoint::break_address()`或者`KprobeBuilder::probe_addr()`返回
47     /// - `kprobe`: kprobe的实例
48     fn insert_break_point(&mut self, address: usize, kprobe: LockKprobe) {
49         let list = self.break_list.entry(address).or_default();
50         list.push(kprobe);
51     }
52 
53     /// # 向debug_list中插入一个kprobe
54     ///
55     /// ## 参数
56     /// - `address`: kprobe的单步执行地址,由`KprobePoint::debug_address()`返回
57     /// - `kprobe`: kprobe的实例
58     fn insert_debug_point(&mut self, address: usize, kprobe: LockKprobe) {
59         let list = self.debug_list.entry(address).or_default();
60         list.push(kprobe);
61     }
62 
63     pub fn get_break_list(&self, address: usize) -> Option<&Vec<LockKprobe>> {
64         self.break_list.get(&address)
65     }
66 
67     pub fn get_debug_list(&self, address: usize) -> Option<&Vec<LockKprobe>> {
68         self.debug_list.get(&address)
69     }
70 
71     /// # 返回一个地址上注册的kprobe数量
72     ///
73     /// ## 参数
74     /// - `address`: kprobe的地址, 由`KprobePoint::break_address()`或者`KprobeBuilder::probe_addr()`返回
75     pub fn kprobe_num(&self, address: usize) -> usize {
76         self.break_list_len(address)
77     }
78 
79     #[inline]
80     fn break_list_len(&self, address: usize) -> usize {
81         self.break_list
82             .get(&address)
83             .map(|list| list.len())
84             .unwrap_or(0)
85     }
86     #[inline]
87     fn debug_list_len(&self, address: usize) -> usize {
88         self.debug_list
89             .get(&address)
90             .map(|list| list.len())
91             .unwrap_or(0)
92     }
93 
94     /// # 移除一个kprobe
95     ///
96     /// ## 参数
97     /// - `kprobe`: kprobe的实例
98     pub fn remove_kprobe(&mut self, kprobe: &LockKprobe) {
99         let probe_point = kprobe.read().probe_point().clone();
100         self.remove_one_break(probe_point.break_address(), kprobe);
101         self.remove_one_debug(probe_point.debug_address(), kprobe);
102     }
103 
104     /// # 从break_list中移除一个kprobe
105     ///
106     /// 如果没有其他kprobe注册在这个地址上,则删除列表
107     ///
108     /// ## 参数
109     /// - `address`: kprobe的地址, 由`KprobePoint::break_address()`或者`KprobeBuilder::probe_addr()`返回
110     /// - `kprobe`: kprobe的实例
111     fn remove_one_break(&mut self, address: usize, kprobe: &LockKprobe) {
112         if let Some(list) = self.break_list.get_mut(&address) {
113             list.retain(|x| !Arc::ptr_eq(x, kprobe));
114         }
115         if self.break_list_len(address) == 0 {
116             self.break_list.remove(&address);
117         }
118     }
119 
120     /// # 从debug_list中移除一个kprobe
121     ///
122     /// 如果没有其他kprobe注册在这个地址上,则删除列表
123     ///
124     /// ## 参数
125     /// - `address`: kprobe的单步执行地址,由`KprobePoint::debug_address()`返回
126     /// - `kprobe`: kprobe的实例
127     fn remove_one_debug(&mut self, address: usize, kprobe: &LockKprobe) {
128         if let Some(list) = self.debug_list.get_mut(&address) {
129             list.retain(|x| !Arc::ptr_eq(x, kprobe));
130         }
131         if self.debug_list_len(address) == 0 {
132             self.debug_list.remove(&address);
133         }
134     }
135 }
136 
137 #[cfg(feature = "kprobe_test")]
138 #[allow(unused)]
139 /// This function is only used for testing kprobe
140 pub fn kprobe_test() {
141     test::kprobe_test();
142 }
143 
144 /// # 注册一个kprobe
145 ///
146 /// 该函数会根据`symbol`查找对应的函数地址,如果找不到则返回错误。
147 ///
148 /// ## 参数
149 /// - `kprobe_info`: kprobe的信息
150 pub fn register_kprobe(kprobe_info: KprobeInfo) -> Result<LockKprobe, SystemError> {
151     let kprobe_builder = KprobeBuilder::try_from(kprobe_info)?;
152     let address = kprobe_builder.probe_addr();
153     let existed_point = KPROBE_POINT_LIST.lock().get(&address).map(Clone::clone);
154     let kprobe = match existed_point {
155         Some(existed_point) => {
156             kprobe_builder
157                 .with_probe_point(existed_point.clone())
158                 .install()
159                 .0
160         }
161         None => {
162             let (kprobe, probe_point) = kprobe_builder.install();
163             KPROBE_POINT_LIST.lock().insert(address, probe_point);
164             kprobe
165         }
166     };
167     let kprobe = Arc::new(RwLock::new(kprobe));
168     KPROBE_MANAGER.lock().insert_kprobe(kprobe.clone());
169     Ok(kprobe)
170 }
171 
172 /// # 注销一个kprobe
173 ///
174 /// ## 参数
175 /// - `kprobe`: 已安装的kprobe
176 pub fn unregister_kprobe(kprobe: LockKprobe) {
177     let kprobe_addr = kprobe.read().probe_point().break_address();
178     KPROBE_MANAGER.lock().remove_kprobe(&kprobe);
179     // 如果没有其他kprobe注册在这个地址上,则删除探测点
180     if KPROBE_MANAGER.lock().kprobe_num(kprobe_addr) == 0 {
181         KPROBE_POINT_LIST.lock().remove(&kprobe_addr);
182     }
183 }
184