xref: /DragonOS/kernel/src/perf/kprobe.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 use super::Result;
2 use crate::arch::interrupt::TrapFrame;
3 use crate::arch::kprobe::KProbeContext;
4 use crate::bpf::helper::BPF_HELPER_FUN_SET;
5 use crate::bpf::prog::BpfProg;
6 use crate::debug::kprobe::args::KprobeInfo;
7 use crate::debug::kprobe::{register_kprobe, unregister_kprobe, LockKprobe};
8 use crate::filesystem::vfs::file::{File, PageCache};
9 use crate::filesystem::vfs::{FilePrivateData, FileSystem, IndexNode};
10 use crate::libs::casting::DowncastArc;
11 use crate::libs::spinlock::SpinLockGuard;
12 use crate::perf::util::PerfProbeArgs;
13 use crate::perf::PerfEventOps;
14 use alloc::boxed::Box;
15 use alloc::string::String;
16 use alloc::sync::Arc;
17 use alloc::vec::Vec;
18 use core::any::Any;
19 use core::fmt::Debug;
20 use kprobe::{CallBackFunc, ProbeArgs};
21 use rbpf::EbpfVmRawOwned;
22 use system_error::SystemError;
23 #[derive(Debug)]
24 pub struct KprobePerfEvent {
25     _args: PerfProbeArgs,
26     kprobe: LockKprobe,
27 }
28 
29 impl Drop for KprobePerfEvent {
drop(&mut self)30     fn drop(&mut self) {
31         unregister_kprobe(self.kprobe.clone());
32     }
33 }
34 
35 impl KprobePerfEvent {
do_set_bpf_prog(&self, prog_file: Arc<File>) -> Result<()>36     pub fn do_set_bpf_prog(&self, prog_file: Arc<File>) -> Result<()> {
37         let file = prog_file
38             .inode()
39             .downcast_arc::<BpfProg>()
40             .ok_or(SystemError::EINVAL)?;
41         let prog_slice = file.insns();
42         let mut vm =
43             EbpfVmRawOwned::new(Some(prog_slice.to_vec())).map_err(|_| SystemError::EINVAL)?;
44         vm.register_helper_set(BPF_HELPER_FUN_SET.get())
45             .map_err(|_| SystemError::EINVAL)?;
46         // create a callback to execute the ebpf prog
47         let callback = Box::new(KprobePerfCallBack::new(file, vm));
48         // update callback for kprobe
49         self.kprobe.write().update_event_callback(callback);
50         Ok(())
51     }
52 }
53 
54 pub struct KprobePerfCallBack {
55     _bpf_prog_file: Arc<BpfProg>,
56     vm: EbpfVmRawOwned,
57 }
58 
59 impl KprobePerfCallBack {
new(bpf_prog_file: Arc<BpfProg>, vm: EbpfVmRawOwned) -> Self60     fn new(bpf_prog_file: Arc<BpfProg>, vm: EbpfVmRawOwned) -> Self {
61         Self {
62             _bpf_prog_file: bpf_prog_file,
63             vm,
64         }
65     }
66 }
67 
68 impl CallBackFunc for KprobePerfCallBack {
call(&self, trap_frame: &dyn ProbeArgs)69     fn call(&self, trap_frame: &dyn ProbeArgs) {
70         let trap_frame = trap_frame.as_any().downcast_ref::<TrapFrame>().unwrap();
71         let pt_regs = KProbeContext::from(trap_frame);
72         let probe_context = unsafe {
73             core::slice::from_raw_parts_mut(
74                 &pt_regs as *const KProbeContext as *mut u8,
75                 size_of::<KProbeContext>(),
76             )
77         };
78         let _res = self
79             .vm
80             .execute_program(probe_context)
81             .map_err(|_| SystemError::EINVAL);
82     }
83 }
84 
85 impl IndexNode for KprobePerfEvent {
read_at( &self, _offset: usize, _len: usize, _buf: &mut [u8], _data: SpinLockGuard<FilePrivateData>, ) -> Result<usize>86     fn read_at(
87         &self,
88         _offset: usize,
89         _len: usize,
90         _buf: &mut [u8],
91         _data: SpinLockGuard<FilePrivateData>,
92     ) -> Result<usize> {
93         panic!("read_at not implemented for PerfEvent");
94     }
95 
write_at( &self, _offset: usize, _len: usize, _buf: &[u8], _data: SpinLockGuard<FilePrivateData>, ) -> Result<usize>96     fn write_at(
97         &self,
98         _offset: usize,
99         _len: usize,
100         _buf: &[u8],
101         _data: SpinLockGuard<FilePrivateData>,
102     ) -> Result<usize> {
103         panic!("write_at not implemented for PerfEvent");
104     }
105 
fs(&self) -> Arc<dyn FileSystem>106     fn fs(&self) -> Arc<dyn FileSystem> {
107         panic!("fs not implemented for PerfEvent");
108     }
109 
as_any_ref(&self) -> &dyn Any110     fn as_any_ref(&self) -> &dyn Any {
111         self
112     }
113 
list(&self) -> Result<Vec<String>>114     fn list(&self) -> Result<Vec<String>> {
115         Err(SystemError::ENOSYS)
116     }
117 
page_cache(&self) -> Option<Arc<PageCache>>118     fn page_cache(&self) -> Option<Arc<PageCache>> {
119         None
120     }
121 }
122 
123 impl PerfEventOps for KprobePerfEvent {
set_bpf_prog(&self, bpf_prog: Arc<File>) -> Result<()>124     fn set_bpf_prog(&self, bpf_prog: Arc<File>) -> Result<()> {
125         self.do_set_bpf_prog(bpf_prog)
126     }
enable(&self) -> Result<()>127     fn enable(&self) -> Result<()> {
128         self.kprobe.write().enable();
129         Ok(())
130     }
disable(&self) -> Result<()>131     fn disable(&self) -> Result<()> {
132         self.kprobe.write().disable();
133         Ok(())
134     }
135 
readable(&self) -> bool136     fn readable(&self) -> bool {
137         true
138     }
139 }
140 
perf_event_open_kprobe(args: PerfProbeArgs) -> KprobePerfEvent141 pub fn perf_event_open_kprobe(args: PerfProbeArgs) -> KprobePerfEvent {
142     let symbol = args.name.clone();
143     log::info!("create kprobe for symbol: {symbol}");
144     let kprobe_info = KprobeInfo {
145         pre_handler: |_| {},
146         post_handler: |_| {},
147         fault_handler: None,
148         event_callback: None,
149         symbol: Some(symbol),
150         addr: None,
151         offset: 0,
152         enable: false,
153     };
154     let kprobe = register_kprobe(kprobe_info).expect("create kprobe failed");
155     KprobePerfEvent {
156         _args: args,
157         kprobe,
158     }
159 }
160