@@ -10,15 +10,37 @@ use std::io::{Error, ErrorKind};
1010// Represents a parsed single line from /proc/<PID>/maps.
1111#[ derive( Debug , Clone , Default , PartialEq ) ]
1212pub struct MapLine {
13- pub address : String ,
13+ pub address : Address ,
1414 pub size_in_kb : u64 ,
1515 pub perms : Perms ,
1616 pub offset : String ,
17- pub device : String ,
17+ pub device : Device ,
1818 pub inode : u64 ,
1919 pub mapping : String ,
2020}
2121
22+ #[ derive( Debug , Clone , Default , PartialEq ) ]
23+ pub struct Address {
24+ pub start : String ,
25+ pub low : u64 ,
26+ pub high : u64 ,
27+ }
28+
29+ impl fmt:: Display for Address {
30+ // By default, pads with white spaces.
31+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
32+ write ! ( f, "{: >16}" , self . start)
33+ }
34+ }
35+
36+ impl Address {
37+ // Format for default, extended option, and device option.
38+ // Pads the start address with zero.
39+ pub fn zero_pad ( & self ) -> String {
40+ format ! ( "{:0>16}" , self . start)
41+ }
42+ }
43+
2244// Represents a set of permissions from the "perms" column of /proc/<PID>/maps.
2345#[ derive( Clone , Copy , Debug , Default , PartialEq ) ]
2446pub struct Perms {
@@ -69,6 +91,28 @@ impl Perms {
6991 }
7092}
7193
94+ #[ derive( Debug , Clone , Default , PartialEq ) ]
95+ pub struct Device {
96+ pub major : String ,
97+ pub minor : String ,
98+ pub width : usize ,
99+ }
100+
101+ impl fmt:: Display for Device {
102+ // By default, does not pad.
103+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
104+ write ! ( f, "{}:{}" , self . major, self . minor)
105+ }
106+ }
107+
108+ impl Device {
109+ // Format for device option.
110+ // Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
111+ pub fn device ( & self ) -> String {
112+ format ! ( "{:0>3}:{:0>5}" , self . major, self . minor)
113+ }
114+ }
115+
72116// Parses a single line from /proc/<PID>/maps. See
73117// https://www.kernel.org/doc/html/latest/filesystems/proc.html for details about the expected
74118// format.
@@ -90,7 +134,7 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
90134 let ( offset, rest) = rest
91135 . split_once ( ' ' )
92136 . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
93- let offset = format ! ( "{offset:0>16 }" ) ;
137+ let offset = format ! ( "{offset:0>8 }" ) ;
94138
95139 let ( device, rest) = rest
96140 . split_once ( ' ' )
@@ -116,9 +160,8 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
116160 } )
117161}
118162
119- // Returns the start address and the size of the provided memory range. The start address is always
120- // 16-digits and padded with 0, if necessary. The size is in KB.
121- fn parse_address ( memory_range : & str ) -> Result < ( String , u64 ) , Error > {
163+ // Returns Address instance and the size of the provided memory range. The size is in KB.
164+ fn parse_address ( memory_range : & str ) -> Result < ( Address , u64 ) , Error > {
122165 let ( start, end) = memory_range
123166 . split_once ( '-' )
124167 . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
@@ -127,15 +170,26 @@ fn parse_address(memory_range: &str) -> Result<(String, u64), Error> {
127170 let high = u64:: from_str_radix ( end, 16 ) . map_err ( |_| Error :: from ( ErrorKind :: InvalidData ) ) ?;
128171 let size_in_kb = ( high - low) / 1024 ;
129172
130- Ok ( ( format ! ( "{start:0>16}" ) , size_in_kb) )
173+ Ok ( (
174+ Address {
175+ start : start. to_string ( ) ,
176+ low,
177+ high,
178+ } ,
179+ size_in_kb,
180+ ) )
131181}
132182
133- // Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD .
134- fn parse_device ( device : & str ) -> Result < String , Error > {
183+ // Returns Device instance .
184+ fn parse_device ( device : & str ) -> Result < Device , Error > {
135185 let ( major, minor) = device
136186 . split_once ( ':' )
137187 . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
138- Ok ( format ! ( "{major:0>3}:{minor:0>5}" ) )
188+ Ok ( Device {
189+ major : major. to_string ( ) ,
190+ minor : minor. to_string ( ) ,
191+ width : device. len ( ) ,
192+ } )
139193}
140194
141195impl MapLine {
@@ -174,19 +228,31 @@ mod test {
174228
175229 fn create_map_line (
176230 address : & str ,
231+ low : u64 ,
232+ high : u64 ,
177233 size_in_kb : u64 ,
178234 perms : Perms ,
179235 offset : & str ,
180- device : & str ,
236+ major : & str ,
237+ minor : & str ,
238+ width : usize ,
181239 inode : u64 ,
182240 mapping : & str ,
183241 ) -> MapLine {
184242 MapLine {
185- address : address. to_string ( ) ,
243+ address : Address {
244+ start : address. to_string ( ) ,
245+ low,
246+ high,
247+ } ,
186248 size_in_kb,
187249 perms,
188250 offset : offset. to_string ( ) ,
189- device : device. to_string ( ) ,
251+ device : Device {
252+ major : major. to_string ( ) ,
253+ minor : minor. to_string ( ) ,
254+ width,
255+ } ,
190256 inode,
191257 mapping : mapping. to_string ( ) ,
192258 }
@@ -210,31 +276,31 @@ mod test {
210276 fn test_parse_map_line ( ) {
211277 let data = [
212278 (
213- create_map_line ( "000062442eb9e000 " , 16 , Perms :: from ( "r--p" ) , "0000000000000000 " , "008:00008" , 10813151 , "/usr/bin/konsole" ) ,
279+ create_map_line ( "62442eb9e000 " , 0x62442eb9e000 , 0x62442eba2000 , 16 , Perms :: from ( "r--p" ) , "00000000 " , "08" , "08" , 5 , 10813151 , "/usr/bin/konsole" ) ,
214280 "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
215281 ) ,
216282 (
217- create_map_line ( "000071af50000000 " , 132 , Perms :: from ( "rw-p" ) , "0000000000000000 " , "000:00000" , 0 , "" ) ,
283+ create_map_line ( "71af50000000 " , 0x71af50000000 , 0x71af50021000 , 132 , Perms :: from ( "rw-p" ) , "00000000 " , "00" , "00" , 5 , 0 , "" ) ,
218284 "71af50000000-71af50021000 rw-p 00000000 00:00 0 "
219285 ) ,
220286 (
221- create_map_line ( "00007ffc3f8df000 " , 132 , Perms :: from ( "rw-p" ) , "0000000000000000 " , "000:00000" , 0 , "[stack]" ) ,
287+ create_map_line ( "7ffc3f8df000 " , 0x7ffc3f8df000 , 0x7ffc3f900000 , 132 , Perms :: from ( "rw-p" ) , "00000000 " , "00" , "00" , 5 , 0 , "[stack]" ) ,
222288 "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
223289 ) ,
224290 (
225- create_map_line ( "000071af8c9e6000 " , 16 , Perms :: from ( "rw-s" ) , "0000000105830000 " , "000:00010" , 1075 , "anon_inode:i915.gem" ) ,
291+ create_map_line ( "71af8c9e6000 " , 0x71af8c9e6000 , 0x71af8c9ea000 , 16 , Perms :: from ( "rw-s" ) , "105830000 " , "00" , "10" , 5 , 1075 , "anon_inode:i915.gem" ) ,
226292 "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
227293 ) ,
228294 (
229- create_map_line ( "000071af6cf0c000 " , 3560 , Perms :: from ( "rw-s" ) , "0000000000000000 " , "000:00001" , 256481 , "/memfd:wayland-shm (deleted)" ) ,
295+ create_map_line ( "71af6cf0c000 " , 0x71af6cf0c000 , 0x71af6d286000 , 3560 , Perms :: from ( "rw-s" ) , "00000000 " , "00" , "01" , 5 , 256481 , "/memfd:wayland-shm (deleted)" ) ,
230296 "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
231297 ) ,
232298 (
233- create_map_line ( "ffffffffff600000" , 4 , Perms :: from ( "--xp" ) , "0000000000000000 " , "000:00000" , 0 , "[vsyscall]" ) ,
299+ create_map_line ( "ffffffffff600000" , 0xffffffffff600000 , 0xffffffffff601000 , 4 , Perms :: from ( "--xp" ) , "00000000 " , "00" , "00" , 5 , 0 , "[vsyscall]" ) ,
234300 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
235301 ) ,
236302 (
237- create_map_line ( "00005e8187da8000 " , 24 , Perms :: from ( "r--p" ) , "0000000000000000 " , "008:00008" , 9524160 , "/usr/bin/hello world" ) ,
303+ create_map_line ( "5e8187da8000 " , 0x5e8187da8000 , 0x5e8187dae000 , 24 , Perms :: from ( "r--p" ) , "00000000 " , "08" , "08" , 5 , 9524160 , "/usr/bin/hello world" ) ,
238304 "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
239305 ) ,
240306 ] ;
@@ -251,12 +317,16 @@ mod test {
251317
252318 #[ test]
253319 fn test_parse_address ( ) {
254- let ( start, size) = parse_address ( "ffffffffff600000-ffffffffff601000" ) . unwrap ( ) ;
255- assert_eq ! ( start, "ffffffffff600000" ) ;
320+ let ( address, size) = parse_address ( "ffffffffff600000-ffffffffff601000" ) . unwrap ( ) ;
321+ assert_eq ! ( address. start, "ffffffffff600000" ) ;
322+ assert_eq ! ( address. low, 0xffffffffff600000 ) ;
323+ assert_eq ! ( address. high, 0xffffffffff601000 ) ;
256324 assert_eq ! ( size, 4 ) ;
257325
258- let ( start, size) = parse_address ( "7ffc4f0c2000-7ffc4f0e3000" ) . unwrap ( ) ;
259- assert_eq ! ( start, "00007ffc4f0c2000" ) ;
326+ let ( address, size) = parse_address ( "7ffc4f0c2000-7ffc4f0e3000" ) . unwrap ( ) ;
327+ assert_eq ! ( address. start, "7ffc4f0c2000" ) ;
328+ assert_eq ! ( address. low, 0x7ffc4f0c2000 ) ;
329+ assert_eq ! ( address. high, 0x7ffc4f0e3000 ) ;
260330 assert_eq ! ( size, 132 ) ;
261331 }
262332
@@ -273,8 +343,15 @@ mod test {
273343
274344 #[ test]
275345 fn test_parse_device ( ) {
276- assert_eq ! ( "012:00034" , parse_device( "12:34" ) . unwrap( ) ) ;
277- assert_eq ! ( "000:00000" , parse_device( "00:00" ) . unwrap( ) ) ;
346+ assert_eq ! ( "12:34" , parse_device( "12:34" ) . unwrap( ) . to_string( ) ) ;
347+ assert_eq ! ( "00:00" , parse_device( "00:00" ) . unwrap( ) . to_string( ) ) ;
348+ assert_eq ! ( "fe:01" , parse_device( "fe:01" ) . unwrap( ) . to_string( ) ) ;
349+ assert_eq ! ( "103:100" , parse_device( "103:100" ) . unwrap( ) . to_string( ) ) ;
350+
351+ assert_eq ! ( "012:00034" , parse_device( "12:34" ) . unwrap( ) . device( ) ) ;
352+ assert_eq ! ( "000:00000" , parse_device( "00:00" ) . unwrap( ) . device( ) ) ;
353+ assert_eq ! ( "0fe:00001" , parse_device( "fe:01" ) . unwrap( ) . device( ) ) ;
354+ assert_eq ! ( "103:00100" , parse_device( "103:100" ) . unwrap( ) . device( ) ) ;
278355 }
279356
280357 #[ test]
0 commit comments