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