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