1use crate::error::Error;
2use bitflags::bitflags;
3use std::fmt;
4use std::fs::File;
5use std::io::{BufRead, BufReader};
6use std::ops::Range;
7use std::path::PathBuf;
8
9#[cfg(target_os = "freebsd")]
10use crate::os_impl::freebsd as platform;
11
12#[cfg(any(target_os = "android", target_os = "linux"))]
13use crate::os_impl::linux as platform;
14
15#[cfg(any(target_os = "macos", target_os = "ios"))]
16use crate::os_impl::macos as platform;
17
18#[cfg(target_os = "windows")]
19use crate::os_impl::windows as platform;
20
21bitflags! {
22 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
24 pub struct Protection: u32 {
25 const READ = 1 << 0;
27 const WRITE = 1 << 1;
29 const EXECUTE = 1 << 3;
31 }
32}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum ShareMode {
37 Private,
39 Shared,
41}
42
43#[derive(Clone, Debug)]
45pub struct MemoryArea {
46 pub(crate) allocation_base: usize,
48 pub(crate) range: Range<usize>,
50 pub(crate) protection: Protection,
52 pub(crate) share_mode: ShareMode,
54 pub(crate) path: Option<(PathBuf, u64)>,
56}
57
58impl MemoryArea {
59 #[inline]
61 pub fn allocation_base(&self) -> usize {
62 self.allocation_base
63 }
64
65 #[inline]
67 pub fn range(&self) -> &Range<usize> {
68 &self.range
69 }
70
71 #[inline]
73 pub fn start(&self) -> usize {
74 self.range.start
75 }
76
77 #[inline]
79 pub fn end(&self) -> usize {
80 self.range.end
81 }
82
83 #[inline]
85 pub fn protection(&self) -> Protection {
86 self.protection
87 }
88
89 #[inline]
91 pub fn share_mode(&self) -> ShareMode {
92 self.share_mode
93 }
94
95 #[inline]
97 pub fn path(&self) -> Option<&PathBuf> {
98 self.path.as_ref().map(|(path, _)| path)
99 }
100
101 #[inline]
103 pub fn file_offset(&self) -> Option<u64> {
104 self.path.as_ref().map(|(_, offset)| *offset)
105 }
106}
107
108pub struct MemoryAreas<B> {
110 inner: platform::MemoryAreas<B>,
111}
112
113impl<B> fmt::Debug for MemoryAreas<B> {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.debug_struct("MemoryAreas").finish_non_exhaustive()
116 }
117}
118
119impl MemoryAreas<BufReader<File>> {
120 pub fn open(pid: Option<u32>) -> Result<Self, Error> {
123 let inner = platform::MemoryAreas::open(pid, None)?;
124
125 Ok(Self { inner })
126 }
127
128 pub fn query(address: usize) -> Result<Option<MemoryArea>, Error> {
132 Self::query_process(None, address)
133 }
134
135 pub fn query_range(range: Range<usize>) -> Result<Self, Error> {
138 Self::query_process_range(None, range)
139 }
140
141 pub fn query_process(pid: Option<u32>, address: usize) -> Result<Option<MemoryArea>, Error> {
146 let mut areas = platform::MemoryAreas::open(pid, Some(address..address + 1))?;
147
148 areas.next().transpose()
149 }
150
151 pub fn query_process_range(pid: Option<u32>, range: Range<usize>) -> Result<Self, Error> {
155 let inner = platform::MemoryAreas::open(pid, Some(range))?;
156
157 Ok(Self { inner })
158 }
159}
160
161impl<B: BufRead> Iterator for MemoryAreas<B> {
162 type Item = Result<MemoryArea, Error>;
163
164 fn next(&mut self) -> Option<Self::Item> {
165 self.inner.next()
166 }
167}