Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions src/uu/pmap/src/maps_format_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,13 @@ impl MapLine {
}
}

match self.mapping.rsplit_once('/') {
Some((_, name)) => name.into(),
None => self.mapping.clone(),
if pmap_config.show_path {
self.mapping.clone()
} else {
match self.mapping.rsplit_once('/') {
Some((_, name)) => name.into(),
None => self.mapping.clone(),
}
}
}
}
Expand Down Expand Up @@ -285,32 +289,68 @@ mod test {

mapline.mapping = "".to_string();
pmap_config.custom_format_enabled = false;
pmap_config.show_path = false;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.custom_format_enabled = true;
pmap_config.show_path = false;
assert_eq!("", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!("", mapline.parse_mapping(&pmap_config));

mapline.mapping = "[vvar]".to_string();
pmap_config.custom_format_enabled = false;
pmap_config.show_path = false;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.custom_format_enabled = true;
pmap_config.show_path = false;
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!("[vvar]", mapline.parse_mapping(&pmap_config));

mapline.mapping = "anon_inode:i915.gem".to_string();
pmap_config.custom_format_enabled = false;
pmap_config.show_path = false;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(" [ anon ]", mapline.parse_mapping(&pmap_config));
pmap_config.custom_format_enabled = true;
pmap_config.show_path = false;
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!("anon_inode:i915.gem", mapline.parse_mapping(&pmap_config));

mapline.mapping = "[stack]".to_string();
pmap_config.custom_format_enabled = false;
pmap_config.show_path = false;
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(" [ stack ]", mapline.parse_mapping(&pmap_config));
pmap_config.custom_format_enabled = true;
pmap_config.show_path = false;
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!("[stack]", mapline.parse_mapping(&pmap_config));

mapline.mapping = "/usr/lib/ld-linux-x86-64.so.2".to_string();
pmap_config.custom_format_enabled = false;
pmap_config.show_path = false;
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(
"/usr/lib/ld-linux-x86-64.so.2",
mapline.parse_mapping(&pmap_config)
);
pmap_config.custom_format_enabled = true;
pmap_config.show_path = false;
assert_eq!("ld-linux-x86-64.so.2", mapline.parse_mapping(&pmap_config));
pmap_config.show_path = true;
assert_eq!(
"/usr/lib/ld-linux-x86-64.so.2",
mapline.parse_mapping(&pmap_config)
);
}
}
5 changes: 5 additions & 0 deletions src/uu/pmap/src/pmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pmap_config.set_most_extended();
}

// Options independent with field selection:
if matches.get_flag(options::SHOW_PATH) {
pmap_config.show_path = true;
}

let pids = matches
.get_many::<String>(options::PID)
.expect("PID required");
Expand Down
2 changes: 2 additions & 0 deletions src/uu/pmap/src/pmap_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub struct PmapConfig {
pub protection_key: bool,
pub vmflags: bool,
pub mapping: bool,
// [Mapping] category
pub show_path: bool,
// Misc
pub custom_format_enabled: bool,
}
Expand Down
130 changes: 106 additions & 24 deletions tests/by-util/test_pmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn test_existing_pid() {
.succeeds()
.stdout_move_str();

assert_format(pid, &result);
assert_format(pid, &result, false);
}

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

assert_format(pid, &left.join("\n"));
assert_format(pid, &right.join("\n"));
assert_format(pid, &left.join("\n"), false);
assert_format(pid, &right.join("\n"), false);
}

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

assert_format(pid, result);
assert_format(pid, result, false);
}

#[test]
Expand Down Expand Up @@ -103,7 +103,7 @@ fn test_extended() {
.succeeds()
.stdout_move_str();

assert_extended_format(pid, &result);
assert_extended_format(pid, &result, false);
}
}

Expand All @@ -119,7 +119,7 @@ fn test_more_extended() {
.succeeds()
.stdout_move_str();

assert_more_extended_format(pid, &result);
assert_more_extended_format(pid, &result, false);
}

