backtrace/symbolize/gimli/
parse_running_mmaps_unix.rs
1use super::mystd::fs::File;
6use super::mystd::io::Read;
7use super::mystd::str::FromStr;
8use super::{OsString, String, Vec};
9
10#[derive(PartialEq, Eq, Debug)]
11pub(super) struct MapsEntry {
12 address: (usize, usize),
14 perms: [char; 4],
22 offset: usize,
24 dev: (usize, usize),
26 inode: usize,
28 pathname: OsString,
54}
55
56pub(super) fn parse_maps() -> Result<Vec<MapsEntry>, &'static str> {
57 let mut v = Vec::new();
58 let mut proc_self_maps =
59 File::open("/proc/self/maps").map_err(|_| "Couldn't open /proc/self/maps")?;
60 let mut buf = String::new();
61 let _bytes_read = proc_self_maps
62 .read_to_string(&mut buf)
63 .map_err(|_| "Couldn't read /proc/self/maps")?;
64 for line in buf.lines() {
65 v.push(line.parse()?);
66 }
67
68 Ok(v)
69}
70
71impl MapsEntry {
72 pub(super) fn pathname(&self) -> &OsString {
73 &self.pathname
74 }
75
76 pub(super) fn ip_matches(&self, ip: usize) -> bool {
77 self.address.0 <= ip && ip < self.address.1
78 }
79}
80
81impl FromStr for MapsEntry {
82 type Err = &'static str;
83
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 let (range_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
93 if range_str.is_empty() {
94 return Err("Couldn't find address");
95 }
96
97 let (perms_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
98 if perms_str.is_empty() {
99 return Err("Couldn't find permissions");
100 }
101
102 let (offset_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
103 if offset_str.is_empty() {
104 return Err("Couldn't find offset");
105 }
106
107 let (dev_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
108 if dev_str.is_empty() {
109 return Err("Couldn't find dev");
110 }
111
112 let (inode_str, s) = s.trim_start().split_once(' ').unwrap_or((s, ""));
113 if inode_str.is_empty() {
114 return Err("Couldn't find inode");
115 }
116
117 let pathname_str = s.trim_start();
119
120 let hex = |s| usize::from_str_radix(s, 16).map_err(|_| "Couldn't parse hex number");
121 let address = if let Some((start, limit)) = range_str.split_once('-') {
122 (hex(start)?, hex(limit)?)
123 } else {
124 return Err("Couldn't parse address range");
125 };
126 let perms: [char; 4] = {
127 let mut chars = perms_str.chars();
128 let mut c = || chars.next().ok_or("insufficient perms");
129 let perms = [c()?, c()?, c()?, c()?];
130 if chars.next().is_some() {
131 return Err("too many perms");
132 }
133 perms
134 };
135 let offset = hex(offset_str)?;
136 let dev = if let Some((major, minor)) = dev_str.split_once(':') {
137 (hex(major)?, hex(minor)?)
138 } else {
139 return Err("Couldn't parse dev");
140 };
141 let inode = hex(inode_str)?;
142 let pathname = pathname_str.into();
143
144 Ok(MapsEntry {
145 address,
146 perms,
147 offset,
148 dev,
149 inode,
150 pathname,
151 })
152 }
153}
154
155#[cfg(target_pointer_width = "64")]
157#[test]
158fn check_maps_entry_parsing_64bit() {
159 assert_eq!(
160 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 \
161 [vsyscall]"
162 .parse::<MapsEntry>()
163 .unwrap(),
164 MapsEntry {
165 address: (0xffffffffff600000, 0xffffffffff601000),
166 perms: ['-', '-', 'x', 'p'],
167 offset: 0x00000000,
168 dev: (0x00, 0x00),
169 inode: 0x0,
170 pathname: "[vsyscall]".into(),
171 }
172 );
173
174 assert_eq!(
175 "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 \
176 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
177 .parse::<MapsEntry>()
178 .unwrap(),
179 MapsEntry {
180 address: (0x7f5985f46000, 0x7f5985f48000),
181 perms: ['r', 'w', '-', 'p'],
182 offset: 0x00039000,
183 dev: (0x103, 0x06),
184 inode: 0x76021795,
185 pathname: "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2".into(),
186 }
187 );
188 assert_eq!(
189 "35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
190 .parse::<MapsEntry>()
191 .unwrap(),
192 MapsEntry {
193 address: (0x35b1a21000, 0x35b1a22000),
194 perms: ['r', 'w', '-', 'p'],
195 offset: 0x00000000,
196 dev: (0x00, 0x00),
197 inode: 0x0,
198 pathname: Default::default(),
199 }
200 );
201}
202
203#[test]
205fn check_maps_entry_parsing_32bit() {
206 assert_eq!(
212 "08056000-08077000 rw-p 00000000 00:00 0 \
213 [heap]"
214 .parse::<MapsEntry>()
215 .unwrap(),
216 MapsEntry {
217 address: (0x08056000, 0x08077000),
218 perms: ['r', 'w', '-', 'p'],
219 offset: 0x00000000,
220 dev: (0x00, 0x00),
221 inode: 0x0,
222 pathname: "[heap]".into(),
223 }
224 );
225
226 assert_eq!(
227 "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
228 /usr/lib/locale/locale-archive"
229 .parse::<MapsEntry>()
230 .unwrap(),
231 MapsEntry {
232 address: (0xb7c79000, 0xb7e02000),
233 perms: ['r', '-', '-', 'p'],
234 offset: 0x00000000,
235 dev: (0x08, 0x01),
236 inode: 0x60662705,
237 pathname: "/usr/lib/locale/locale-archive".into(),
238 }
239 );
240 assert_eq!(
241 "b7e02000-b7e03000 rw-p 00000000 00:00 0"
242 .parse::<MapsEntry>()
243 .unwrap(),
244 MapsEntry {
245 address: (0xb7e02000, 0xb7e03000),
246 perms: ['r', 'w', '-', 'p'],
247 offset: 0x00000000,
248 dev: (0x00, 0x00),
249 inode: 0x0,
250 pathname: Default::default(),
251 }
252 );
253 assert_eq!(
254 "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
255 /executable/path/with some spaces"
256 .parse::<MapsEntry>()
257 .unwrap(),
258 MapsEntry {
259 address: (0xb7c79000, 0xb7e02000),
260 perms: ['r', '-', '-', 'p'],
261 offset: 0x00000000,
262 dev: (0x08, 0x01),
263 inode: 0x60662705,
264 pathname: "/executable/path/with some spaces".into(),
265 }
266 );
267 assert_eq!(
268 "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
269 /executable/path/with multiple-continuous spaces "
270 .parse::<MapsEntry>()
271 .unwrap(),
272 MapsEntry {
273 address: (0xb7c79000, 0xb7e02000),
274 perms: ['r', '-', '-', 'p'],
275 offset: 0x00000000,
276 dev: (0x08, 0x01),
277 inode: 0x60662705,
278 pathname: "/executable/path/with multiple-continuous spaces ".into(),
279 }
280 );
281 assert_eq!(
282 " b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
283 /executable/path/starts-with-spaces"
284 .parse::<MapsEntry>()
285 .unwrap(),
286 MapsEntry {
287 address: (0xb7c79000, 0xb7e02000),
288 perms: ['r', '-', '-', 'p'],
289 offset: 0x00000000,
290 dev: (0x08, 0x01),
291 inode: 0x60662705,
292 pathname: "/executable/path/starts-with-spaces".into(),
293 }
294 );
295}