Repository: uutils/procps
Pull request #195 (2024-08-20 14:48:51)

pmap: add size column
This PR adds a new column to the output that shows the memory size when running `cargo run pmap <some PID>`. 

Before the change:
```
00007740f1b9a000 rw-p 00036000 08:08 10773308                   /usr/lib/ld-linux-x86-64.so.2
```
After the change:
```
00007740f1b9a000      8K rw-p 00036000 08:08 10773308                   /usr/lib/ld-linux-x86-64.so.2
```
In comparison, the output of the original `pmap`:
```
00007740f1b9a000      8K rw--- ld-linux-x86-64.so.2
```


Patch:
diff --git a/src/uu/pmap/src/pmap.rs b/src/uu/pmap/src/pmap.rs
index d43a4e2..b720e3a 100644
--- a/src/uu/pmap/src/pmap.rs
+++ b/src/uu/pmap/src/pmap.rs
@@ -57,15 +57,31 @@ fn parse_maps(pid: &str) -> Result<(), Error> {
 
     for line in contents.lines() {
         let (memory_range, rest) = line.split_once(' ').expect("line should contain ' '");
-        let (start, _) = memory_range
-            .split_once('-')
-            .expect("memory range should contain '-'");
-        println!("{start:0>16} {rest}");
+        let (start_address, size_in_kb) = parse_memory_range(memory_range);
+
+        println!("{start_address} {size_in_kb:>6}K {rest}");
     }
 
     Ok(())
 }
 
+// Returns the start address and the size of the provided memory range. The start address is always
+// 16-digits and padded with 0, if necessary. The size is in KB.
+//
+// This function assumes the provided `memory_range` comes from /proc/<PID>/maps and thus its
+// format is correct.
+fn parse_memory_range(memory_range: &str) -> (String, u64) {
+    let (start, end) = memory_range
+        .split_once('-')
+        .expect("memory range should contain '-'");
+
+    let low = u64::from_str_radix(start, 16).expect("should be a hex value");
+    let high = u64::from_str_radix(end, 16).expect("should be a hex value");
+    let size_in_kb = (high - low) / 1024;
+
+    (format!("{start:0>16}"), size_in_kb)
+}
+
 pub fn uu_app() -> Command {
     Command::new(env!("CARGO_PKG_NAME"))
         .version(crate_version!())
@@ -147,3 +163,19 @@ pub fn uu_app() -> Command {
                 .help("limit results to the given range"),
         )
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_parse_memory_range() {
+        let (start, size) = parse_memory_range("ffffffffff600000-ffffffffff601000");
+        assert_eq!(start, "ffffffffff600000");
+        assert_eq!(size, 4);
+
+        let (start, size) = parse_memory_range("7ffc4f0c2000-7ffc4f0e3000");
+        assert_eq!(start, "00007ffc4f0c2000");
+        assert_eq!(size, 132);
+    }
+}


Test patch:
diff --git a/tests/by-util/test_pmap.rs b/tests/by-util/test_pmap.rs
index f1915ba..451957c 100644
--- a/tests/by-util/test_pmap.rs
+++ b/tests/by-util/test_pmap.rs
@@ -30,7 +30,7 @@ fn test_existing_pid() {
 
     let rest = rest.trim_end();
     let (memory_map, last_line) = rest.rsplit_once('\n').unwrap();
-    let re = Regex::new("(?m)^[0-9a-f]{16} ").unwrap();
+    let re = Regex::new("(?m)^[0-9a-f]{16} +[1-9][0-9]*K ").unwrap();
     assert!(re.is_match(memory_map));
     // TODO ensure that "total" is followed by a total amount
     assert!(last_line.starts_with(" total"));