44// file that was distributed with this source code.
55
66use clap:: { crate_version, Arg , ArgAction , Command } ;
7+ use maps_format_parser:: parse_map_line;
78use std:: env;
89use std:: fs;
910use std:: io:: Error ;
1011use uucore:: error:: { set_exit_code, UResult } ;
1112use uucore:: { format_usage, help_about, help_usage} ;
1213
14+ mod maps_format_parser;
15+
1316const ABOUT : & str = help_about ! ( "pmap.md" ) ;
1417const USAGE : & str = help_usage ! ( "pmap.md" ) ;
1518
@@ -41,7 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4144}
4245
4346fn parse_cmdline ( pid : & str ) -> Result < String , Error > {
44- let path = format ! ( "/proc/{}/cmdline" , pid ) ;
47+ let path = format ! ( "/proc/{pid }/cmdline" ) ;
4548 let contents = fs:: read ( path) ?;
4649 // Command line arguments are separated by null bytes.
4750 // Replace them with spaces for display.
@@ -55,78 +58,22 @@ fn parse_cmdline(pid: &str) -> Result<String, Error> {
5558}
5659
5760fn parse_maps ( pid : & str ) -> Result < u64 , Error > {
58- let path = format ! ( "/proc/{}/maps" , pid ) ;
61+ let path = format ! ( "/proc/{pid }/maps" ) ;
5962 let contents = fs:: read_to_string ( path) ?;
6063 let mut total = 0 ;
6164
6265 for line in contents. lines ( ) {
63- let ( generated_line, size) = parse_map_line ( line) ;
64- println ! ( "{generated_line}" ) ;
65- total += size;
66+ let map_line = parse_map_line ( line) ;
67+ println ! (
68+ "{} {:>6}K {} {}" ,
69+ map_line. address, map_line. size_in_kb, map_line. perms, map_line. mapping
70+ ) ;
71+ total += map_line. size_in_kb ;
6672 }
6773
6874 Ok ( total)
6975}
7076
71- // Parses a single line from /proc/<PID>/maps.
72- fn parse_map_line ( line : & str ) -> ( String , u64 ) {
73- let ( memory_range, rest) = line. split_once ( ' ' ) . expect ( "line should contain ' '" ) ;
74- let ( start_address, size_in_kb) = parse_memory_range ( memory_range) ;
75-
76- let ( perms, rest) = rest. split_once ( ' ' ) . expect ( "line should contain 2nd ' '" ) ;
77- let perms = parse_perms ( perms) ;
78-
79- let filename: String = rest. splitn ( 4 , ' ' ) . skip ( 3 ) . collect ( ) ;
80- let filename = filename. trim_ascii_start ( ) ;
81- let filename = parse_filename ( filename) ;
82-
83- (
84- format ! ( "{start_address} {size_in_kb:>6}K {perms} {filename}" ) ,
85- size_in_kb,
86- )
87- }
88-
89- // Returns the start address and the size of the provided memory range. The start address is always
90- // 16-digits and padded with 0, if necessary. The size is in KB.
91- //
92- // This function assumes the provided `memory_range` comes from /proc/<PID>/maps and thus its
93- // format is correct.
94- fn parse_memory_range ( memory_range : & str ) -> ( String , u64 ) {
95- let ( start, end) = memory_range
96- . split_once ( '-' )
97- . expect ( "memory range should contain '-'" ) ;
98-
99- let low = u64:: from_str_radix ( start, 16 ) . expect ( "should be a hex value" ) ;
100- let high = u64:: from_str_radix ( end, 16 ) . expect ( "should be a hex value" ) ;
101- let size_in_kb = ( high - low) / 1024 ;
102-
103- ( format ! ( "{start:0>16}" ) , size_in_kb)
104- }
105-
106- // Turns a 4-char perms string from /proc/<PID>/maps into a 5-char perms string. The first three
107- // chars are left untouched.
108- fn parse_perms ( perms : & str ) -> String {
109- let perms = perms. replace ( "p" , "-" ) ;
110-
111- // the fifth char seems to be always '-' in the original pmap
112- format ! ( "{perms}-" )
113- }
114-
115- fn parse_filename ( filename : & str ) -> String {
116- if filename == "[stack]" {
117- return " [ stack ]" . into ( ) ;
118- }
119-
120- if filename. is_empty ( ) || filename. starts_with ( '[' ) || filename. starts_with ( "anon" ) {
121- return " [ anon ]" . into ( ) ;
122- }
123-
124- match filename. rsplit_once ( '/' ) {
125- Some ( ( _, name) ) => name. into ( ) ,
126- None => filename. into ( ) ,
127- }
128- }
129-
13077pub fn uu_app ( ) -> Command {
13178 Command :: new ( env ! ( "CARGO_PKG_NAME" ) )
13279 . version ( crate_version ! ( ) )
@@ -208,79 +155,3 @@ pub fn uu_app() -> Command {
208155 . help ( "limit results to the given range" ) ,
209156 )
210157}
211-
212- #[ cfg( test) ]
213- mod test {
214- use super :: * ;
215-
216- #[ test]
217- fn test_parse_map_line ( ) {
218- let data = [
219- (
220- ( "000062442eb9e000 16K r---- konsole" , 16 ) ,
221- "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
222- ) ,
223- (
224- ( "000071af50000000 132K rw--- [ anon ]" , 132 ) ,
225- "71af50000000-71af50021000 rw-p 00000000 00:00 0 "
226- ) ,
227- (
228- ( "00007ffc3f8df000 132K rw--- [ stack ]" , 132 ) ,
229- "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
230- ) ,
231- (
232- ( "000071af8c9e6000 16K rw-s- [ anon ]" , 16 ) ,
233- "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
234- ) ,
235- (
236- ( "000071af6cf0c000 3560K rw-s- memfd:wayland-shm (deleted)" , 3560 ) ,
237- "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
238- ) ,
239- (
240- ( "ffffffffff600000 4K --x-- [ anon ]" , 4 ) ,
241- "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
242- ) ,
243- (
244- ( "00005e8187da8000 24K r---- hello world" , 24 ) ,
245- "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
246- ) ,
247- ] ;
248-
249- for ( ( expected_line, expected_size) , line) in data {
250- let ( generated_line, size) = parse_map_line ( line) ;
251- assert_eq ! ( expected_line, generated_line) ;
252- assert_eq ! ( expected_size, size) ;
253- }
254- }
255-
256- #[ test]
257- fn test_parse_memory_range ( ) {
258- let ( start, size) = parse_memory_range ( "ffffffffff600000-ffffffffff601000" ) ;
259- assert_eq ! ( start, "ffffffffff600000" ) ;
260- assert_eq ! ( size, 4 ) ;
261-
262- let ( start, size) = parse_memory_range ( "7ffc4f0c2000-7ffc4f0e3000" ) ;
263- assert_eq ! ( start, "00007ffc4f0c2000" ) ;
264- assert_eq ! ( size, 132 ) ;
265- }
266-
267- #[ test]
268- fn test_parse_perms ( ) {
269- assert_eq ! ( "-----" , parse_perms( "---p" ) ) ;
270- assert_eq ! ( "---s-" , parse_perms( "---s" ) ) ;
271- assert_eq ! ( "rwx--" , parse_perms( "rwxp" ) ) ;
272- }
273-
274- #[ test]
275- fn test_parse_filename ( ) {
276- assert_eq ! ( " [ anon ]" , parse_filename( "" ) ) ;
277- assert_eq ! ( " [ anon ]" , parse_filename( "[vvar]" ) ) ;
278- assert_eq ! ( " [ anon ]" , parse_filename( "[vdso]" ) ) ;
279- assert_eq ! ( " [ anon ]" , parse_filename( "anon_inode:i915.gem" ) ) ;
280- assert_eq ! ( " [ stack ]" , parse_filename( "[stack]" ) ) ;
281- assert_eq ! (
282- "ld-linux-x86-64.so.2" ,
283- parse_filename( "/usr/lib/ld-linux-x86-64.so.2" )
284- ) ;
285- }
286- }
0 commit comments