summary refs log tree commit diff
path: root/ripple/minitrace/src/maps_file.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ripple/minitrace/src/maps_file.rs')
-rw-r--r--ripple/minitrace/src/maps_file.rs186
1 files changed, 186 insertions, 0 deletions
diff --git a/ripple/minitrace/src/maps_file.rs b/ripple/minitrace/src/maps_file.rs
new file mode 100644
index 0000000..84fc0fb
--- /dev/null
+++ b/ripple/minitrace/src/maps_file.rs
@@ -0,0 +1,186 @@
+// SPDX-FileCopyrightText: edef <edef@unfathomable.blue>
+// SPDX-License-Identifier: OSL-3.0
+
+use {
+	anyhow::bail,
+	nom::{
+		branch::alt,
+		bytes::complete::{tag, take_while},
+		combinator::map_res,
+		sequence::tuple,
+		IResult,
+	},
+	std::fmt::{self, Debug},
+};
+
+fn whitespace(s: &str) -> IResult<&str, &str> {
+	take_while(|c| c == ' ')(s)
+}
+
+fn hex_u32(s: &str) -> IResult<&str, u32> {
+	map_res(take_while(|c: char| c.is_ascii_hexdigit()), |src| {
+		u32::from_str_radix(src, 16)
+	})(s)
+}
+
+fn hex_u64(s: &str) -> IResult<&str, u64> {
+	map_res(take_while(|c: char| c.is_ascii_hexdigit()), |src| {
+		u64::from_str_radix(src, 16)
+	})(s)
+}
+
+fn dec_u64(s: &str) -> IResult<&str, u64> {
+	map_res(take_while(|c: char| c.is_ascii_hexdigit()), |src| {
+		u64::from_str_radix(src, 10)
+	})(s)
+}
+
+fn perm(c: &'static str) -> impl Fn(&str) -> IResult<&str, bool> {
+	move |input| {
+		let (input, tag) = alt((tag(c), tag("-")))(input)?;
+		Ok((input, tag != "-"))
+	}
+}
+
+fn shared(input: &str) -> IResult<&str, bool> {
+	let (input, tag) = alt((tag("p"), tag("s")))(input)?;
+	Ok((input, tag == "s"))
+}
+
+fn pathname(input: &str) -> IResult<&str, &str> {
+	take_while(|c| c != '\n')(input)
+}
+
+fn mapping(input: &str) -> IResult<&str, Mapping> {
+	let (
+		input,
+		(
+			start,
+			_,
+			end,
+			_,
+			perm_read,
+			perm_write,
+			perm_exec,
+			shared,
+			_,
+			offset,
+			_,
+			dev_maj,
+			_,
+			dev_min,
+			_,
+			inode,
+			_,
+			pathname,
+		),
+	) = tuple((
+		hex_u64,
+		tag("-"),
+		hex_u64,
+		whitespace,
+		perm("r"),
+		perm("w"),
+		perm("x"),
+		shared,
+		whitespace,
+		hex_u64,
+		whitespace,
+		hex_u32,
+		tag(":"),
+		hex_u32,
+		whitespace,
+		dec_u64,
+		whitespace,
+		pathname,
+	))(input)?;
+	Ok((
+		input,
+		Mapping {
+			start,
+			end,
+			perm_read,
+			perm_write,
+			perm_exec,
+			shared,
+			offset,
+			dev: (dev_maj, dev_min),
+			inode,
+			pathname: pathname.to_owned(),
+		},
+	))
+}
+
+pub(crate) fn parse_mapping_line(line: &str) -> anyhow::Result<Mapping> {
+	match mapping(line) {
+		Ok(("", mapping)) => Ok(mapping),
+		Ok(_) => unreachable!(),
+		Err(err) => bail!("Cannot parse mapping: {err}"),
+	}
+}
+
+#[derive(Eq, PartialEq)]
+pub(crate) struct Mapping {
+	start: u64,
+	end: u64,
+	perm_read: bool,
+	perm_write: bool,
+	perm_exec: bool,
+	shared: bool,
+	offset: u64,
+	dev: (u32, u32),
+	inode: u64,
+	pathname: String,
+}
+
+impl Debug for Mapping {
+	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+		use std::fmt::Write;
+
+		let Mapping {
+			start,
+			end,
+			perm_read,
+			perm_write,
+			perm_exec,
+			shared,
+			offset,
+			dev: (dev_maj, dev_min),
+			inode,
+			ref pathname,
+		} = *self;
+
+		write!(f, "{start:016x}-{end:016x} ")?;
+
+		for (c, p) in [('r', perm_read), ('w', perm_write), ('x', perm_exec)] {
+			f.write_char(if p { c } else { '-' })?;
+		}
+		f.write_char(if shared { 's' } else { 'p' })?;
+		f.write_char(' ')?;
+
+		write!(
+			f,
+			"{offset:016x} {dev_maj:04x}:{dev_min:04x} {inode:20} {pathname}"
+		)
+	}
+}
+
+#[test]
+fn golden_mapping() {
+	let line =
+				"00400000-00407000 r--p 00000000 00:1e 7507895                            /nix/store/hgl0ydlkgs6y6hx9h7k209shw3v7z77j-coreutils-9.0/bin/coreutils";
+	let golden = Mapping {
+		start: 0x00400000,
+		end: 0x00407000,
+		perm_read: true,
+		perm_write: false,
+		perm_exec: false,
+		shared: false,
+		offset: 0,
+		dev: (0x00, 0x1e),
+		inode: 7507895,
+		pathname: "/nix/store/hgl0ydlkgs6y6hx9h7k209shw3v7z77j-coreutils-9.0/bin/coreutils"
+			.to_owned(),
+	};
+	assert_eq!(mapping(line).unwrap().1, golden);
+}