-
Notifications
You must be signed in to change notification settings - Fork 247
/
trace_point.rs
139 lines (127 loc) · 4.14 KB
/
trace_point.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Tracepoint programs.
use std::{fs, io};
use thiserror::Error;
use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT,
programs::{
define_link_wrapper, load_program,
perf_attach::{perf_attach, PerfLink, PerfLinkId},
OwnedLink, ProgramData, ProgramError,
},
sys::perf_event_open_trace_point,
};
/// The type returned when attaching a [`TracePoint`] fails.
#[derive(Debug, Error)]
pub enum TracePointError {
/// Error detaching from debugfs
#[error("`{filename}`")]
FileError {
/// The file name
filename: String,
/// The [`io::Error`] returned from the file operation
#[source]
io_error: io::Error,
},
}
/// A program that can be attached at a pre-defined kernel trace point.
///
/// The kernel provides a set of pre-defined trace points that eBPF programs can
/// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
/// events can be traced.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.7.
///
/// # Examples
///
/// ```no_run
/// # #[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use std::convert::TryInto;
/// use aya::programs::TracePoint;
///
/// let prog: &mut TracePoint = bpf.program_mut("trace_context_switch").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach("sched", "sched_switch")?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_TRACEPOINT")]
pub struct TracePoint {
pub(crate) data: ProgramData<TracePointLink>,
}
impl TracePoint {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_TRACEPOINT, &mut self.data)
}
/// Attaches to a given trace point.
///
/// For a list of the available event categories and names, see
/// `/sys/kernel/debug/tracing/events`.
///
/// The returned value can be used to detach, see [TracePoint::detach].
pub fn attach(&mut self, category: &str, name: &str) -> Result<TracePointLinkId, ProgramError> {
let id = read_sys_fs_trace_point_id(category, name)?;
let fd = perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| {
ProgramError::SyscallError {
call: "perf_event_open".to_owned(),
io_error,
}
})? as i32;
perf_attach(&mut self.data, fd)
}
/// Detaches from a trace point.
///
/// See [TracePoint::attach].
pub fn detach(&mut self, link_id: TracePointLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}
/// Takes ownership of the link referenced by the provided link_id.
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn forget_link(
&mut self,
link_id: TracePointLinkId,
) -> Result<OwnedLink<TracePointLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
}
define_link_wrapper!(
/// The link used by [TracePoint] programs.
TracePointLink,
/// The type returned by [TracePoint::attach]. Can be passed to [TracePoint::detach].
TracePointLinkId,
PerfLink,
PerfLinkId
);
pub(crate) fn read_sys_fs_trace_point_id(
category: &str,
name: &str,
) -> Result<u32, TracePointError> {
let file = format!("/sys/kernel/debug/tracing/events/{}/{}/id", category, name);
let id = fs::read_to_string(&file).map_err(|io_error| TracePointError::FileError {
filename: file.clone(),
io_error,
})?;
let id = id
.trim()
.parse::<u32>()
.map_err(|error| TracePointError::FileError {
filename: file.clone(),
io_error: io::Error::new(io::ErrorKind::Other, error),
})?;
Ok(id)
}