Skip to main content

kprobe/
lib.rs

1//! A Rust library for dynamic kernel probing (kprobes and kretprobes).
2//!! This library provides a safe and ergonomic interface for registering and managing kprobes
3//! and kretprobes in a kernel environment.
4//!! It supports multiple architectures, including x86_64, riscv64, and loongarch64.
5//!! # Features
6//! - Register and unregister kprobes and kretprobes.
7//! - Support for pre-handler and post-handler functions.
8//! - Safe management of probe points and handlers.
9//! - Architecture-specific implementations for handling breakpoints and single-stepping.
10//!
11#![no_std]
12#![deny(missing_docs)]
13extern crate alloc;
14
15mod arch;
16mod kprobe;
17mod kretprobe;
18mod manager;
19mod uprobe;
20mod uretprobe;
21
22use alloc::sync::Arc;
23use core::ops::Deref;
24
25pub use arch::*;
26pub use kprobe::*;
27pub use kretprobe::*;
28use lock_api::RawMutex;
29pub use manager::*;
30pub use uprobe::*;
31pub use uretprobe::*;
32
33use crate::arch::retprobe::RetprobeData;
34
35/// An enum representing either a kprobe or a kretprobe.
36#[derive(Debug)]
37#[allow(missing_docs)]
38pub enum UniProbe<L: RawMutex + 'static, F: KprobeAuxiliaryOps> {
39    Kprobe(Arc<Kprobe<L, F>>),
40    Kretprobe(Arc<Kretprobe<L, F>>),
41    Uprobe(Arc<Uprobe<L, F>>),
42    Uretprobe(Arc<Uretprobe<L, F>>),
43}
44
45impl<L: RawMutex + 'static, F: KprobeAuxiliaryOps> Deref for UniProbe<L, F> {
46    type Target = Kprobe<L, F>;
47    fn deref(&self) -> &Self::Target {
48        match self {
49            UniProbe::Kprobe(kprobe) => kprobe,
50            UniProbe::Kretprobe(kretprobe) => kretprobe.kprobe(),
51            UniProbe::Uprobe(uprobe) => uprobe,
52            UniProbe::Uretprobe(uretprobe) => uretprobe.kprobe(),
53        }
54    }
55}
56
57impl<L: RawMutex + 'static, F: KprobeAuxiliaryOps> UniProbe<L, F> {
58    /// Get the probe point of the probe.
59    pub fn probe_point(&self) -> &Arc<ProbePoint<F>> {
60        match self {
61            UniProbe::Kprobe(kprobe) => kprobe.probe_point(),
62            UniProbe::Kretprobe(kretprobe) => kretprobe.kprobe().probe_point(),
63            UniProbe::Uprobe(uprobe) => uprobe.probe_point(),
64            UniProbe::Uretprobe(uretprobe) => uretprobe.kprobe().probe_point(),
65        }
66    }
67    /// Check if the probe is a kretprobe.
68    pub fn is_kretprobe(&self) -> bool {
69        matches!(self, UniProbe::Kretprobe(_))
70    }
71}
72
73impl<L: RawMutex + 'static, F: KprobeAuxiliaryOps> Clone for UniProbe<L, F> {
74    fn clone(&self) -> Self {
75        match self {
76            UniProbe::Kprobe(kprobe) => UniProbe::Kprobe(kprobe.clone()),
77            UniProbe::Kretprobe(kretprobe) => UniProbe::Kretprobe(kretprobe.clone()),
78            UniProbe::Uprobe(uprobe) => UniProbe::Uprobe(uprobe.clone()),
79            UniProbe::Uretprobe(uretprobe) => UniProbe::Uretprobe(uretprobe.clone()),
80        }
81    }
82}
83
84/// Register a kretprobe.
85///
86/// See [`register_kprobe`] for more details.
87pub fn register_kretprobe<L: RawMutex + 'static, F: KprobeAuxiliaryOps + 'static>(
88    manager: &mut ProbeManager<L, F>,
89    kprobe_point_list: &mut ProbePointList<F>,
90    kretprobe_builder: KretprobeBuilder<L>,
91) -> Arc<Kretprobe<L, F>> {
92    let (entry_handler, ret_handler) = kretprobe_builder.handler();
93
94    let kprobe_builder = ProbeBuilder::from(kretprobe_builder);
95    let kprobe = kprobe::__register_kprobe(kprobe_point_list, kprobe_builder);
96
97    let kretprobe = Kretprobe::new(kprobe, entry_handler, ret_handler);
98    let kretprobe = Arc::new(kretprobe);
99
100    let data = kretprobe.kprobe().get_data();
101    let data = data.as_any().downcast_ref::<RetprobeData<L, F>>().unwrap();
102    *data.retprobe.lock() = Arc::downgrade(&kretprobe);
103
104    manager.insert_probe(UniProbe::Kretprobe(kretprobe.clone()));
105    kretprobe
106}
107
108/// Unregister a kretprobe.
109///
110/// See [`unregister_kprobe`] for more details.
111pub fn unregister_kretprobe<L: RawMutex + 'static, F: KprobeAuxiliaryOps>(
112    manager: &mut ProbeManager<L, F>,
113    kprobe_point_list: &mut ProbePointList<F>,
114    kretprobe: Arc<Kretprobe<L, F>>,
115) {
116    let kprobe = kretprobe.kprobe();
117    let kprobe_addr = kprobe.probe_point().break_address();
118    manager.remove_probe(UniProbe::Kretprobe(kretprobe));
119
120    if manager.kprobe_num(kprobe_addr) == 0 {
121        kprobe_point_list.remove(&kprobe_addr);
122    }
123}