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::()]; buf.copy_from_slice(bytes); unsafe { std::mem::transmute(buf) } } } #[test] fn record_executable_mmap() { // Use the pagesize as the mmap size so that the recorded length in the // record and the length we allocate are the same. 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"); // This should cause the sampler to record a MMAP event 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::()]); 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 _); }