Skip to content

Commit 5cb72d5

Browse files
committed
pmap: add parser support for "offset" & "device"
1 parent a706ecb commit 5cb72d5

File tree

1 file changed

+54
-10
lines changed

1 file changed

+54
-10
lines changed

src/uu/pmap/src/maps_format_parser.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
use std::io::{Error, ErrorKind};
77

8-
// Represents a parsed single line from /proc/<PID>/maps.
8+
// Represents a parsed single line from /proc/<PID>/maps for the default and device formats. It
9+
// omits the inode information because it's not used by those formats.
910
#[derive(Debug, PartialEq)]
1011
pub struct MapLine {
1112
pub address: String,
1213
pub size_in_kb: u64,
1314
pub perms: String,
15+
pub offset: String,
16+
pub device: String,
1417
pub mapping: String,
1518
}
1619

@@ -32,14 +35,27 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
3235
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
3336
let perms = parse_perms(perms);
3437

35-
let mapping: String = rest.splitn(4, ' ').skip(3).collect();
38+
let (offset, rest) = rest
39+
.split_once(' ')
40+
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
41+
let offset = format!("{offset:0>16}");
42+
43+
let (device, rest) = rest
44+
.split_once(' ')
45+
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
46+
let device = parse_device(device)?;
47+
48+
// skip the "inode" column
49+
let mapping: String = rest.splitn(2, ' ').skip(1).collect();
3650
let mapping = mapping.trim_ascii_start();
3751
let mapping = parse_mapping(mapping);
3852

3953
Ok(MapLine {
4054
address,
4155
size_in_kb,
4256
perms,
57+
offset,
58+
device,
4359
mapping,
4460
})
4561
}
@@ -67,6 +83,14 @@ fn parse_perms(perms: &str) -> String {
6783
format!("{perms}-")
6884
}
6985

86+
// Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
87+
fn parse_device(device: &str) -> Result<String, Error> {
88+
let (major, minor) = device
89+
.split_once(':')
90+
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
91+
Ok(format!("{major:0>3}:{minor:0>5}"))
92+
}
93+
7094
fn parse_mapping(mapping: &str) -> String {
7195
if mapping == "[stack]" {
7296
return " [ stack ]".into();
@@ -86,11 +110,20 @@ fn parse_mapping(mapping: &str) -> String {
86110
mod test {
87111
use super::*;
88112

89-
fn create_map_line(address: &str, size_in_kb: u64, perms: &str, mapping: &str) -> MapLine {
113+
fn create_map_line(
114+
address: &str,
115+
size_in_kb: u64,
116+
perms: &str,
117+
offset: &str,
118+
device: &str,
119+
mapping: &str,
120+
) -> MapLine {
90121
MapLine {
91122
address: address.to_string(),
92123
size_in_kb,
93124
perms: perms.to_string(),
125+
offset: offset.to_string(),
126+
device: device.to_string(),
94127
mapping: mapping.to_string(),
95128
}
96129
}
@@ -99,31 +132,31 @@ mod test {
99132
fn test_parse_map_line() {
100133
let data = [
101134
(
102-
create_map_line("000062442eb9e000", 16, "r----", "konsole"),
135+
create_map_line("000062442eb9e000", 16, "r----", "0000000000000000", "008:00008", "konsole"),
103136
"62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
104137
),
105138
(
106-
create_map_line("000071af50000000", 132, "rw---", " [ anon ]"),
139+
create_map_line("000071af50000000", 132, "rw---", "0000000000000000", "000:00000", " [ anon ]"),
107140
"71af50000000-71af50021000 rw-p 00000000 00:00 0 "
108141
),
109142
(
110-
create_map_line("00007ffc3f8df000", 132, "rw---", " [ stack ]"),
143+
create_map_line("00007ffc3f8df000", 132, "rw---", "0000000000000000", "000:00000", " [ stack ]"),
111144
"7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
112145
),
113146
(
114-
create_map_line("000071af8c9e6000", 16, "rw-s-", " [ anon ]"),
147+
create_map_line("000071af8c9e6000", 16, "rw-s-", "0000000105830000", "000:00010", " [ anon ]"),
115148
"71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
116149
),
117150
(
118-
create_map_line("000071af6cf0c000", 3560, "rw-s-", "memfd:wayland-shm (deleted)"),
151+
create_map_line("000071af6cf0c000", 3560, "rw-s-", "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"),
119152
"71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
120153
),
121154
(
122-
create_map_line("ffffffffff600000", 4, "--x--", " [ anon ]"),
155+
create_map_line("ffffffffff600000", 4, "--x--", "0000000000000000", "000:00000", " [ anon ]"),
123156
"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
124157
),
125158
(
126-
create_map_line("00005e8187da8000", 24, "r----", "hello world"),
159+
create_map_line("00005e8187da8000", 24, "r----", "0000000000000000", "008:00008", "hello world"),
127160
"5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
128161
),
129162
];
@@ -167,6 +200,17 @@ mod test {
167200
assert_eq!("rwx--", parse_perms("rwxp"));
168201
}
169202

203+
#[test]
204+
fn test_parse_device() {
205+
assert_eq!("012:00034", parse_device("12:34").unwrap());
206+
assert_eq!("000:00000", parse_device("00:00").unwrap());
207+
}
208+
209+
#[test]
210+
fn test_parse_device_without_colon() {
211+
assert!(parse_device("1234").is_err());
212+
}
213+
170214
#[test]
171215
fn test_parse_mapping() {
172216
assert_eq!(" [ anon ]", parse_mapping(""));

0 commit comments

Comments
 (0)