#[test]
Expand All @@ -134,7 +134,7 @@ fn test_most_extended() {
.succeeds()
.stdout_move_str();

assert_most_extended_format(pid, &result);
assert_most_extended_format(pid, &result, false);
}

#[test]
Expand Down Expand Up @@ -166,7 +166,7 @@ fn test_device() {
.succeeds()
.stdout_move_str();

assert_device_format(pid, &result);
assert_device_format(pid, &result, false);
}
}

Expand All @@ -187,6 +187,63 @@ fn test_device_permission_denied() {
}
}

#[test]
#[cfg(target_os = "linux")]
fn test_showpath() {
let pid = process::id();

for arg in ["-p", "--show-path"] {
// default format
let result = new_ucmd!()
.arg(arg)
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_format(pid, &result, true);

// extended format
let result = new_ucmd!()
.arg(arg)
.arg("--extended")
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_extended_format(pid, &result, true);

// more-extended format
let result = new_ucmd!()
.arg(arg)
.arg("-X")
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_more_extended_format(pid, &result, true);

// most-extended format
let result = new_ucmd!()
.arg(arg)
.arg("--XX")
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_most_extended_format(pid, &result, true);

// device format
let result = new_ucmd!()
.arg(arg)
.arg("--device")
.arg(pid.to_string())
.succeeds()
.stdout_move_str();

assert_device_format(pid, &result, true);
}
}

#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
Expand All @@ -211,14 +268,20 @@ fn assert_cmdline_only(pid: &str, s: &str) {
// ...
// total 1040320K
#[cfg(target_os = "linux")]
fn assert_format(pid: u32, s: &str) {
fn assert_format(pid: u32, s: &str, show_path: bool) {
let (first_line, rest) = s.split_once('\n').unwrap();
let re = Regex::new(&format!("^{pid}: .+[^ ]$")).unwrap();
assert!(re.is_match(first_line));

let rest = rest.trim_end();
let (memory_map, last_line) = rest.rsplit_once('\n').unwrap();
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();
let base_pattern = r"(?m)^[0-9a-f]{16} +[1-9][0-9]*K (-|r)(-|w)(-|x)(-|s)-";
let mapping_pattern = if show_path {
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
} else {
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
};
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();
assert!(re.is_match(memory_map));

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

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

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

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

Expand All @@ -292,7 +358,13 @@ fn assert_more_extended_format(pid: u32, s: &str) {
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();
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);

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();
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+)?";
let mapping_pattern = if show_path {
r" (|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
} else {
r" (|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
};
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();

for line in lines.iter().take(line_count - 2).skip(2) {
assert!(re.is_match(line), "failing line: '{line}'");
Expand Down Expand Up @@ -324,7 +396,7 @@ fn assert_more_extended_format(pid: u32, s: &str) {
// ==== ============== =========== ==== ==== ========= ============ ============ ============= ============= ========== ========= ======== ============= ============== ============= ============== =============== ==== ======= ====== =========== (one intentional trailing space)
// 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)
#[cfg(target_os = "linux")]
fn assert_most_extended_format(pid: u32, s: &str) {
fn assert_most_extended_format(pid: u32, s: &str, show_path: bool) {
let lines: Vec<_> = s.lines().collect();
let line_count = lines.len();

Expand All @@ -334,7 +406,13 @@ fn assert_most_extended_format(pid: u32, s: &str) {
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();
assert!(re.is_match(lines[1]), "failing line: '{}'", lines[1]);

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();
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] )*";
let mapping_pattern = if show_path {
r"(|\[[a-zA-Z_ ]+\]|/[/a-zA-Z0-9._-]+)$"
} else {
r"(|\[[a-zA-Z_ ]+\]|[a-zA-Z0-9._-]+)$"
};
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();

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

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

let re = Regex::new(
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._-]+)$",
)
.unwrap();
let base_pattern =
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}";
let mapping_pattern = if show_path {
r" ( \[ (anon|stack) \]|/[/a-zA-Z0-9._-]+)$"
} else {
r" ( \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$"
};
let re = Regex::new(&format!("{base_pattern}{mapping_pattern}")).unwrap();

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