use crate::error::Error;
use bitflags::bitflags;
use std::fmt;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::ops::Range;
use std::path::PathBuf;
#[cfg(target_os = "freebsd")]
use crate::os_impl::freebsd as platform;
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::os_impl::linux as platform;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use crate::os_impl::macos as platform;
#[cfg(target_os = "windows")]
use crate::os_impl::windows as platform;
bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Protection: u32 {
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXECUTE = 1 << 3;
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ShareMode {
Private,
Shared,
}
#[derive(Clone, Debug)]
pub struct MemoryArea {
pub(crate) allocation_base: usize,
pub(crate) range: Range<usize>,
pub(crate) protection: Protection,
pub(crate) share_mode: ShareMode,
pub(crate) path: Option<(PathBuf, u64)>,
}
impl MemoryArea {
#[inline]
pub fn allocation_base(&self) -> usize {
self.allocation_base
}
#[inline]
pub fn range(&self) -> &Range<usize> {
&self.range
}
#[inline]
pub fn start(&self) -> usize {
self.range.start
}
#[inline]
pub fn end(&self) -> usize {
self.range.end
}
#[inline]
pub fn protection(&self) -> Protection {
self.protection
}
#[inline]
pub fn share_mode(&self) -> ShareMode {
self.share_mode
}
#[inline]
pub fn path(&self) -> Option<&PathBuf> {
self.path.as_ref().map(|(path, _)| path)
}
#[inline]
pub fn file_offset(&self) -> Option<u64> {
self.path.as_ref().map(|(_, offset)| *offset)
}
}
pub struct MemoryAreas<B> {
inner: platform::MemoryAreas<B>,
}
impl<B> fmt::Debug for MemoryAreas<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MemoryAreas").finish_non_exhaustive()
}
}
impl MemoryAreas<BufReader<File>> {
pub fn open(pid: Option<u32>) -> Result<Self, Error> {
let inner = platform::MemoryAreas::open(pid, None)?;
Ok(Self { inner })
}
pub fn query(address: usize) -> Result<Option<MemoryArea>, Error> {
Self::query_process(None, address)
}
pub fn query_range(range: Range<usize>) -> Result<Self, Error> {
Self::query_process_range(None, range)
}
pub fn query_process(pid: Option<u32>, address: usize) -> Result<Option<MemoryArea>, Error> {
let mut areas = platform::MemoryAreas::open(pid, Some(address..address + 1))?;
areas.next().transpose()
}
pub fn query_process_range(pid: Option<u32>, range: Range<usize>) -> Result<Self, Error> {
let inner = platform::MemoryAreas::open(pid, Some(range))?;
Ok(Self { inner })
}
}
impl<B: BufRead> Iterator for MemoryAreas<B> {
type Item = Result<MemoryArea, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}