Skip to content

Commit 6cdec94

Browse files
authored
pmap: implemented show-path option (#418)
* pmap: implemented show-path option * Fix CI failure caused by zip crate version upgrade * Revert the previous commit as the problem was solved upstream This reverts commit 9c2de67. * Refactored regexes in test pmap
1 parent 1dafe8d commit 6cdec94

4 files changed

Lines changed: 156 additions & 27 deletions

File tree

src/uu/pmap/src/maps_format_parser.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,13 @@ impl MapLine {
157157
}
158158
}
159159

160-
match self.mapping.rsplit_once('/') {
161-
Some((_, name)) => name.into(),
162-
None => self.mapping.clone(),
160+
if pmap_config.show_path {
161+
self.mapping.clone()
162+
} else {
163+
match self.mapping.rsplit_once('/') {
164+
Some((_, name)) => name.into(),
165+
None => self.mapping.clone(),
166+
}
163167
}
164168
}
165169
}
@@ -285,32 +289,68 @@ mod test {
285289

286290
mapline.mapping = "".to_string();
287291
pmap_config.custom_format_enabled = false;
292+
pmap_config.show_path = false;
293+
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
294+
pmap_config.show_path = true;
288295
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
289296
pmap_config.custom_format_enabled = true;
297+
pmap_config.show_path = false;
298+
assert_eq!("", mapline.parse_mapping(&pmap_config));
299+
pmap_config.show_path = true;
290300
assert_eq!("", mapline.parse_mapping(&pmap_config));
291301

292302
mapline.mapping = "[vvar]".to_string();
293303
pmap_config.custom_format_enabled = false;
304+
pmap_config.show_path = false;
305+
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
306+
pmap_config.show_path = true;
294307
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
295308
pmap_config.custom_format_enabled = true;
309+
pmap_config.show_path = false;
310+
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));
311+
pmap_config.show_path = true;
296312
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));
297313

298314
mapline.mapping = "anon_inode:i915.gem".to_string();
299315
pmap_config.custom_format_enabled = false;
316+
pmap_config.show_path = false;
317+
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
318+
pmap_config.show_path = true;
300319
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
301320
pmap_config.custom_format_enabled = true;
321+
pmap_config.show_path = false;
322+
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));
323+
pmap_config.show_path = true;
302324
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));
303325

304326
mapline.mapping = "[stack]".to_string();
305327
pmap_config.custom_format_enabled = false;
328+
pmap_config.show_path = false;
329+
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
330+
pmap_config.show_path = true;
306331
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
307332
pmap_config.custom_format_enabled = true;
333+
pmap_config.show_path = false;
334+
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));
335+
pmap_config.show_path = true;
308336
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));
309337

310338
mapline.mapping = "/usr/lib/ld-linux-x86-64.so.2".to_string();
311339
pmap_config.custom_format_enabled = false;
340+
pmap_config.show_path = false;
312341
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
342+
pmap_config.show_path = true;
343+
assert_eq!(
344+
"/usr/lib/ld-linux-x86-64.so.2",
345+
mapline.parse_mapping(&pmap_config)
346+
);
313347
pmap_config.custom_format_enabled = true;
348+
pmap_config.show_path = false;
314349
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
350+
pmap_config.show_path = true;
351+
assert_eq!(
352+
"/usr/lib/ld-linux-x86-64.so.2",
353+
mapline.parse_mapping(&pmap_config)
354+
);
315355
}
316356
}

src/uu/pmap/src/pmap.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4747
pmap_config.set_most_extended();
4848
}
4949

50+
// Options independent with field selection:
51+
if matches.get_flag(options::SHOW_PATH) {
52+
pmap_config.show_path = true;
53+
}
54+
5055
let pids = matches
5156
.get_many::<String>(options::PID)
5257
.expect("PID required");

