use crate::error::{Error, Result};
use crate::raw;
use crate::Uffd;
use libc::c_void;
#[cfg(feature = "linux4_14")]
use nix::unistd::Pid;
use std::os::unix::io::{FromRawFd, RawFd};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ReadWrite {
Read,
Write,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum FaultKind {
Missing,
#[cfg(feature = "linux5_7")]
WriteProtected,
}
#[derive(Debug)]
pub enum Event {
Pagefault {
kind: FaultKind,
rw: ReadWrite,
addr: *mut c_void,
#[cfg(feature = "linux4_14")]
thread_id: Pid,
},
Fork {
uffd: Uffd,
},
Remap {
from: *mut c_void,
to: *mut c_void,
len: usize,
},
Remove {
start: *mut c_void,
end: *mut c_void,
},
Unmap {
start: *mut c_void,
end: *mut c_void,
},
}
impl Event {
pub(crate) fn from_uffd_msg(msg: &raw::uffd_msg) -> Result<Event> {
match msg.event {
raw::UFFD_EVENT_PAGEFAULT => {
let pagefault = unsafe { msg.arg.pagefault };
cfg_if::cfg_if!(
if #[cfg(feature = "linux5_7")] {
let kind = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WP != 0 {
FaultKind::WriteProtected
} else {
FaultKind::Missing
};
} else {
let kind = FaultKind::Missing;
}
);
let rw = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WRITE == 0 {
ReadWrite::Read
} else {
ReadWrite::Write
};
#[cfg(feature = "linux4_14")]
let thread_id = Pid::from_raw(unsafe { pagefault.feat.ptid } as i32);
Ok(Event::Pagefault {
kind,
rw,
addr: pagefault.address as *mut c_void,
#[cfg(feature = "linux4_14")]
thread_id,
})
}
raw::UFFD_EVENT_FORK => {
let fork = unsafe { msg.arg.fork };
Ok(Event::Fork {
uffd: unsafe { Uffd::from_raw_fd(fork.ufd as RawFd) },
})
}
raw::UFFD_EVENT_REMAP => {
let remap = unsafe { msg.arg.remap };
Ok(Event::Remap {
from: remap.from as *mut c_void,
to: remap.to as *mut c_void,
len: remap.len as usize,
})
}
raw::UFFD_EVENT_REMOVE => {
let remove = unsafe { msg.arg.remove };
Ok(Event::Remove {
start: remove.start as *mut c_void,
end: remove.end as *mut c_void,
})
}
raw::UFFD_EVENT_UNMAP => {
let remove = unsafe { msg.arg.remove };
Ok(Event::Unmap {
start: remove.start as *mut c_void,
end: remove.end as *mut c_void,
})
}
_ => Err(Error::UnrecognizedEvent(msg.event)),
}
}
}