1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use libc;
use std;
use std::fs::File;
use std::io::Read;
pub type Pid = libc::pid_t;
#[derive(Debug, Clone, PartialEq)]
pub struct MapRange {
range_start: usize,
range_end: usize,
pub offset: usize,
pub dev: String,
pub flags: String,
pub inode: usize,
pathname: Option<String>,
}
impl MapRange {
pub fn size(&self) -> usize { self.range_end - self.range_start }
pub fn start(&self) -> usize { self.range_start }
pub fn filename(&self) -> &Option<String> { &self.pathname }
pub fn is_exec(&self) -> bool { &self.flags[2..3] == "x" }
pub fn is_write(&self) -> bool { &self.flags[1..2] == "w" }
pub fn is_read(&self) -> bool { &self.flags[0..1] == "r" }
}
pub fn get_process_maps(pid: Pid) -> std::io::Result<Vec<MapRange>> {
let maps_file = format!("/proc/{}/maps", pid);
let mut file = File::open(maps_file)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(parse_proc_maps(&contents))
}
fn parse_proc_maps(contents: &str) -> Vec<MapRange> {
let mut vec: Vec<MapRange> = Vec::new();
for line in contents.split("\n") {
let mut split = line.split_whitespace();
let range = split.next();
if range == None {
break;
}
let mut range_split = range.unwrap().split("-");
let range_start = range_split.next().unwrap();
let range_end = range_split.next().unwrap();
let flags = split.next().unwrap();
let offset = split.next().unwrap();
let dev = split.next().unwrap();
let inode = split.next().unwrap();
vec.push(MapRange {
range_start: usize::from_str_radix(range_start, 16).unwrap(),
range_end: usize::from_str_radix(range_end, 16).unwrap(),
offset: usize::from_str_radix(offset, 16).unwrap(),
dev: dev.to_string(),
flags: flags.to_string(),
inode: usize::from_str_radix(inode, 10).unwrap(),
pathname: Some(split.collect::<Vec<&str>>().join(" ")).filter(|x| !x.is_empty()),
});
}
vec
}
#[test]
fn test_parse_maps() {
let contents = include_str!("../ci/testdata/map.txt");
let vec = parse_proc_maps(contents);
let expected = vec![
MapRange {
range_start: 0x00400000,
range_end: 0x00507000,
offset: 0,
dev: "00:14".to_string(),
flags: "r-xp".to_string(),
inode: 205736,
pathname: Some("/usr/bin/fish".to_string()),
},
MapRange {
range_start: 0x00708000,
range_end: 0x0070a000,
offset: 0,
dev: "00:00".to_string(),
flags: "rw-p".to_string(),
inode: 0,
pathname: None,
},
MapRange {
range_start: 0x0178c000,
range_end: 0x01849000,
offset: 0,
dev: "00:00".to_string(),
flags: "rw-p".to_string(),
inode: 0,
pathname: Some("[heap]".to_string()),
},
MapRange {
range_start: 0x7f438053b000,
range_end: 0x7f438053f000,
offset: 0,
dev: "fd:01".to_string(),
flags: "r--p".to_string(),
inode: 59034409,
pathname: Some("/usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.4200.6 (deleted)".to_string()),
}
];
assert_eq!(vec, expected);
assert_eq!(super::maps_contain_addr(0x00400000, &vec), true);
assert_eq!(super::maps_contain_addr(0x00300000, &vec), false);
}