src/uu/pmap/src/pmap_config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub struct PmapConfig {
7272
pub protection_key: bool,
7373
pub vmflags: bool,
7474
pub mapping: bool,
75+
// [Mapping] category
76+
pub show_path: bool,
7577
// Misc
7678
pub custom_format_enabled: bool,
7779
}

tests/by-util/test_pmap.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn test_existing_pid() {
3030
.succeeds()
3131
.stdout_move_str();
3232

33-
assert_format(pid, &result);
33+
assert_format(pid, &result, false);
3434
}
3535

3636
#[test]
@@ -50,8 +50,8 @@ fn test_multiple_existing_pids() {
5050
let pos_second_pid = result.iter().rposition(|line| re.is_match(line)).unwrap();
5151
let (left, right) = result.split_at(pos_second_pid);
5252

53-
assert_format(pid, &left.join("\n"));
54-
assert_format(pid, &right.join("\n"));
53+
assert_format(pid, &left.join("\n"), false);
54+
assert_format(pid, &right.join("\n"), false);
5555
}
5656

5757
#[test]
@@ -65,7 +65,7 @@ fn test_non_existing_and_existing_pid() {
6565
.fails();
6666
let result = result.code_is(42).no_stderr().stdout_str();
6767

68-
assert_format(pid, result);
68+
assert_format(pid, result, false);
6969
}
7070

7171
#[test]
@@ -103,7 +103,7 @@ fn test_extended() {
103103
.succeeds()
104104
.stdout_move_str();
105105

106-
assert_extended_format(pid, &result);
106+
assert_extended_format(pid, &result, false);
107107
}
108108
}
109109

@@ -119,7 +119,7 @@ fn test_more_extended() {
119119
.succeeds()
120120
.stdout_move_str();
121121

122-
assert_more_extended_format(pid, &result);
122+
assert_more_extended_format(pid, &result, false);
123123
}
124124

125125
#[test]
@@ -134,7 +134,7 @@ fn test_most_extended() {
134134
.succeeds()
135135
.stdout_move_str();
136136

137-
assert_most_extended_format(pid, &result);
137+
assert_most_extended_format(pid, &result, false);
138138
}
139139

140140
#[test]
@@ -166,7 +166,7 @@ fn test_device() {
166166
.succeeds()
167167
.stdout_move_str();
168168

169-
assert_device_format(pid, &result);
169+
assert_device_format(pid, &result, false);
170170
}
171171
}
172172

@@ -187,6 +187,63 @@ fn test_device_permission_denied() {
187187
}
188188
}
189189

