bpf_api/platform/linux/
probes.rs

1use crate::error::Error;
2use crate::platform::linux::bpf::{CallBpf, Command};
3use crate::platform::linux::perf::{perf_event_attach, perf_event_enable, perf_event_open_by_name};
4use crate::platform::linux::prog::Program;
5use crate::platform::linux::syscalls::{cbzero, close};
6
7use std::collections::HashMap;
8
9#[derive(Default)]
10#[repr(C, align(8))]
11struct BpfRawTracepointOpenAttr {
12    pub name: u64,
13    pub prog_fd: u32,
14}
15
16impl CallBpf for BpfRawTracepointOpenAttr {}
17
18#[derive(Default)]
19#[repr(C, align(8))]
20struct BpfLinkCreateAttr {
21    pub prog_fd: u32,
22    pub target_fd: u32,
23    pub attach_type: u32,
24    pub flags: u32,
25    pub target_btf_id: u32,
26}
27
28impl CallBpf for BpfLinkCreateAttr {}
29
30#[derive(Clone)]
31pub enum AttachInfo {
32    RawTracepoint(String),
33    KProbe((String, u64)),
34    UProbe((String, u64)),
35}
36
37pub struct Probe {
38    attach_info: AttachInfo,
39    attach_fds: HashMap<u32, Vec<u32>>,
40}
41
42impl Probe {
43    /// Create a probe object from a given program.
44    ///
45    /// # Arguments
46    ///
47    /// * `attach_info` - Describes the type of probe and attributes.
48    pub fn create(attach_info: AttachInfo) -> Self {
49        Self {
50            attach_info,
51            attach_fds: HashMap::new(),
52        }
53    }
54
55    /// Attaches the given program to the probe.
56    pub fn attach(&mut self, program: &Program) -> Result<(), Error> {
57        let attach_info = self.attach_info.clone();
58        match &attach_info {
59            AttachInfo::RawTracepoint(name) => self.attach_raw_tracepoint(program, name),
60            AttachInfo::KProbe((name, addr)) => self.attach_probe(program, "kprobe", name, *addr),
61            AttachInfo::UProbe((name, addr)) => self.attach_probe(program, "uprobe", name, *addr),
62        }
63    }
64
65    fn attach_probe(
66        &mut self,
67        program: &Program,
68        probe_name: &str,
69        name: &str,
70        addr: u64,
71    ) -> Result<(), Error> {
72        let perf_event_fds = perf_event_open_by_name(probe_name, name, addr)?;
73
74        let mut fds = vec![];
75        for fd in perf_event_fds {
76            perf_event_attach(fd, program.get_fd())?;
77            perf_event_enable(fd)?;
78            fds.push(fd);
79        }
80        self.attach_fds.insert(program.get_fd(), fds);
81
82        Ok(())
83    }
84
85    fn attach_raw_tracepoint(&mut self, program: &Program, name: &str) -> Result<(), Error> {
86        let mut bpf_attr = BpfRawTracepointOpenAttr::default();
87
88        /*
89         * this unsafe zeroing is required to have the padding in the
90         * attr structure zeroed. this padding is checked by the kernel
91         * and has to be zero. std::mem:zeroed and Default don't work.
92         */
93        cbzero(&mut bpf_attr);
94
95        /*
96         * Assumes that String's internal representation of a string is
97         * ascii.
98         */
99        let mut attach_name = String::from("");
100        attach_name.push_str(name);
101        attach_name.push('\0');
102
103        bpf_attr.prog_fd = program.get_fd();
104        bpf_attr.name = attach_name.as_ptr() as u64;
105
106        let fds = vec![bpf_attr.call_bpf(Command::RawTracepointOpen)?];
107        self.attach_fds.insert(program.get_fd(), fds);
108
109        Ok(())
110    }
111
112    /// Attaches the program from the probe.
113    pub fn detach(&mut self, program: &Program) -> Result<(), Error> {
114        if let Some(fds) = self.attach_fds.get(&program.get_fd()) {
115            for fd in fds {
116                close(*fd);
117            }
118        }
119        self.attach_fds.remove(&program.get_fd());
120
121        Ok(())
122    }
123}
124
125impl Drop for Probe {
126    fn drop(&mut self) {
127        for fds in self.attach_fds.values() {
128            for fd in fds {
129                close(*fd);
130            }
131        }
132    }
133}