Skip to content

Commit 8f14e7b

Browse files
authored
pmap: fixed padding of Address, Offset, and Device fields (#458)
* pmap: fixed padding of Address, Offset, and Device fields * pmap: fixed tests for more and most extended formats
1 parent e6261fa commit 8f14e7b

File tree

4 files changed

+172
-71
lines changed

4 files changed

+172
-71
lines changed

src/uu/pmap/src/maps_format_parser.rs

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,37 @@ use std::io::{Error, ErrorKind};
1010
// Represents a parsed single line from /proc/<PID>/maps.
1111
#[derive(Debug, Clone, Default, PartialEq)]
1212
pub struct MapLine {
13-
pub address: String,
13+
pub address: Address,
1414
pub size_in_kb: u64,
1515
pub perms: Perms,
1616
pub offset: String,
17-
pub device: String,
17+
pub device: Device,
1818
pub inode: u64,
1919
pub mapping: String,
2020
}
2121

22+
#[derive(Debug, Clone, Default, PartialEq)]
23+
pub struct Address {
24+
pub start: String,
25+
pub low: u64,
26+
pub high: u64,
27+
}
28+
29+
impl fmt::Display for Address {
30+
// By default, pads with white spaces.
31+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32+
write!(f, "{: >16}", self.start)
33+
}
34+
}
35+
36+
impl Address {
37+
// Format for default, extended option, and device option.
38+
// Pads the start address with zero.
39+
pub fn zero_pad(&self) -> String {
40+
format!("{:0>16}", self.start)
41+
}
42+
}
43+
2244
// Represents a set of permissions from the "perms" column of /proc/<PID>/maps.
2345
#[derive(Clone, Copy, Debug, Default, PartialEq)]
2446
pub struct Perms {
@@ -69,6 +91,28 @@ impl Perms {
6991
}
7092
}
7193

94+
#[derive(Debug, Clone, Default, PartialEq)]
95+
pub struct Device {
96+
pub major: String,
97+
pub minor: String,
98+
pub width: usize,
99+
}
100+
101+
impl fmt::Display for Device {
102+
// By default, does not pad.
103+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104+
write!(f, "{}:{}", self.major, self.minor)
105+
}
106+
}
107+
108+
impl Device {
109+
// Format for device option.
110+
// Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
111+
pub fn device(&self) -> String {
112+
format!("{:0>3}:{:0>5}", self.major, self.minor)
113+
}
114+
}
115+
72116
// Parses a single line from /proc/<PID>/maps. See
73117
// https://www.kernel.org/doc/html/latest/filesystems/proc.html for details about the expected
74118
// format.
@@ -90,7 +134,7 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
90134
let (offset, rest) = rest
91135
.split_once(' ')
92136
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
93-
let offset = format!("{offset:0>16}");
137+
let offset = format!("{offset:0>8}");
94138

95139
let (device, rest) = rest
96140
.split_once(' ')
@@ -116,9 +160,8 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
116160
})
117161
}
118162

