mmap_rs/
areas.rs

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    /// The protection of the memory area.
23    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
24    pub struct Protection: u32 {
25        /// The memory area is mapped with read permissions.
26        const READ          = 1 << 0;
27        /// The memory area is mapped with write permissions.
28        const WRITE         = 1 << 1;
29        /// The memory area is mapped with execute permissions.
30        const EXECUTE       = 1 << 3;
31    }
32}
33
34/// The share mode of the memory area.
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum ShareMode {
37    /// The memory area is mapped as private.
38    Private,
39    /// The memory area is mapped as shared.
40    Shared,
41}
42
43/// Describes a memory area of a process.
44#[derive(Clone, Debug)]
45pub struct MemoryArea {
46    /// The allocation base of the memory area.
47    pub(crate) allocation_base: usize,
48    /// The address range of the memory area.
49    pub(crate) range: Range<usize>,
50    /// The protection with which the memory area has been mapped.
51    pub(crate) protection: Protection,
52    /// The share mode of the memory area.
53    pub(crate) share_mode: ShareMode,
54    /// The path to the file that backs this memory area, if backed by a file.
55    pub(crate) path: Option<(PathBuf, u64)>,
56}
57
58impl MemoryArea {
59    /// The allocation base of the memory area.
60    #[inline]
61    pub fn allocation_base(&self) -> usize {
62        self.allocation_base
63    }
64
65    /// The address range of the memory area.
66    #[inline]
67    pub fn range(&self) -> &Range<usize> {
68        &self.range
69    }
70
71    /// The start address of the area.
72    #[inline]
73    pub fn start(&self) -> usize {
74        self.range.start
75    }
76
77    /// The end address of the area.
78    #[inline]
79    pub fn end(&self) -> usize {
80        self.range.end
81    }
82
83    /// The protection with which the memory area has been mapped.
84    #[inline]
85    pub fn protection(&self) -> Protection {
86        self.protection
87    }
88
89    /// The share mode of the memory area.
90    #[inline]
91    pub fn share_mode(&self) -> ShareMode {
92        self.share_mode
93    }
94
95    /// The path to the file that backs this memory area, if backed by a file.
96    #[inline]
97    pub fn path(&self) -> Option<&PathBuf> {
98        self.path.as_ref().map(|(path, _)| path)
99    }
100
101    /// The file offset, if backed by a file.
102    #[inline]
103    pub fn file_offset(&self) -> Option<u64> {
104        self.path.as_ref().map(|(_, offset)| *offset)
105    }
106}
107
108/// The memory areas of the process.
109pub 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    /// Creates an iterator over the memory maps for the specified process. If no process ID is
121    /// given, then it enumerates the memory areas of the current process.
122    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    /// Retrieve information about the memory area corresponding to the virtual address in the
129    /// virtual address space of the current process. Returns `Ok(None)` if no memory has been
130    /// mapped at the given virtual address.
131    pub fn query(address: usize) -> Result<Option<MemoryArea>, Error> {
132        Self::query_process(None, address)
133    }
134
135    /// Retrieves information about the memory area(s) corresponding to the virtual address range
136    /// in the virtual address space of the current process.
137    pub fn query_range(range: Range<usize>) -> Result<Self, Error> {
138        Self::query_process_range(None, range)
139    }
140
141    /// Retrieve information about the memory area corresponding to the virtual address in the
142    /// virtual address space of the specified process. This queries the current process if no
143    /// process ID is given. Returns `Ok(None)` if no memory has been mapped at the given
144    /// virtual address.
145    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    /// Retrieves information about the memory area(s) corresponding to the virtual address range
152    /// in the virtual address space of the specified process. This queries the current process if
153    /// no process ID is given.
154    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}