55
66use std:: io:: { Error , ErrorKind } ;
77
8- // Represents a parsed single line from /proc/<PID>/maps.
8+ // Represents a parsed single line from /proc/<PID>/maps for the default and device formats. It
9+ // omits the inode information because it's not used by those formats.
910#[ derive( Debug , PartialEq ) ]
1011pub struct MapLine {
1112 pub address : String ,
1213 pub size_in_kb : u64 ,
1314 pub perms : String ,
15+ pub offset : String ,
16+ pub device : String ,
1417 pub mapping : String ,
1518}
1619
@@ -32,14 +35,27 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
3235 . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
3336 let perms = parse_perms ( perms) ;
3437
35- let mapping: String = rest. splitn ( 4 , ' ' ) . skip ( 3 ) . collect ( ) ;
38+ let ( offset, rest) = rest
39+ . split_once ( ' ' )
40+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
41+ let offset = format ! ( "{offset:0>16}" ) ;
42+
43+ let ( device, rest) = rest
44+ . split_once ( ' ' )
45+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
46+ let device = parse_device ( device) ?;
47+
48+ // skip the "inode" column
49+ let mapping: String = rest. splitn ( 2 , ' ' ) . skip ( 1 ) . collect ( ) ;
3650 let mapping = mapping. trim_ascii_start ( ) ;
3751 let mapping = parse_mapping ( mapping) ;
3852
3953 Ok ( MapLine {
4054 address,
4155 size_in_kb,
4256 perms,
57+ offset,
58+ device,
4359 mapping,
4460 } )
4561}
@@ -67,6 +83,14 @@ fn parse_perms(perms: &str) -> String {
6783 format ! ( "{perms}-" )
6884}
6985
86+ // Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
87+ fn parse_device ( device : & str ) -> Result < String , Error > {
88+ let ( major, minor) = device
89+ . split_once ( ':' )
90+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
91+ Ok ( format ! ( "{major:0>3}:{minor:0>5}" ) )
92+ }
93+
7094fn parse_mapping ( mapping : & str ) -> String {
7195 if mapping == "[stack]" {
7296 return " [ stack ]" . into ( ) ;
@@ -86,11 +110,20 @@ fn parse_mapping(mapping: &str) -> String {
86110mod test {
87111 use super :: * ;
88112
89- fn create_map_line ( address : & str , size_in_kb : u64 , perms : & str , mapping : & str ) -> MapLine {
113+ fn create_map_line (
114+ address : & str ,
115+ size_in_kb : u64 ,
116+ perms : & str ,
117+ offset : & str ,
118+ device : & str ,
119+ mapping : & str ,
120+ ) -> MapLine {
90121 MapLine {
91122 address : address. to_string ( ) ,
92123 size_in_kb,
93124 perms : perms. to_string ( ) ,
125+ offset : offset. to_string ( ) ,
126+ device : device. to_string ( ) ,
94127 mapping : mapping. to_string ( ) ,
95128 }
96129 }
@@ -99,31 +132,31 @@ mod test {
99132 fn test_parse_map_line ( ) {
100133 let data = [
101134 (
102- create_map_line ( "000062442eb9e000" , 16 , "r----" , "konsole" ) ,
135+ create_map_line ( "000062442eb9e000" , 16 , "r----" , "0000000000000000" , "008:00008" , " konsole") ,
103136 "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
104137 ) ,
105138 (
106- create_map_line ( "000071af50000000" , 132 , "rw---" , " [ anon ]" ) ,
139+ create_map_line ( "000071af50000000" , 132 , "rw---" , "0000000000000000" , "000:00000" , " [ anon ]") ,
107140 "71af50000000-71af50021000 rw-p 00000000 00:00 0 "
108141 ) ,
109142 (
110- create_map_line ( "00007ffc3f8df000" , 132 , "rw---" , " [ stack ]" ) ,
143+ create_map_line ( "00007ffc3f8df000" , 132 , "rw---" , "0000000000000000" , "000:00000" , " [ stack ]") ,
111144 "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
112145 ) ,
113146 (
114- create_map_line ( "000071af8c9e6000" , 16 , "rw-s-" , " [ anon ]" ) ,
147+ create_map_line ( "000071af8c9e6000" , 16 , "rw-s-" , "0000000105830000" , "000:00010" , " [ anon ]") ,
115148 "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
116149 ) ,
117150 (
118- create_map_line ( "000071af6cf0c000" , 3560 , "rw-s-" , "memfd:wayland-shm (deleted)" ) ,
151+ create_map_line ( "000071af6cf0c000" , 3560 , "rw-s-" , "0000000000000000" , "000:00001" , " memfd:wayland-shm (deleted)") ,
119152 "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
120153 ) ,
121154 (
122- create_map_line ( "ffffffffff600000" , 4 , "--x--" , " [ anon ]" ) ,
155+ create_map_line ( "ffffffffff600000" , 4 , "--x--" , "0000000000000000" , "000:00000" , " [ anon ]") ,
123156 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
124157 ) ,
125158 (
126- create_map_line ( "00005e8187da8000" , 24 , "r----" , "hello world" ) ,
159+ create_map_line ( "00005e8187da8000" , 24 , "r----" , "0000000000000000" , "008:00008" , " hello world") ,
127160 "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
128161 ) ,
129162 ] ;
@@ -167,6 +200,17 @@ mod test {
167200 assert_eq ! ( "rwx--" , parse_perms( "rwxp" ) ) ;
168201 }
169202
203+ #[ test]
204+ fn test_parse_device ( ) {
205+ assert_eq ! ( "012:00034" , parse_device( "12:34" ) . unwrap( ) ) ;
206+ assert_eq ! ( "000:00000" , parse_device( "00:00" ) . unwrap( ) ) ;
207+ }
208+
209+ #[ test]
210+ fn test_parse_device_without_colon ( ) {
211+ assert ! ( parse_device( "1234" ) . is_err( ) ) ;
212+ }
213+
170214 #[ test]
171215 fn test_parse_mapping ( ) {
172216 assert_eq ! ( " [ anon ]" , parse_mapping( "" ) ) ;
0 commit comments