use nix::unistd::SysconfVar;
use perf_event::events::Software;
use perf_event::Builder;
use perf_event_open_sys::bindings;
use super::Hex;
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct MmapRecord {
pub pid: u32,
pub tid: u32,
pub addr: u64,
pub len: u64,
pub pgoff: u64,
}
impl MmapRecord {
pub fn from_bytes(bytes: &[u8]) -> Self {
let mut buf = [0; std::mem::size_of::<Self>()];
buf.copy_from_slice(bytes);
unsafe { std::mem::transmute(buf) }
}
}
#[test]
fn record_executable_mmap() {
let pagesize = nix::unistd::sysconf(SysconfVar::PAGE_SIZE)
.expect("Unable to get page size")
.expect("No page size returned") as usize;
let mut sampler = Builder::new(Software::DUMMY)
.mmap(true)
.build()
.expect("Failed to build counter")
.sampled(4096)
.expect("Failed to build sampler");
sampler.enable().expect("Failed to enable sampler");
let mmap = memmap2::MmapOptions::new()
.len(pagesize)
.map_anon()
.expect("Failed to create anonymous memory map");
let mmap = mmap
.make_exec()
.expect("Failed to transition memory mapping to be executable");
sampler.disable().expect("Failed to disable sampler");
let record = sampler
.next_record()
.expect("Sampler did not record any events");
assert_eq!(record.ty(), bindings::PERF_RECORD_MMAP);
let bytes = record.to_contiguous();
let record = MmapRecord::from_bytes(&bytes[..std::mem::size_of::<MmapRecord>()]);
eprintln!("record: {:#?}", record);
assert_eq!(Hex(record.addr), Hex(mmap.as_ptr() as usize as _));
assert_eq!(record.len, mmap.len() as _);
assert_eq!(record.pid, nix::unistd::getpid().as_raw() as _);
assert_eq!(record.tid, nix::unistd::gettid().as_raw() as _);
}