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 { 30 fn drop(&mut self) { 31 unregister_kprobe(self.kprobe.clone()); 32 } 33 } 34 35 impl KprobePerfEvent { 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 { 60 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 { 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 { 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 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 106 fn fs(&self) -> Arc<dyn FileSystem> { 107 panic!("fs not implemented for PerfEvent"); 108 } 109 110 fn as_any_ref(&self) -> &dyn Any { 111 self 112 } 113 114 fn list(&self) -> Result<Vec<String>> { 115 Err(SystemError::ENOSYS) 116 } 117 118 fn page_cache(&self) -> Option<Arc<PageCache>> { 119 None 120 } 121 } 122 123 impl PerfEventOps for KprobePerfEvent { 124 fn set_bpf_prog(&self, bpf_prog: Arc<File>) -> Result<()> { 125 self.do_set_bpf_prog(bpf_prog) 126 } 127 fn enable(&self) -> Result<()> { 128 self.kprobe.write().enable(); 129 Ok(()) 130 } 131 fn disable(&self) -> Result<()> { 132 self.kprobe.write().disable(); 133 Ok(()) 134 } 135 136 fn readable(&self) -> bool { 137 true 138 } 139 } 140 141 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