use crate::to_ok_result;
use bitflags::bitflags;
use lief_ffi as ffi;
use num_traits::{Num, cast};
use crate::{
Error,
common::{FromFFI, into_optional},
};
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MmapFlags: u32 {
const NONE = 0;
const PRIVATE = 1 << 0;
const ANONYMOUS = 1 << 1;
const SHARED = 1 << 2;
const FIXED = 1 << 3;
const JIT = 1 << 4;
}
}
impl std::fmt::Display for MmapFlags {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
impl From<u32> for MmapFlags {
fn from(value: u32) -> Self {
MmapFlags::from_bits_truncate(value)
}
}
impl From<MmapFlags> for u32 {
fn from(value: MmapFlags) -> Self {
value.bits()
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Perm: u32 {
const NONE = 0;
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXEC = 1 << 2;
}
}
impl std::fmt::Display for Perm {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
impl From<u32> for Perm {
fn from(value: u32) -> Self {
Perm::from_bits_truncate(value)
}
}
impl From<Perm> for u32 {
fn from(value: Perm) -> Self {
value.bits()
}
}
pub struct Chunk {
ptr: cxx::UniquePtr<ffi::runtime_Memory_Chunk>,
}
impl FromFFI<ffi::runtime_Memory_Chunk> for Chunk {
fn from_ffi(ptr: cxx::UniquePtr<ffi::runtime_Memory_Chunk>) -> Self {
Self { ptr }
}
}
impl Chunk {
pub fn addr(&self) -> u64 {
self.ptr.addr()
}
pub fn size(&self) -> u64 {
self.ptr.size()
}
pub fn permissions(&self) -> Perm {
Perm::from(self.ptr.permissions())
}
pub fn page_start(&self) -> u64 {
self.ptr.page_start()
}
pub fn page_end(&self) -> u64 {
self.ptr.page_end()
}
pub fn change_permissions(&mut self, perm: Perm) {
self.ptr.pin_mut().change_permissions(perm.into());
}
pub fn make_x(&mut self) {
self.ptr.pin_mut().make_x();
}
pub fn make_rw(&mut self) {
self.ptr.pin_mut().make_rw();
}
pub fn make_rx(&mut self) {
self.ptr.pin_mut().make_rx();
}
pub fn make_rwx(&mut self) {
self.ptr.pin_mut().make_rwx();
}
pub fn make_ro(&mut self) {
self.ptr.pin_mut().make_ro();
}
pub fn cache_flush(&mut self) {
self.ptr.pin_mut().cache_flush();
}
pub fn is_valid(&self) -> bool {
self.ptr.is_valid()
}
}
impl std::fmt::Display for Chunk {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.ptr.to_string())
}
}
pub struct Memory {}
impl Memory {
pub fn mmap(size: u64, flags: MmapFlags, permission: Perm) -> Option<Chunk> {
into_optional(ffi::runtime_Memory::mmap(
size,
flags.into(),
permission.into(),
))
}
pub fn munmap(chunk: &mut Chunk) -> Result<(), Error> {
to_ok_result!(ffi::runtime_Memory::munmap, chunk.ptr.pin_mut());
}
pub fn mprotect(chunk: &mut Chunk, perm: Perm) -> Result<(), Error> {
to_ok_result!(
ffi::runtime_Memory::mprotect,
chunk.ptr.pin_mut(),
perm.into()
);
}
pub unsafe fn read<T>(addr: u64) -> T
where
T: Num + cast::FromPrimitive + cast::ToPrimitive + Clone,
{
let ptr = addr as *const T;
unsafe { (*ptr).clone() }
}
pub unsafe fn write<T>(addr: u64, value: T)
where
T: Num + cast::FromPrimitive + cast::ToPrimitive,
{
let ptr = addr as *mut T;
unsafe {
*ptr = value;
}
}
}