perf_event/events/breakpoint.rs
1use bitflags::bitflags;
2use perf_event_open_sys::bindings;
3
4use crate::events::Event;
5
6bitflags! {
7 /// Memory access mask for a hardware data breakpoint.
8 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
9 pub struct BreakpointAccess : u32 {
10 /// Count when we read the memory location.
11 const READ = bindings::HW_BREAKPOINT_R;
12
13 /// Count when we write the memory location.
14 const WRITE = bindings::HW_BREAKPOINT_W;
15
16 /// Count when we read or write the memory location.
17 const READ_WRITE = Self::READ.union(Self::WRITE).bits();
18 }
19}
20
21/// A hardware breakpoint.
22///
23/// A hardware breakpoint watches a region of memory for accesses. It has three
24/// parameters:
25/// - the address that is being watched (`addr`)
26/// - the number of bytes that breakpoint covers (`len`)
27/// - which type of memory accesses we care about (`ty`)
28///
29/// Note that both number of bytes that can be watched as well as the number of
30/// breakpoints that is allowed to be active at any given time is limited.
31///
32/// # Execute Breakpoint
33/// We can use a breakpoint to count the number of times that a function gets
34/// called, as long as the compiler does not optimize the function away.
35///
36/// ```
37/// # use perf_event::Builder;
38/// # use perf_event::events::Breakpoint;
39/// #[inline(never)]
40/// fn do_some_things() {
41/// // ...
42/// # println!("test println so the function doesn't get removed")
43/// }
44///
45/// let fnptr = do_some_things as fn() as usize;
46/// let mut counter = Builder::new(Breakpoint::execute(fnptr as u64)).build()?;
47/// counter.enable()?;
48///
49/// for _ in 0..500 {
50/// do_some_things();
51/// }
52///
53/// counter.disable()?;
54/// assert_eq!(counter.read()?, 500);
55/// # std::io::Result::Ok(())
56/// ```
57///
58/// # Data Breakpoint
59/// We can also use a breakpoint to count the number of times that a memory
60/// location is accessed.
61/// ```
62/// # use perf_event::Builder;
63/// # use perf_event::events::Breakpoint;
64/// #
65/// let mut data: Vec<u64> = (0..1024).rev().collect();
66///
67/// let breakpoint = Breakpoint::read_write(&data[20] as *const _ as usize as u64, 8);
68/// let mut counter = Builder::new(breakpoint).build()?;
69/// counter.enable()?;
70/// data.sort();
71/// counter.disable()?;
72///
73/// println!("Position 20 accessed {} times", counter.read()?);
74/// # std::io::Result::Ok(())
75/// ```
76///
77/// # Usage Notes
78/// - Some systems do not support creating read-only or write-only breakpoints.
79/// If you are getting `EINVAL` errors while trying to build such a counter
80/// using a read-write breakpoint might work instead.
81///
82/// - The valid values of len are quite limited. The [`perf_event_open`][man]
83/// manpage indicates that the only valid values for `bp_len` are 1, 2, 4, and
84/// 8.
85///
86/// [man]: https://www.mankier.com/2/perf_event_open
87#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
88pub enum Breakpoint {
89 /// Data breakpoint. Triggers when code reads or writes to the memory area
90 /// as configured by the parameters below.
91 Data {
92 /// Bitfield containing the types of accesses we want the breakpoint to
93 /// trigger on.
94 access: BreakpointAccess,
95
96 /// The address of the memory location on which the breakpoint should
97 /// trigger.
98 addr: u64,
99
100 /// The length of the breakpoint being measured.
101 ///
102 /// There are a limited number of valid values for this field.
103 /// Basically, the options are 1, 2, 4, and 8. Setting this
104 /// field to anything else will cause counter creation to fail
105 /// with an error.
106 len: u64,
107 },
108
109 /// Code breakpoint. Triggers when the code at the address is executed.
110 Code {
111 /// The address that the breakpoint is monitoring.
112 addr: u64,
113 },
114}
115
116impl Breakpoint {
117 /// Create a code execution breakpoint, that counts the number of
118 /// times the instruction at the provided address was executed.
119 pub const fn execute(addr: u64) -> Self {
120 Self::Code { addr }
121 }
122
123 /// Create a memory read breakpoint, that counts the number of
124 /// times we read from the provided memory location.
125 ///
126 /// See the struct field docs for valid values of `len`.
127 pub const fn read(addr: u64, len: u64) -> Self {
128 Self::Data {
129 access: BreakpointAccess::READ,
130 addr,
131 len,
132 }
133 }
134
135 /// Create a memory write breakpoint, that counts the number of
136 /// times we write to the provided memory location.
137 ///
138 /// See the struct field docs for valid values of `len`.
139 pub const fn write(addr: u64, len: u64) -> Self {
140 Self::Data {
141 access: BreakpointAccess::WRITE,
142 addr,
143 len,
144 }
145 }
146
147 /// Create a memory access breakpoint, that counts the number of
148 /// times we either read from or write to the provided memory
149 /// location.
150 ///
151 /// See the struct field docs for valid values of `len`.
152 pub const fn read_write(addr: u64, len: u64) -> Self {
153 Self::Data {
154 access: BreakpointAccess::READ_WRITE,
155 addr,
156 len,
157 }
158 }
159}
160
161impl Event for Breakpoint {
162 fn update_attrs(self, attr: &mut bindings::perf_event_attr) {
163 attr.type_ = bindings::PERF_TYPE_BREAKPOINT;
164 attr.config = 0;
165
166 match self {
167 Self::Data { access, addr, len } => {
168 attr.bp_type = access.bits();
169 attr.bp_addr = addr;
170 attr.bp_len = len;
171 }
172 Self::Code { addr } => {
173 attr.bp_type = bindings::HW_BREAKPOINT_X;
174 attr.bp_addr = addr;
175 // According to the perf_event_open man page, execute breakpoints
176 // should set len to sizeof(long).
177 attr.bp_len = std::mem::size_of::<libc::c_long>() as _;
178 }
179 }
180 }
181}