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
use std::borrow::Cow;
use std::ffi::OsStr;
use std::fmt;
use crate::prelude::*;
use crate::Mmap2;
/// MMAP events record memory mappings.
///
/// This struct corresponds to `PERF_RECORD_MMAP`. See the [manpage] for more
/// documentation here.
///
/// [manpage]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[derive(Clone)]
pub struct Mmap<'a> {
/// The process ID.
pub pid: u32,
/// The thread ID.
pub tid: u32,
/// The address that the mapping was placed at in the process' address
/// space.
pub addr: u64,
/// The length, in bytes, of the allocated memory.
pub len: u64,
/// The page offset of the memory mapping.
pub pgoff: u64,
/// The path to the file that is being mapped, if there is one.
///
/// # Notes
/// - Not all memory mappings have a path on the file system. In cases where
/// there is no such path then this will be a label(ish) string from the
/// kernel (e.g. `[stack]`, `[heap]`, `[vdso]`, etc.)
/// - Just because the mapping has a path doesn't necessarily mean that the
/// file at that path was the file that was mapped. The file may have been
/// deleted in the meantime or the process may be under a chroot.
///
/// If you need to be able to tell whether the file at the path is the same
/// one as was mapped you will need to use [`Mmap2`] instead.
pub filename: Cow<'a, [u8]>,
}
impl<'a> Mmap<'a> {
/// The path to the file that is being mapped, as an [`OsStr`].
///
/// # Notes
/// - Not all memory mappings have a path on the file system. In cases where
/// there is no such path then this will be a label(ish) string from the
/// kernel (e.g. `[stack]`, `[heap]`, `[vdso]`, etc.)
/// - Just because the mapping has a path doesn't necessarily mean that the
/// file at that path was the file that was mapped. The file may have been
/// deleted in the meantime or the process may be under a chroot.
///
/// If you need to be able to tell whether the file at the path is the same
/// one as was mapped you will need to use [`Mmap2`] instead.
#[cfg(unix)]
pub fn filename_os(&self) -> &OsStr {
use std::os::unix::ffi::OsStrExt;
OsStrExt::from_bytes(&self.filename)
}
/// Convert all the borrowed data in this `Mmap` into owned data.
pub fn into_owned(self) -> Mmap<'static> {
Mmap {
filename: self.filename.into_owned().into(),
..self
}
}
}
impl<'p> Parse<'p> for Mmap<'p> {
fn parse<B, E>(p: &mut Parser<B, E>) -> ParseResult<Self>
where
E: Endian,
B: ParseBuf<'p>,
{
Ok(Self {
pid: p.parse()?,
tid: p.parse()?,
addr: p.parse()?,
len: p.parse()?,
pgoff: p.parse()?,
filename: p.parse_rest_trim_nul()?,
})
}
}
impl<'a> From<Mmap2<'a>> for Mmap<'a> {
fn from(value: Mmap2<'a>) -> Self {
value.into_mmap()
}
}
impl fmt::Debug for Mmap<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mmap")
.field("pid", &self.pid)
.field("tid", &self.tid)
.field("addr", &crate::util::fmt::HexAddr(self.addr))
.field("len", &self.len)
.field("pgoff", &self.pgoff)
.field("filename", &crate::util::fmt::ByteStr(&self.filename))
.finish()
}
}
#[cfg(test)]
mod tests {
use crate::endian::Little;
use super::*;
#[test]
fn test_parse() {
let bytes: &[u8] = &[
10, 100, 0, 0, 11, 100, 0, 0, 0, 160, 118, 129, 189, 127, 0, 0, 0, 16, 0, 0, 0, 0, 0,
0, 0, 160, 118, 129, 189, 127, 0, 0, 47, 47, 97, 110, 111, 110, 0, 0,
];
let mut parser: Parser<_, Little> = Parser::new(bytes, ParseConfig::default());
let mmap: Mmap = parser.parse().unwrap();
assert_eq!(mmap.pid, 25610);
assert_eq!(mmap.tid, 25611);
assert_eq!(mmap.addr, 0x7FBD8176A000);
assert_eq!(mmap.len, 4096);
assert_eq!(mmap.pgoff, 0x7FBD8176A000);
assert_eq!(&*mmap.filename, b"//anon");
}
}