44
55use super :: mystd:: fs:: File ;
66use super :: mystd:: io:: Read ;
7- use super :: mystd :: str :: FromStr ;
8- use super :: { OsString , String , Vec } ;
7+ use super :: OsString ;
8+ use super :: { String , Vec } ;
99
1010#[ derive( PartialEq , Eq , Debug ) ]
11- pub ( super ) struct MapsEntry {
11+ pub struct MapsEntry {
1212 /// start (inclusive) and limit (exclusive) of address range.
1313 address : ( usize , usize ) ,
1414 /// The perms field are the permissions for the entry
@@ -53,42 +53,6 @@ pub(super) struct MapsEntry {
5353 pathname : OsString ,
5454}
5555
56- #[ cfg( not( target_os = "nto" ) ) ]
57- pub ( super ) fn parse_maps ( ) -> Result < Vec < MapsEntry > , & ' static str > {
58- let mut v = Vec :: new ( ) ;
59- let mut proc_self_maps =
60- File :: open ( "/proc/self/maps" ) . map_err ( |_| "Couldn't open /proc/self/maps" ) ?;
61- let mut buf = String :: new ( ) ;
62- let _bytes_read = proc_self_maps
63- . read_to_string ( & mut buf)
64- . map_err ( |_| "Couldn't read /proc/self/maps" ) ?;
65- for line in buf. lines ( ) {
66- v. push ( line. parse ( ) ?) ;
67- }
68-
69- Ok ( v)
70- }
71-
72- // TODO: This could be merged with the above block but seems to require
73- // creating a couple of extra strings to pass to map_err(). Is
74- // there a way to pass it paramenters without adding a bunch of
75- // lines of code?
76- #[ cfg( target_os = "nto" ) ]
77- pub ( super ) fn parse_maps ( ) -> Result < Vec < MapsEntry > , & ' static str > {
78- let mut v = Vec :: new ( ) ;
79- let mut proc_self_maps =
80- File :: open ( "/proc/self/pmap" ) . map_err ( |_| "Couldn't open /proc/self/pmap" ) ?;
81- let mut buf = String :: new ( ) ;
82- let _bytes_read = proc_self_maps
83- . read_to_string ( & mut buf)
84- . map_err ( |_| "Couldn't read /proc/self/pmap" ) ?;
85- for line in buf. lines ( ) {
86- v. push ( line. parse ( ) ?) ;
87- }
88-
89- Ok ( v)
90- }
91-
9256impl MapsEntry {
9357 pub ( super ) fn pathname ( & self ) -> & OsString {
9458 & self . pathname
@@ -99,269 +63,51 @@ impl MapsEntry {
9963 }
10064}
10165
102- #[ cfg( not( target_os = "nto" ) ) ]
103- impl FromStr for MapsEntry {
104- type Err = & ' static str ;
105-
106- // Format: address perms offset dev inode pathname
107- // e.g.: "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
108- // e.g.: "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
109- // e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
110- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
111- let mut parts = s
112- . split ( ' ' ) // space-separated fields
113- . filter ( |s| s. len ( ) > 0 ) ; // multiple spaces implies empty strings that need to be skipped.
114- let range_str = parts. next ( ) . ok_or ( "Couldn't find address" ) ?;
115- let perms_str = parts. next ( ) . ok_or ( "Couldn't find permissions" ) ?;
116- let offset_str = parts. next ( ) . ok_or ( "Couldn't find offset" ) ?;
117- let dev_str = parts. next ( ) . ok_or ( "Couldn't find dev" ) ?;
118- let inode_str = parts. next ( ) . ok_or ( "Couldn't find inode" ) ?;
119- let pathname_str = parts. next ( ) . unwrap_or ( "" ) ; // pathname may be omitted.
120-
121- let hex = |s| usize:: from_str_radix ( s, 16 ) . map_err ( |_| "Couldn't parse hex number" ) ;
122- let address = {
123- // This could use `range_str.split_once('-')` once the MSRV passes 1.52.
124- if let Some ( idx) = range_str. find ( '-' ) {
125- let ( start, rest) = range_str. split_at ( idx) ;
126- let ( _div, limit) = rest. split_at ( 1 ) ;
127- ( hex ( start) ?, hex ( limit) ?)
128- } else {
129- return Err ( "Couldn't parse address range" ) ;
130- }
131- } ;
132- let perms: [ char ; 4 ] = {
133- let mut chars = perms_str. chars ( ) ;
134- let mut c = || chars. next ( ) . ok_or ( "insufficient perms" ) ;
135- let perms = [ c ( ) ?, c ( ) ?, c ( ) ?, c ( ) ?] ;
136- if chars. next ( ) . is_some ( ) {
137- return Err ( "too many perms" ) ;
138- }
139- perms
140- } ;
141- let offset = hex ( offset_str) ?;
142- let dev = {
143- // This could use `dev_str.split_once(':')` once the MSRV passes 1.52.
144- if let Some ( idx) = dev_str. find ( ':' ) {
145- let ( major, rest) = dev_str. split_at ( idx) ;
146- let ( _div, minor) = rest. split_at ( 1 ) ;
147- ( hex ( major) ?, hex ( minor) ?)
148- } else {
149- return Err ( "Couldn't parse dev" ) ?;
150- }
151- } ;
152- let inode = hex ( inode_str) ?;
153- let pathname = pathname_str. into ( ) ;
154-
155- Ok ( MapsEntry {
156- address,
157- perms,
158- offset,
159- dev,
160- inode,
161- pathname,
162- } )
163- }
66+ fn concat_str ( a : & str , b : & str ) -> String {
67+ let mut e = String :: from ( a) ;
68+ e += b;
69+ e
16470}
16571
166- #[ cfg( target_os = "nto" ) ]
167- impl FromStr for MapsEntry {
168- type Err = & ' static str ;
169-
170- // Format: vaddr,size,flags,prot,maxprot,dev,ino,offset,rsv,guardsize,refcnt,mapcnt,path
171- // e.g.: "0x00000022fa36b000,0x0000000000002000,0x00000071,0x05,0x0f,0x0000040b,0x00000000000000dd,
172- // 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/proc/boot/cat"
173- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
174- let mut parts = s. split ( ',' ) ;
175- let vaddr_str = parts. next ( ) . ok_or ( "Couldn't find virtual address" ) ?;
176- let size_str = parts. next ( ) . ok_or ( "Couldn't find size" ) ?;
177- let _flags_str = parts. next ( ) . ok_or ( "Couldn't find flags" ) ?;
178- let prot_str = parts. next ( ) . ok_or ( "Couldn't find protection" ) ?;
179- let _maxprot_str = parts. next ( ) . ok_or ( "Couldn't find maximum protection" ) ?;
180- let dev_str = parts. next ( ) . ok_or ( "Couldn't find device" ) ?;
181- let ino_str = parts. next ( ) . ok_or ( "Couldn't find inode" ) ?;
182- let offset_str = parts. next ( ) . ok_or ( "Couldn't find offset" ) ?;
183- let _rsv_str = parts. next ( ) . ok_or ( "Couldn't find reserved pages" ) ?;
184- let _guardsize_str = parts. next ( ) . ok_or ( "Couldn't find guard size" ) ?;
185- let _refcnt_str = parts. next ( ) . ok_or ( "Couldn't find reference count" ) ?;
186- let _mapcnt_str = parts. next ( ) . ok_or ( "Couldn't find mapped count" ) ?;
187- let pathname_str = parts. next ( ) . unwrap_or ( "" ) ; // pathname may be omitted.
188-
189- let hex = |s : & str | usize:: from_str_radix ( & s[ 2 ..] , 16 ) . map_err ( |_| "Couldn't parse hex number" ) ;
190- let address = { ( hex ( vaddr_str) ?, hex ( vaddr_str) ? + hex ( size_str) ?) } ;
191-
192- // TODO: Probably a rust'ier way of doing this
193- let mut perms: [ char ; 4 ] = [ '-' , '-' , '-' , '-' ] ;
194- let perm_str: [ char ; 3 ] = [ 'r' , 'w' , 'x' ] ;
195- let perm_bits: [ usize ; 3 ] = [ 0x1 , 0x2 , 0x4 ] ;
196-
197- for ( pos, val) in perm_bits. iter ( ) . enumerate ( ) {
198- let prot = hex ( prot_str) ?;
199- if val & prot != 0 {
200- perms[ pos] = perm_str[ pos]
201- }
202- }
203-
204- let offset = hex ( offset_str) ?;
205- let dev = { ( hex ( dev_str) ?, 0x00000000 ) } ;
206- let inode = hex ( ino_str) ?;
207- let pathname = pathname_str. into ( ) ;
208-
209- Ok ( MapsEntry {
210- address,
211- perms,
212- offset,
213- dev,
214- inode,
215- pathname,
216- } )
217- }
72+ fn read_file ( file : & str ) -> Result < String , String > {
73+ let mut proc_self_maps =
74+ File :: open ( file) . map_err ( |_| concat_str ( "Couldn't open file: " , file) ) ?;
75+ let mut buf = String :: new ( ) ;
76+ let _bytes_read = proc_self_maps
77+ . read_to_string ( & mut buf)
78+ . map_err ( |_| concat_str ( "Couldn't read file: " , file) ) ?;
79+ Ok ( buf)
21880}
21981
220- // Make sure we can parse 64-bit sample output if we're on a 64-bit target.
221- #[ cfg( target_pointer_width = "64" ) ]
222- #[ test]
223- #[ cfg( not( target_os = "nto" ) ) ]
224- fn check_maps_entry_parsing_64bit ( ) {
225- assert_eq ! (
226- "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 \
227- [vsyscall]"
228- . parse:: <MapsEntry >( )
229- . unwrap( ) ,
230- MapsEntry {
231- address: ( 0xffffffffff600000 , 0xffffffffff601000 ) ,
232- perms: [ '-' , '-' , 'x' , 'p' ] ,
233- offset: 0x00000000 ,
234- dev: ( 0x00 , 0x00 ) ,
235- inode: 0x0 ,
236- pathname: "[vsyscall]" . into( ) ,
237- }
238- ) ;
239-
240- assert_eq ! (
241- "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 \
242- /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
243- . parse:: <MapsEntry >( )
244- . unwrap( ) ,
245- MapsEntry {
246- address: ( 0x7f5985f46000 , 0x7f5985f48000 ) ,
247- perms: [ 'r' , 'w' , '-' , 'p' ] ,
248- offset: 0x00039000 ,
249- dev: ( 0x103 , 0x06 ) ,
250- inode: 0x76021795 ,
251- pathname: "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" . into( ) ,
252- }
253- ) ;
254- assert_eq ! (
255- "35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
256- . parse:: <MapsEntry >( )
257- . unwrap( ) ,
258- MapsEntry {
259- address: ( 0x35b1a21000 , 0x35b1a22000 ) ,
260- perms: [ 'r' , 'w' , '-' , 'p' ] ,
261- offset: 0x00000000 ,
262- dev: ( 0x00 , 0x00 ) ,
263- inode: 0x0 ,
264- pathname: Default :: default ( ) ,
265- }
266- ) ;
82+ pub fn parse_maps ( ) -> Result < Vec < MapsEntry > , String > {
83+ let ( file, skip) = config ( ) ;
84+ let content = read_file ( file) ?;
85+ parse_maps_lines ( & content, skip)
26786}
26887
269- #[ cfg( target_os = "nto" ) ]
270- fn check_maps_entry_parsing_64bit ( ) {
271- assert_eq ! (
272- "0xffffffffff600000,0x0000000000001000,0x00000071,0x04,0x0f,0x00000000,0x0000000000000000,\
273- 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/proc/boot/foo"
274- . parse:: <MapsEntry >( )
275- . unwrap( ) ,
276- MapsEntry {
277- address: ( 0xffffffffff600000 , 0xffffffffff601000 ) ,
278- perms: [ '-' , '-' , 'x' , '-' ] ,
279- offset: 0x00000000 ,
280- dev: ( 0x00 , 0x00 ) ,
281- inode: 0x0 ,
282- pathname: "/proc/boot/foo" . into( ) ,
283- }
284- ) ;
285-
286- assert_eq ! (
287- "0x00007f5985f46000,0x0000000000002000,0x00000071,0x03,0x0f,0x00000103,0x0000000076021795,\
288- 0x0000000000039000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/usr/lib/ldqnx-64.so.2"
289- . parse:: <MapsEntry >( )
290- . unwrap( ) ,
291- MapsEntry {
292- address: ( 0x7f5985f46000 , 0x7f5985f48000 ) ,
293- perms: [ 'r' , 'w' , '-' , '-' ] ,
294- offset: 0x00039000 ,
295- dev: ( 0x103 , 0x0 ) ,
296- inode: 0x76021795 ,
297- pathname: "/usr/lib/ldqnx-64.so.2" . into( ) ,
298- }
299- ) ;
300- assert_eq ! (
301- "0x00000035b1a21000,0x0000000000001000,0x00000071,0x03,0x0f,0x00000000,0x0000000000000000,\
302- 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003,"
303- . parse:: <MapsEntry >( )
304- . unwrap( ) ,
305- MapsEntry {
306- address: ( 0x35b1a21000 , 0x35b1a22000 ) ,
307- perms: [ 'r' , 'w' , '-' , '-' ] ,
308- offset: 0x00000000 ,
309- dev: ( 0x00 , 0x00 ) ,
310- inode: 0x0 ,
311- pathname: Default :: default ( ) ,
312- }
313- ) ;
88+ fn parse_maps_lines ( content : & str , skip : usize ) -> Result < Vec < MapsEntry > , String > {
89+ let mut data = Vec :: new ( ) ;
90+ for line in content. lines ( ) . skip ( skip) {
91+ data. push ( line. parse ( ) ?) ;
92+ }
93+ Ok ( data)
31494}
31595
316- // (This output was taken from a 32-bit machine, but will work on any target)
317- #[ cfg( not( target_os = "nto" ) ) ]
318- #[ test]
319- fn check_maps_entry_parsing_32bit ( ) {
320- /* Example snippet of output:
321- 08056000-08077000 rw-p 00000000 00:00 0 [heap]
322- b7c79000-b7e02000 r--p 00000000 08:01 60662705 /usr/lib/locale/locale-archive
323- b7e02000-b7e03000 rw-p 00000000 00:00 0
324- */
325- assert_eq ! (
326- "08056000-08077000 rw-p 00000000 00:00 0 \
327- [heap]"
328- . parse:: <MapsEntry >( )
329- . unwrap( ) ,
330- MapsEntry {
331- address: ( 0x08056000 , 0x08077000 ) ,
332- perms: [ 'r' , 'w' , '-' , 'p' ] ,
333- offset: 0x00000000 ,
334- dev: ( 0x00 , 0x00 ) ,
335- inode: 0x0 ,
336- pathname: "[heap]" . into( ) ,
337- }
338- ) ;
96+ cfg_if:: cfg_if! {
97+ if #[ cfg( target_os = "nto" ) ] {
98+ mod parse_running_mmaps_unix_nto;
99+ use parse_running_mmaps_unix_nto:: * ;
100+ } else {
101+ mod parse_running_mmaps_unix_default;
102+ use parse_running_mmaps_unix_default:: * ;
103+ }
104+ }
339105
340- assert_eq ! (
341- "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
342- /usr/lib/locale/locale-archive"
343- . parse:: <MapsEntry >( )
344- . unwrap( ) ,
345- MapsEntry {
346- address: ( 0xb7c79000 , 0xb7e02000 ) ,
347- perms: [ 'r' , '-' , '-' , 'p' ] ,
348- offset: 0x00000000 ,
349- dev: ( 0x08 , 0x01 ) ,
350- inode: 0x60662705 ,
351- pathname: "/usr/lib/locale/locale-archive" . into( ) ,
352- }
353- ) ;
354- assert_eq ! (
355- "b7e02000-b7e03000 rw-p 00000000 00:00 0"
356- . parse:: <MapsEntry >( )
357- . unwrap( ) ,
358- MapsEntry {
359- address: ( 0xb7e02000 , 0xb7e03000 ) ,
360- perms: [ 'r' , 'w' , '-' , 'p' ] ,
361- offset: 0x00000000 ,
362- dev: ( 0x00 , 0x00 ) ,
363- inode: 0x0 ,
364- pathname: Default :: default ( ) ,
365- }
366- ) ;
106+ #[ cfg( test) ]
107+ mod test {
108+ #[ test]
109+ fn test_parse_maps ( ) {
110+ use super :: * ;
111+ assert ! ( parse_maps( ) . is_ok( ) ) ;
112+ }
367113}
0 commit comments