use std::ffi::{CStr, CString};
use arrayvec::ArrayVec;
use super::{RecordId, SampleType, Task};
use crate::ffi::{bindings as b, deref_offset};
const BUILD_ID_SIZE_MAX: usize = 20;
#[derive(Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Mmap {
pub record_id: Option<RecordId>,
pub executable: bool,
pub task: Task,
pub addr: u64,
pub len: u64,
pub file: CString,
pub page_offset: u64,
pub ext: Option<Ext>,
}
impl Mmap {
pub(crate) unsafe fn from_ptr(
mut ptr: *const u8,
misc: u16,
v2: bool,
sample_id_all: Option<SampleType>,
) -> Self {
let task = Task {
pid: deref_offset(&mut ptr),
tid: deref_offset(&mut ptr),
};
let addr = deref_offset(&mut ptr);
let len = deref_offset(&mut ptr);
let page_offset = deref_offset(&mut ptr);
let ext = v2.then(|| {
#[cfg(feature = "linux-5.12")]
let info = if misc as u32 & b::PERF_RECORD_MISC_MMAP_BUILD_ID > 0 {
let len = deref_offset::<u8>(&mut ptr) as usize;
ptr = ptr.add(3); let build_id = {
let slice = std::slice::from_raw_parts(ptr, len);
let result = ArrayVec::try_from(slice);
unsafe { result.unwrap_unchecked() }
};
ptr = ptr.add(BUILD_ID_SIZE_MAX);
Info::BuildId(build_id)
} else {
Info::Device {
major: deref_offset(&mut ptr),
minor: deref_offset(&mut ptr),
inode: deref_offset(&mut ptr),
inode_gen: deref_offset(&mut ptr),
}
};
#[cfg(not(feature = "linux-5.12"))]
let info = Info::Device {
major: deref_offset(&mut ptr),
minor: deref_offset(&mut ptr),
inode: deref_offset(&mut ptr),
inode_gen: deref_offset(&mut ptr),
};
let prot = deref_offset(&mut ptr);
let flags = deref_offset(&mut ptr);
Ext { prot, flags, info }
});
let file = CStr::from_ptr(ptr as _).to_owned();
let record_id = sample_id_all.map(|SampleType(ty)| {
ptr = ptr.add(file.as_bytes_with_nul().len());
ptr = ptr.add(ptr.align_offset(align_of::<u64>()));
RecordId::from_ptr(ptr, ty)
});
let executable = misc as u32 & b::PERF_RECORD_MISC_MMAP_DATA == 0;
Self {
record_id,
executable,
task,
addr,
len,
file,
page_offset,
ext,
}
}
}
super::from!(Mmap);
super::debug!(Mmap {
{record_id?},
{executable},
{task},
{addr},
{len},
{file},
{page_offset},
{ext?},
});
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Ext {
pub prot: u32,
pub flags: u32,
pub info: Info,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Info {
Device {
major: u32,
minor: u32,
inode: u64,
inode_gen: u64,
},
BuildId(ArrayVec<u8, BUILD_ID_SIZE_MAX>),
}