perf_event_data/records/
text_poke.rs

1use std::borrow::Cow;
2use std::fmt;
3
4use crate::prelude::*;
5
6/// TEXT_POKE records indicate a change in the kernel text.
7///
8/// This struct corresponds to `PERF_RECORD_TEXT_POKE`. See the [manpage] for
9/// more documentation.
10///
11/// [manpage]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
12#[derive(Clone)]
13pub struct TextPoke<'a> {
14    /// The address of the change.
15    pub addr: u64,
16
17    /// The old bytes at `addr`.
18    pub old_bytes: Cow<'a, [u8]>,
19
20    /// The new bytes at `addr`.
21    pub new_bytes: Cow<'a, [u8]>,
22}
23
24impl<'a> TextPoke<'a> {
25    /// Convert all the borrowed data in this `TextPoke` into owned data.
26    pub fn to_owned(self) -> TextPoke<'static> {
27        TextPoke {
28            old_bytes: self.old_bytes.into_owned().into(),
29            new_bytes: self.new_bytes.into_owned().into(),
30            ..self
31        }
32    }
33}
34
35impl<'p> Parse<'p> for TextPoke<'p> {
36    fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
37    where
38        E: Endian,
39        B: ParseBuf<'p>,
40    {
41        use crate::util::cow::CowSliceExt;
42
43        let addr = p.parse()?;
44        let old_len = p.parse_u16()? as usize;
45        let new_len = p.parse_u16()? as usize;
46
47        // The records emitted by perf_event_open always have a length that is a
48        // multiple of 8. Strictly speaking, we don't have to do this since this is the
49        // end of the record and higher levels should avoid this being a problem, but
50        // it's best to do things right here anyways.
51        let full_len = round_up_mod(old_len + new_len, 4, 8);
52        let bytes = p.parse_bytes(full_len)?;
53
54        let (old_bytes, mut new_bytes) = bytes.split_at(old_len);
55        new_bytes.truncate(new_len);
56
57        Ok(Self {
58            addr,
59            old_bytes,
60            new_bytes,
61        })
62    }
63}
64
65impl fmt::Debug for TextPoke<'_> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_struct("TextPoke")
68            .field("addr", &crate::util::fmt::HexAddr(self.addr))
69            .field("old_bytes", &self.old_bytes)
70            .field("new_bytes", &self.new_bytes)
71            .finish()
72    }
73}
74
75/// Round v up so that it is equal to k (mod m)
76fn round_up_mod(v: usize, k: usize, m: usize) -> usize {
77    assert!(k < m);
78
79    v + match v % m {
80        vm if vm <= k => k - vm,
81        vm if vm > k => (k + m) - vm,
82        _ => unreachable!(),
83    }
84}