119-
// Returns the start address and the size of the provided memory range. The start address is always
120-
// 16-digits and padded with 0, if necessary. The size is in KB.
121-
fn parse_address(memory_range: &str) -> Result<(String, u64), Error> {
163+
// Returns Address instance and the size of the provided memory range. The size is in KB.
164+
fn parse_address(memory_range: &str) -> Result<(Address, u64), Error> {
122165
let (start, end) = memory_range
123166
.split_once('-')
124167
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
@@ -127,15 +170,26 @@ fn parse_address(memory_range: &str) -> Result<(String, u64), Error> {
127170
let high = u64::from_str_radix(end, 16).map_err(|_| Error::from(ErrorKind::InvalidData))?;
128171
let size_in_kb = (high - low) / 1024;
129172

130-
Ok((format!("{start:0>16}"), size_in_kb))
173+
Ok((
174+
Address {
175+
start: start.to_string(),
176+
low,
177+
high,
178+
},
179+
size_in_kb,
180+
))
131181
}
132182

133-
// Pads the device info from /proc/<PID>/maps with zeros and turns AB:CD into 0AB:000CD.
134-
fn parse_device(device: &str) -> Result<String, Error> {
183+
// Returns Device instance.
184+
fn parse_device(device: &str) -> Result<Device, Error> {
135185
let (major, minor) = device
136186
.split_once(':')
137187
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
138-
Ok(format!("{major:0>3}:{minor:0>5}"))
188+
Ok(Device {
189+
major: major.to_string(),
190+
minor: minor.to_string(),
191+
width: device.len(),
192+
})
139193
}
140194

141195
impl MapLine {
@@ -174,19 +228,31 @@ mod test {
174228

175229
fn create_map_line(
176230
address: &str,
231+
low: u64,
232+
high: u64,
177233
size_in_kb: u64,
178234
perms: Perms,
179235
offset: &str,
180-
device: &str,
236+
major: &str,
237+
minor: &str,
238+
width: usize,
181239
inode: u64,
182240
mapping: &str,
183241
) -> MapLine {
184242
MapLine {
185-
address: address.to_string(),
243+
address: Address {
244+
start: address.to_string(),
245+
low,
246+
high,
247+
},
186248
size_in_kb,
187249
perms,
188250
offset: offset.to_string(),
189-
device: device.to_string(),
251+
device: Device {
252+
major: major.to_string(),
253+
minor: minor.to_string(),
254+
width,
255+
},
190256
inode,
191257
mapping: mapping.to_string(),
192258
}
@@ -210,31 +276,31 @@ mod test {
210276
fn test_parse_map_line() {
211277
let data = [
212278
(
213-
create_map_line("000062442eb9e000", 16, Perms::from("r--p"), "0000000000000000", "008:00008", 10813151, "/usr/bin/konsole"),
279+
create_map_line("62442eb9e000", 0x62442eb9e000, 0x62442eba2000, 16, Perms::from("r--p"), "00000000", "08", "08", 5, 10813151, "/usr/bin/konsole"),
214280
"62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151 /usr/bin/konsole"
215281
),
216282
(
217-
create_map_line("000071af50000000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", 0, ""),
283+
create_map_line("71af50000000", 0x71af50000000, 0x71af50021000, 132, Perms::from("rw-p"), "00000000", "00", "00", 5, 0, ""),
218284
"71af50000000-71af50021000 rw-p 00000000 00:00 0 "
219285
),
220286
(
221-
create_map_line("00007ffc3f8df000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", 0, "[stack]"),
287+
create_map_line("7ffc3f8df000", 0x7ffc3f8df000, 0x7ffc3f900000, 132, Perms::from("rw-p"), "00000000", "00", "00", 5, 0, "[stack]"),
222288
"7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0 [stack]"
223289
),
224290
(
225-
create_map_line("000071af8c9e6000", 16, Perms::from("rw-s"), "0000000105830000", "000:00010", 1075, "anon_inode:i915.gem"),
291+
create_map_line("71af8c9e6000", 0x71af8c9e6000, 0x71af8c9ea000, 16, Perms::from("rw-s"), "105830000", "00", "10", 5, 1075, "anon_inode:i915.gem"),
226292
"71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075 anon_inode:i915.gem"
227293
),
228294
(
229-
create_map_line("000071af6cf0c000", 3560, Perms::from("rw-s"), "0000000000000000", "000:00001", 256481, "/memfd:wayland-shm (deleted)"),
295+
create_map_line("71af6cf0c000", 0x71af6cf0c000, 0x71af6d286000, 3560, Perms::from("rw-s"), "00000000", "00", "01", 5, 256481, "/memfd:wayland-shm (deleted)"),
230296
"71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481 /memfd:wayland-shm (deleted)"
231297
),
232298
(
233-
create_map_line("ffffffffff600000", 4, Perms::from("--xp"), "0000000000000000", "000:00000", 0, "[vsyscall]"),
299+
create_map_line("ffffffffff600000", 0xffffffffff600000, 0xffffffffff601000, 4, Perms::from("--xp"), "00000000", "00", "00", 5, 0, "[vsyscall]"),
234300
"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
235301
),
236302
(
237-
create_map_line("00005e8187da8000", 24, Perms::from("r--p"), "0000000000000000", "008:00008", 9524160, "/usr/bin/hello world"),
303+
create_map_line("5e8187da8000", 0x5e8187da8000, 0x5e8187dae000, 24, Perms::from("r--p"), "00000000", "08", "08", 5, 9524160, "/usr/bin/hello world"),
238304
"5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160 /usr/bin/hello world"
239305
),
240306
];
@@ -251,12 +317,16 @@ mod test {
251317

252318
#[test]
253319
fn test_parse_address() {
254-
let (start, size) = parse_address("ffffffffff600000-ffffffffff601000").unwrap();
255-
assert_eq!(start, "ffffffffff600000");
320+
let (address, size) = parse_address("ffffffffff600000-ffffffffff601000").unwrap();
321+
assert_eq!(address.start, "ffffffffff600000");
322+
assert_eq!(address.low, 0xffffffffff600000);
323+
assert_eq!(address.high, 0xffffffffff601000);
256324
assert_eq!(size, 4);
257325

258-
let (start, size) = parse_address("7ffc4f0c2000-7ffc4f0e3000").unwrap();
259-
assert_eq!(start, "00007ffc4f0c2000");
326+
let (address, size) = parse_address("7ffc4f0c2000-7ffc4f0e3000").unwrap();
327+
assert_eq!(address.start, "7ffc4f0c2000");
328+
assert_eq!(address.low, 0x7ffc4f0c2000);
329+
assert_eq!(address.high, 0x7ffc4f0e3000);
260330
assert_eq!(size, 132);
261331
}
262332

@@ -273,8 +343,15 @@ mod test {
273343

274344
#[test]
275345
fn test_parse_device() {
276-
assert_eq!("012:00034", parse_device("12:34").unwrap());
277-
assert_eq!("000:00000", parse_device("00:00").unwrap());
346+
assert_eq!("12:34", parse_device("12:34").unwrap().to_string());
347+
assert_eq!("00:00", parse_device("00:00").unwrap().to_string());
348+
assert_eq!("fe:01", parse_device("fe:01").unwrap().to_string());
349+
assert_eq!("103:100", parse_device("103:100").unwrap().to_string());
350+
351+
assert_eq!("012:00034", parse_device("12:34").unwrap().device());
352+
assert_eq!("000:00000", parse_device("00:00").unwrap().device());
353+
assert_eq!("0fe:00001", parse_device("fe:01").unwrap().device());
354+
assert_eq!("103:00100", parse_device("103:100").unwrap().device());
278355
}
279356

280357
#[test]

src/uu/pmap/src/pmap.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ fn output_default_format(pid: &str, pmap_config: &PmapConfig) -> Result<(), Erro
184184
process_maps(pid, None, |map_line| {
185185
println!(
186186
"{} {:>6}K {} {}",
187-
map_line.address,
187+
map_line.address.zero_pad(),
188188
map_line.size_in_kb,
189189
map_line.perms.mode(),
190190
map_line.parse_mapping(pmap_config)
@@ -209,7 +209,7 @@ fn output_extended_format(pid: &str, pmap_config: &PmapConfig) -> Result<(), Err
209209
for smap_entry in smap_table.entries {
210210
println!(
211211
"{} {:>7} {:>7} {:>7} {} {}",
212-
smap_entry.map_line.address,
212+
smap_entry.map_line.address.zero_pad(),
213213
smap_entry.map_line.size_in_kb,
214214
smap_entry.rss_in_kb,
215215
smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
@@ -361,12 +361,12 @@ fn output_device_format(pid: &str, pmap_config: &PmapConfig) -> Result<(), Error
361361
},
362362
|map_line| {
363363
println!(
364-
"{} {:>7} {} {} {} {}",
365-
map_line.address,
364+
"{} {:>7} {} {:0>16} {} {}",
365+
map_line.address.zero_pad(),
366366
map_line.size_in_kb,
367367
map_line.perms.mode(),
368368
map_line.offset,
369-
map_line.device,
369+
map_line.device.device(),
370370
map_line.parse_mapping(pmap_config)
371371
);
372372
total_mapped += map_line.size_in_kb;

0 commit comments

Comments
 (0)