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 pub struct Protection: u32 {
24 const READ = 1 << 0;
26 const WRITE = 1 << 1;
28 const EXECUTE = 1 << 3;
30 }
31}
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum ShareMode {
36 Private,
38 Shared,
40}
41
42#[derive(Clone, Debug)]
44pub struct MemoryArea {
45 pub(crate) allocation_base: usize,
47 pub(crate) range: Range<usize>,
49 pub(crate) protection: Protection,
51 pub(crate) share_mode: ShareMode,
53 pub(crate) path: Option<(PathBuf, u64)>,
55}
56
57impl MemoryArea {
58 #[inline]
60 pub fn allocation_base(&self) -> usize {
61 self.allocation_base
62 }
63
64 #[inline]
66 pub fn range(&self) -> &Range<usize> {
67 &self.range
68 }
69
70 #[inline]
72 pub fn start(&self) -> usize {
73 self.range.start
74 }
75
76 #[inline]
78 pub fn end(&self) -> usize {
79 self.range.end
80 }
81
82 #[inline]
84 pub fn protection(&self) -> Protection {
85 self.protection
86 }
87
88 #[inline]
90 pub fn share_mode(&self) -> ShareMode {
91 self.share_mode
92 }
93
94 #[inline]
96 pub fn path(&self) -> Option<&PathBuf> {
97 self.path.as_ref().map(|(path, _)| path)
98 }
99
100 #[inline]
102 pub fn file_offset(&self) -> Option<u64> {
103 self.path.as_ref().map(|(_, offset)| *offset)
104 }
105}
106
107pub struct MemoryAreas<B> {
109 inner: platform::MemoryAreas<B>,
110}
111
112impl<B> fmt::Debug for MemoryAreas<B> {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 f.debug_struct("MemoryAreas").finish_non_exhaustive()
115 }
116}
117
118impl MemoryAreas<BufReader<File>> {
119 pub fn open(pid: Option<u32>) -> Result<Self, Error> {
122 let inner = platform::MemoryAreas::open(pid, None)?;
123
124 Ok(Self { inner })
125 }
126
127 pub fn query(address: usize) -> Result<Option<MemoryArea>, Error> {
131 Self::query_process(None, address)
132 }
133
134 pub fn query_range(range: Range<usize>) -> Result<Self, Error> {
137 Self::query_process_range(None, range)
138 }
139
140 pub fn query_process(pid: Option<u32>, address: usize) -> Result<Option<MemoryArea>, Error> {
145 let mut areas = platform::MemoryAreas::open(pid, Some(address..address + 1))?;
146
147 areas.next().transpose()
148 }
149
150 pub fn query_process_range(pid: Option<u32>, range: Range<usize>) -> Result<Self, Error> {
154 let inner = platform::MemoryAreas::open(pid, Some(range))?;
155
156 Ok(Self { inner })
157 }
158}
159
160impl<B: BufRead> Iterator for MemoryAreas<B> {
161 type Item = Result<MemoryArea, Error>;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 self.inner.next()
165 }
166}