use crate::util::Address;
use libc::{c_void, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE};
use std::io::{Error, ErrorKind, Result};
pub fn result_is_mapped(result: Result<()>) -> bool {
match result {
Ok(_) => false,
Err(err) => err.raw_os_error().unwrap() == libc::EEXIST,
}
}
pub fn zero(start: Address, len: usize) {
unsafe {
libc::memset(start.to_mut_ptr() as *mut libc::c_void, 0, len);
}
}
pub fn dzmmap(start: Address, size: usize) -> Result<()> {
let prot = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC;
let flags = libc::MAP_ANON | libc::MAP_PRIVATE | libc::MAP_FIXED;
let result: *mut c_void = unsafe { libc::mmap(start.to_mut_ptr(), size, prot, flags, -1, 0) };
let addr = Address::from_mut_ptr(result);
if addr == start {
#[cfg(not(target_os = "linux"))]
{
zero(addr, size);
}
Ok(())
} else {
Err(Error::from_raw_os_error(
unsafe { *libc::__errno_location() } as _,
))
}
}
pub fn dzmmap_noreplace(start: Address, size: usize) -> Result<()> {
let prot = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC;
let flags = libc::MAP_ANON | libc::MAP_PRIVATE | libc::MAP_FIXED_NOREPLACE;
let result: *mut c_void = unsafe { libc::mmap(start.to_mut_ptr(), size, prot, flags, -1, 0) };
let addr = Address::from_mut_ptr(result);
if addr == start {
#[cfg(not(target_os = "linux"))]
{
zero(addr, size);
}
Ok(())
} else {
Err(Error::from_raw_os_error(
unsafe { *libc::__errno_location() } as _,
))
}
}
pub fn munprotect(start: Address, size: usize) -> Result<()> {
let result =
unsafe { libc::mprotect(start.to_mut_ptr(), size, PROT_READ | PROT_WRITE | PROT_EXEC) };
if result == 0 {
Ok(())
} else {
Err(Error::from_raw_os_error(result))
}
}
pub fn mprotect(start: Address, size: usize) -> Result<()> {
let result = unsafe { libc::mprotect(start.to_mut_ptr(), size, PROT_NONE) };
if result == 0 {
Ok(())
} else {
Err(Error::from_raw_os_error(result))
}
}
pub fn mmap_noreserve(start: Address, size: usize) -> Result<()> {
let prot = libc::PROT_READ | libc::PROT_WRITE;
let flags =
libc::MAP_ANON | libc::MAP_PRIVATE | libc::MAP_FIXED_NOREPLACE | libc::MAP_NORESERVE;
let result: *mut libc::c_void =
unsafe { libc::mmap(start.to_mut_ptr(), size, prot, flags, -1, 0) };
if result == libc::MAP_FAILED {
let err = unsafe { *libc::__errno_location() };
Err(Error::from_raw_os_error(err as _))
} else {
Ok(())
}
}
pub fn try_munmap(start: Address, size: usize) -> Result<()> {
let result = unsafe { libc::munmap(start.to_mut_ptr(), size) };
if result == -1 {
let err = unsafe { *libc::__errno_location() };
Err(Error::from_raw_os_error(err as _))
} else {
Ok(())
}
}
pub fn check_is_mmapped(start: Address, size: usize) -> Result<()> {
let prot = libc::PROT_READ | libc::PROT_WRITE;
let flags = libc::MAP_ANON | libc::MAP_PRIVATE | libc::MAP_FIXED_NOREPLACE;
let result: *mut libc::c_void =
unsafe { libc::mmap(start.to_mut_ptr(), size, prot, flags, -1, 0) };
if result != libc::MAP_FAILED {
return Err(Error::new(ErrorKind::InvalidInput, "NotMMapped"));
}
let err = unsafe { *libc::__errno_location() };
if err == libc::EEXIST {
Ok(())
} else {
Err(Error::from_raw_os_error(err as _))
}
}