Skip to content

Commit

Permalink
pmap: use Perms struct instead of String for perms
Browse files Browse the repository at this point in the history
  • Loading branch information
cakebaker committed Oct 9, 2024
1 parent 93a02fa commit 7ab7635
Showing 1 changed file with 58 additions and 27 deletions.
85 changes: 58 additions & 27 deletions src/uu/pmap/src/maps_format_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,66 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use std::fmt;

// Represents a parsed single line from /proc/<PID>/maps for the default and device formats. It
// omits the inode information because it's not used by those formats.
#[derive(Debug, PartialEq)]
pub struct MapLine {
pub address: String,
pub size_in_kb: u64,
pub perms: String,
pub perms: Perms,
pub offset: String,
pub device: String,
pub mapping: String,
}

// Represents a set of permissions from the "perms" column of /proc/<PID>/maps.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Perms {
pub readable: bool,
pub writable: bool,
pub executable: bool,
pub shared: bool,
}

impl From<&str> for Perms {
fn from(s: &str) -> Self {
let mut chars = s.chars();

Self {
readable: chars.next() == Some('r'),
writable: chars.next() == Some('w'),
executable: chars.next() == Some('x'),
shared: chars.next() == Some('s'),
}
}
}

// Please note: While `Perms` has four boolean fields, it's string representation has five
// characters because pmap's default and device formats use five characters for the perms,
// with the last character always being '-'.
impl fmt::Display for Perms {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}{}{}{}-",
if self.readable { 'r' } else { '-' },
if self.writable { 'w' } else { '-' },
if self.executable { 'x' } else { '-' },
if self.shared { 's' } else { '-' },
)
}
}

// Parses a single line from /proc/<PID>/maps. It assumes the format of `line` is correct (see
// https://www.kernel.org/doc/html/latest/filesystems/proc.html for details).
pub fn parse_map_line(line: &str) -> MapLine {
let (memory_range, rest) = line.split_once(' ').expect("line should contain ' '");
let (address, size_in_kb) = parse_address(memory_range);

let (perms, rest) = rest.split_once(' ').expect("line should contain 2nd ' '");
let perms = parse_perms(perms);
let perms = Perms::from(perms);

let (offset, rest) = rest.split_once(' ').expect("line should contain 3rd ' '");
let offset = format!("{offset:0>16}");
Expand Down Expand Up @@ -59,15 +99,6 @@ fn parse_address(memory_range: &str) -> (String, u64) {
(format!("{start:0>16}"), size_in_kb)
}

// Turns a 4-char perms string from /proc/<PID>/maps into a 5-char perms string. The first three
// chars are left untouched.
fn parse_perms(perms: &str) -> String {
let perms = perms.replace("p", "-");

// the fifth char seems to be always '-' in the original pmap
format!("{perms}-")
}

// Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
fn parse_device(device: &str) -> String {
if let Some((major, minor)) = device.split_once(':') {
Expand Down Expand Up @@ -99,50 +130,57 @@ mod test {
fn create_map_line(
address: &str,
size_in_kb: u64,
perms: &str,
perms: Perms,
offset: &str,
device: &str,
mapping: &str,
) -> MapLine {
MapLine {
address: address.to_string(),
size_in_kb,
perms: perms.to_string(),
perms,
offset: offset.to_string(),
device: device.to_string(),
mapping: mapping.to_string(),
}
}

#[test]
fn test_perms_to_string() {
assert_eq!("-----", Perms::from("---p").to_string());
assert_eq!("---s-", Perms::from("---s").to_string());
assert_eq!("rwx--", Perms::from("rwxp").to_string());
}

#[test]
fn test_parse_map_line() {
let data = [
(
create_map_line("000062442eb9e000", 16, "r----", "0000000000000000", "008:00008", "konsole"),
create_map_line("000062442eb9e000", 16, Perms::from("r--p"), "0000000000000000", "008:00008", "konsole"),
"62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
),
(
create_map_line("000071af50000000", 132, "rw---", "0000000000000000", "000:00000", " [ anon ]"),
create_map_line("000071af50000000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", " [ anon ]"),
"71af50000000-71af50021000 rw-p 00000000 00:00 0 "
),
(
create_map_line("00007ffc3f8df000", 132, "rw---", "0000000000000000", "000:00000", " [ stack ]"),
create_map_line("00007ffc3f8df000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", " [ stack ]"),
"7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
),
(
create_map_line("000071af8c9e6000", 16, "rw-s-", "0000000105830000", "000:00010", " [ anon ]"),
create_map_line("000071af8c9e6000", 16, Perms::from("rw-s"), "0000000105830000", "000:00010", " [ anon ]"),
"71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
),
(
create_map_line("000071af6cf0c000", 3560, "rw-s-", "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"),
create_map_line("000071af6cf0c000", 3560, Perms::from("rw-s"), "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"),
"71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
),
(
create_map_line("ffffffffff600000", 4, "--x--", "0000000000000000", "000:00000", " [ anon ]"),
create_map_line("ffffffffff600000", 4, Perms::from("--xp"), "0000000000000000", "000:00000", " [ anon ]"),
"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
),
(
create_map_line("00005e8187da8000", 24, "r----", "0000000000000000", "008:00008", "hello world"),
create_map_line("00005e8187da8000", 24, Perms::from("r--p"), "0000000000000000", "008:00008", "hello world"),
"5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
),
];
Expand All @@ -163,13 +201,6 @@ mod test {
assert_eq!(size, 132);
}

#[test]
fn test_parse_perms() {
assert_eq!("-----", parse_perms("---p"));
assert_eq!("---s-", parse_perms("---s"));
assert_eq!("rwx--", parse_perms("rwxp"));
}

#[test]
fn test_parse_device() {
assert_eq!("012:00034", parse_device("12:34"));
Expand Down

0 comments on commit 7ab7635

Please sign in to comment.