33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
55
6+ use std:: fmt;
67use std:: io:: { Error , ErrorKind } ;
78
89// Represents a parsed single line from /proc/<PID>/maps for the default and device formats. It
@@ -11,12 +12,50 @@ use std::io::{Error, ErrorKind};
1112pub struct MapLine {
1213 pub address : String ,
1314 pub size_in_kb : u64 ,
14- pub perms : String ,
15+ pub perms : Perms ,
1516 pub offset : String ,
1617 pub device : String ,
1718 pub mapping : String ,
1819}
1920
21+ // Represents a set of permissions from the "perms" column of /proc/<PID>/maps.
22+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
23+ pub struct Perms {
24+ pub readable : bool ,
25+ pub writable : bool ,
26+ pub executable : bool ,
27+ pub shared : bool ,
28+ }
29+
30+ impl From < & str > for Perms {
31+ fn from ( s : & str ) -> Self {
32+ let mut chars = s. chars ( ) ;
33+
34+ Self {
35+ readable : chars. next ( ) == Some ( 'r' ) ,
36+ writable : chars. next ( ) == Some ( 'w' ) ,
37+ executable : chars. next ( ) == Some ( 'x' ) ,
38+ shared : chars. next ( ) == Some ( 's' ) ,
39+ }
40+ }
41+ }
42+
43+ // Please note: While `Perms` has four boolean fields, it's string representation has five
44+ // characters because pmap's default and device formats use five characters for the perms,
45+ // with the last character always being '-'.
46+ impl fmt:: Display for Perms {
47+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
48+ write ! (
49+ f,
50+ "{}{}{}{}-" ,
51+ if self . readable { 'r' } else { '-' } ,
52+ if self . writable { 'w' } else { '-' } ,
53+ if self . executable { 'x' } else { '-' } ,
54+ if self . shared { 's' } else { '-' } ,
55+ )
56+ }
57+ }
58+
2059// Parses a single line from /proc/<PID>/maps. See
2160// https://www.kernel.org/doc/html/latest/filesystems/proc.html for details about the expected
2261// format.
@@ -33,7 +72,7 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
3372 let ( perms, rest) = rest
3473 . split_once ( ' ' )
3574 . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
36- let perms = parse_perms ( perms) ;
75+ let perms = Perms :: from ( perms) ;
3776
3877 let ( offset, rest) = rest
3978 . split_once ( ' ' )
@@ -74,15 +113,6 @@ fn parse_address(memory_range: &str) -> Result<(String, u64), Error> {
74113 Ok ( ( format ! ( "{start:0>16}" ) , size_in_kb) )
75114}
76115
77- // Turns a 4-char perms string from /proc/<PID>/maps into a 5-char perms string. The first three
78- // chars are left untouched.
79- fn parse_perms ( perms : & str ) -> String {
80- let perms = perms. replace ( "p" , "-" ) ;
81-
82- // the fifth char seems to be always '-' in the original pmap
83- format ! ( "{perms}-" )
84- }
85-
86116// Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
87117fn parse_device ( device : & str ) -> Result < String , Error > {
88118 let ( major, minor) = device
@@ -113,50 +143,57 @@ mod test {
113143 fn create_map_line (
114144 address : & str ,
115145 size_in_kb : u64 ,
116- perms : & str ,
146+ perms : Perms ,
117147 offset : & str ,
118148 device : & str ,
119149 mapping : & str ,
120150 ) -> MapLine {
121151 MapLine {
122152 address : address. to_string ( ) ,
123153 size_in_kb,
124- perms : perms . to_string ( ) ,
154+ perms,
125155 offset : offset. to_string ( ) ,
126156 device : device. to_string ( ) ,
127157 mapping : mapping. to_string ( ) ,
128158 }
129159 }
130160
161+ #[ test]
162+ fn test_perms_to_string ( ) {
163+ assert_eq ! ( "-----" , Perms :: from( "---p" ) . to_string( ) ) ;
164+ assert_eq ! ( "---s-" , Perms :: from( "---s" ) . to_string( ) ) ;
165+ assert_eq ! ( "rwx--" , Perms :: from( "rwxp" ) . to_string( ) ) ;
166+ }
167+
131168 #[ test]
132169 fn test_parse_map_line ( ) {
133170 let data = [
134171 (
135- create_map_line ( "000062442eb9e000" , 16 , "r----" , "0000000000000000" , "008:00008" , "konsole" ) ,
172+ create_map_line ( "000062442eb9e000" , 16 , Perms :: from ( "r--p" ) , "0000000000000000" , "008:00008" , "konsole" ) ,
136173 "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
137174 ) ,
138175 (
139- create_map_line ( "000071af50000000" , 132 , "rw---" , "0000000000000000" , "000:00000" , " [ anon ]" ) ,
176+ create_map_line ( "000071af50000000" , 132 , Perms :: from ( "rw-p" ) , "0000000000000000" , "000:00000" , " [ anon ]" ) ,
140177 "71af50000000-71af50021000 rw-p 00000000 00:00 0 "
141178 ) ,
142179 (
143- create_map_line ( "00007ffc3f8df000" , 132 , "rw---" , "0000000000000000" , "000:00000" , " [ stack ]" ) ,
180+ create_map_line ( "00007ffc3f8df000" , 132 , Perms :: from ( "rw-p" ) , "0000000000000000" , "000:00000" , " [ stack ]" ) ,
144181 "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
145182 ) ,
146183 (
147- create_map_line ( "000071af8c9e6000" , 16 , "rw-s-" , "0000000105830000" , "000:00010" , " [ anon ]" ) ,
184+ create_map_line ( "000071af8c9e6000" , 16 , Perms :: from ( "rw-s" ) , "0000000105830000" , "000:00010" , " [ anon ]" ) ,
148185 "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
149186 ) ,
150187 (
151- create_map_line ( "000071af6cf0c000" , 3560 , "rw-s-" , "0000000000000000" , "000:00001" , "memfd:wayland-shm (deleted)" ) ,
188+ create_map_line ( "000071af6cf0c000" , 3560 , Perms :: from ( "rw-s" ) , "0000000000000000" , "000:00001" , "memfd:wayland-shm (deleted)" ) ,
152189 "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
153190 ) ,
154191 (
155- create_map_line ( "ffffffffff600000" , 4 , "--x--" , "0000000000000000" , "000:00000" , " [ anon ]" ) ,
192+ create_map_line ( "ffffffffff600000" , 4 , Perms :: from ( "--xp" ) , "0000000000000000" , "000:00000" , " [ anon ]" ) ,
156193 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
157194 ) ,
158195 (
159- create_map_line ( "00005e8187da8000" , 24 , "r----" , "0000000000000000" , "008:00008" , "hello world" ) ,
196+ create_map_line ( "00005e8187da8000" , 24 , Perms :: from ( "r--p" ) , "0000000000000000" , "008:00008" , "hello world" ) ,
160197 "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
161198 ) ,
162199 ] ;
@@ -193,13 +230,6 @@ mod test {
193230 assert ! ( parse_address( "ffffffffff600000-zfffffffff601000" ) . is_err( ) ) ;
194231 }
195232
196- #[ test]
197- fn test_parse_perms ( ) {
198- assert_eq ! ( "-----" , parse_perms( "---p" ) ) ;
199- assert_eq ! ( "---s-" , parse_perms( "---s" ) ) ;
200- assert_eq ! ( "rwx--" , parse_perms( "rwxp" ) ) ;
201- }
202-
203233 #[ test]
204234 fn test_parse_device ( ) {
205235 assert_eq ! ( "012:00034" , parse_device( "12:34" ) . unwrap( ) ) ;
0 commit comments