190+
#[test]
191+
#[cfg(target_os = "linux")]
192+
fn test_showpath() {
193+
let pid = process::id();
194+
195+
for arg in ["-p", "--show-path"] {
196+
// default format
197+
let result = new_ucmd!()
198+
.arg(arg)
199+
.arg(pid.to_string())
200+
.succeeds()
201+
.stdout_move_str();
202+
203+
assert_format(pid, &result, true);
204+
205+
// extended format
206+
let result = new_ucmd!()
207+
.arg(arg)
208+
.arg("--extended")
209+
.arg(pid.to_string())
210+
.succeeds()
211+
.stdout_move_str();
212+
213+
assert_extended_format(pid, &result, true);
214+
215+
// more-extended format
216+
let result = new_ucmd!()
217+
.arg(arg)
218+
.arg("-X")
219+
.arg(pid.to_string())
220+
.succeeds()
221+
.stdout_move_str();
222+
223+
assert_more_extended_format(pid, &result, true);
224+
225+
// most-extended format
226+
let result = new_ucmd!()
227+
.arg(arg)
228+
.arg("--XX")
229+
.arg(pid.to_string())
230+
.succeeds()
231+
.stdout_move_str();
232+
233+
assert_most_extended_format(pid, &result, true);
234+
235+
// device format
236+
let result = new_ucmd!()
237+
.arg(arg)
238+
.arg("--device")
239+
.arg(pid.to_string())
240+
.succeeds()
241+
.stdout_move_str();
242+
243+
assert_device_format(pid, &result, true);
244+
}
245+
}
246+
190247
#[test]
191248
fn test_invalid_arg() {
192249
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
@@ -211,14 +268,20 @@ fn assert_cmdline_only(pid: &str, s: &str) {
211268
// ...
212269
// total 1040320K
213270
#[cfg(target_os = "linux")]
214-
fn assert_format(pid: u32, s: &str) {
271+
fn assert_format(pid: u32, s: &str, show_path: bool) {
215272
let (first_line, rest) = s.split_once('\n').unwrap();
216273
let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
217274
assert!(re.is_match(first_line));
218275

219276
let rest = rest.trim_end();
220277
let (memory_map, last_line) = rest.rsplit_once('\n').unwrap();
221-
let re = Regex::new(r"(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)- ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$").unwrap();
278+
let base_pattern = r"(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)-";
279+
let mapping_pattern = if show_path {
280+
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
281+
} else {
282+
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
283+
};
284+
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
222285
assert!(re.is_match(memory_map));
223286

224287
let re = Regex::new("^ total +[1-9][0-9]*K$").unwrap();
@@ -236,7 +299,7 @@ fn assert_format(pid: u32, s: &str) {
236299
// ---------------- ------- ------- ------- (one intentional trailing space)
237300
// total kB 144 7 14
238301
#[cfg(target_os = "linux")]
239-
fn assert_extended_format(pid: u32, s: &str) {
302+
fn assert_extended_format(pid: u32, s: &str, show_path: bool) {
240303
let lines: Vec<_> = s.lines().collect();
241304
let line_count = lines.len();
242305

@@ -246,10 +309,13 @@ fn assert_extended_format(pid: u32, s: &str) {
246309
let expected_header = "Address Kbytes RSS Dirty Mode Mapping";
247310
assert_eq!(expected_header, lines[1], "failing line: '{}'", lines[1]);
248311

249-
let re = Regex::new(
250-
r"^[0-9a-f]{16} +[1-9][0-9]* +\d+ +\d+ (-|r)(-|w)(-|x)(-|s)- ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$",
251-
)
252-
.unwrap();
312+
let base_pattern = r"^[0-9a-f]{16} +[1-9][0-9]* +\d+ +\d+ (-|r)(-|w)(-|x)(-|s)-";
313+
let mapping_pattern = if show_path {
314+
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
315+
} else {
316+
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
317+
};
318+
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
253319

254320
for line in lines.iter().take(line_count - 2).skip(2) {
255321
assert!(re.is_match(line), "failing line: '{line}'");
@@ -282,7 +348,7 @@ fn assert_extended_format(pid: u32, s: &str) {
282348
// ==== ==== ==== ========= ========== ========= ======== ============== ============= ============== =============== ==== ======= ====== =========== (one intentional trailing space)
283349
// 4164 3448 2826 552 3448 552 0 0 0 0 0 0 0 0 0 KB (one intentional trailing space)
284350
#[cfg(target_os = "linux")]
285-
fn assert_more_extended_format(pid: u32, s: &str) {
351+
fn assert_more_extended_format(pid: u32, s: &str, show_path: bool) {
286352
let lines: Vec<_> = s.lines().collect();
287353
let line_count = lines.len();
288354

@@ -292,7 +358,13 @@ fn assert_more_extended_format(pid: u32, s: &str) {
292358
let re = Regex::new(r"^ Address Perm Offset Device Inode +Size +Rss +Pss +Pss_Dirty +Referenced +Anonymous( +KSM)? +LazyFree +ShmemPmdMapped +FilePmdMapped +Shared_Hugetlb +Private_Hugetlb +Swap +SwapPss +Locked +THPeligible( +ProtectionKey)? +Mapping$").unwrap();
293359
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);
294360

295-
let re = Regex::new(r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? (|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$").unwrap();
361+
let base_pattern = r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)?";
362+
let mapping_pattern = if show_path {
363+
r" (|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
364+
} else {
365+
r" (|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
366+
};
367+
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
296368

297369
for line in lines.iter().take(line_count - 2).skip(2) {
298370
assert!(re.is_match(line), "failing line: '{line}'");
@@ -324,7 +396,7 @@ fn assert_more_extended_format(pid: u32, s: &str) {
324396
// ==== ============== =========== ==== ==== ========= ============ ============ ============= ============= ========== ========= ======== ============= ============== ============= ============== =============== ==== ======= ====== =========== (one intentional trailing space)
325397
// 4164 92 92 3448 2880 552 1132 0 1764 552 3448 552 0 0 0 0 0 0 0 0 0 0 KB (one intentional trailing space)
326398
#[cfg(target_os = "linux")]
327-
fn assert_most_extended_format(pid: u32, s: &str) {
399+
fn assert_most_extended_format(pid: u32, s: &str, show_path: bool) {
328400
let lines: Vec<_> = s.lines().collect();
329401
let line_count = lines.len();
330402

@@ -334,7 +406,13 @@ fn assert_most_extended_format(pid: u32, s: &str) {
334406
let re = Regex::new(r"^ Address Perm Offset Device Inode +Size +KernelPageSize +MMUPageSize +Rss +Pss +Pss_Dirty +Shared_Clean +Shared_Dirty +Private_Clean +Private_Dirty +Referenced +Anonymous( +KSM)? +LazyFree +AnonHugePages +ShmemPmdMapped +FilePmdMapped +Shared_Hugetlb +Private_Hugetlb +Swap +SwapPss +Locked +THPeligible( +ProtectionKey)? +VmFlags +Mapping$").unwrap();
335407
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);
336408

337-
let re = Regex::new(r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +([a-z][a-z] )*(|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$").unwrap();
409+
let base_pattern = r"^[0-9a-f]{16} (-|r)(-|w)(-|x)(p|s) [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} +\d+ +[1-9][0-9]* +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+( +\d+)? +([a-z][a-z] )*";
410+
let mapping_pattern = if show_path {
411+
r"(|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
412+
} else {
413+
r"(|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
414+
};
415+
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
338416

339417
for line in lines.iter().take(line_count - 2).skip(2) {
340418
assert!(re.is_match(line), "failing line: '{line}'");
@@ -365,7 +443,7 @@ fn assert_most_extended_format(pid: u32, s: &str) {
365443
// ...
366444
// mapped: 3060K writeable/private: 348K shared: 0K
367445
#[cfg(target_os = "linux")]
368-
fn assert_device_format(pid: u32, s: &str) {
446+
fn assert_device_format(pid: u32, s: &str, show_path: bool) {
369447
let lines: Vec<_> = s.lines().collect();
370448
let line_count = lines.len();
371449

@@ -375,10 +453,14 @@ fn assert_device_format(pid: u32, s: &str) {
375453
let expected_header = "Address Kbytes Mode Offset Device Mapping";
376454
assert_eq!(expected_header, lines[1]);
377455

378-
let re = Regex::new(
379-
r"^[0-9a-f]{16} +[1-9][0-9]* (-|r)(-|w)(-|x)(-|s)- [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5} ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$",
380-
)
381-
.unwrap();
456+
let base_pattern =
457+
r"^[0-9a-f]{16} +[1-9][0-9]* (-|r)(-|w)(-|x)(-|s)- [0-9a-f]{16} [0-9a-f]{3}:[0-9a-f]{5}";
458+
let mapping_pattern = if show_path {
459+
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
460+
} else {
461+
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
462+
};
463+
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
382464

383465
for line in lines.iter().take(line_count - 1).skip(2) {
384466
assert!(re.is_match(line), "failing line: {line}");

0 commit comments

Comments
 (0)