summary refs log tree commit diff
path: root/ripple
diff options
context:
space:
mode:
authoredef <edef@unfathomable.blue>2022-07-30 15:12:11 +0000
committeredef <edef@unfathomable.blue>2022-07-30 15:12:11 +0000
commit5929bcc83568242ff3f4a6173e4deeb500cd440f (patch)
treecf1158534c7767dfad1b063f9a953254577f9d01 /ripple
parent264db440596908879070b146837b516722826bf5 (diff)
ripple/minitrace: read /proc/$pid/map_files to disambiguate pathnames
This differentiates \n in pathnames from \012 in pathnames.

Change-Id: I2c86084c9e46f42b43ea7c824be147d97d26a800
Diffstat (limited to 'ripple')
-rw-r--r--ripple/minitrace/src/main.rs32
-rw-r--r--ripple/minitrace/src/maps_file.rs26
2 files changed, 45 insertions, 13 deletions
diff --git a/ripple/minitrace/src/main.rs b/ripple/minitrace/src/main.rs
index 0f9cb0d..9d9a790 100644
--- a/ripple/minitrace/src/main.rs
+++ b/ripple/minitrace/src/main.rs
@@ -20,7 +20,7 @@ use {
 		env,
 		ffi::CString,
 		fmt::{self, Debug},
-		fs::File,
+		fs::{self, File},
 		io::{self, BufRead, Seek, SeekFrom},
 		os::unix::process::CommandExt,
 		process::Command,
@@ -96,15 +96,41 @@ impl Process {
 	}
 
 	fn read_mappings(&self) -> Result<Vec<maps_file::Mapping>> {
-		let contents = std::fs::read_to_string(format!("/proc/{}/maps", self.tgid.0))?;
+		let pid = self.tgid.as_pid();
+		let contents = fs::read_to_string(format!("/proc/{pid}/maps"))?;
 
 		// TODO(edef): consult /proc/$pid/map_files/* for pathnames, since /proc/$pid/maps is unreliable with odd paths
 		// we'll want to verify the two against each other, just to be sure they're congruent
 
-		let mappings = contents
+		let mut mappings = contents
 			.lines()
 			.map(maps_file::parse_mapping_line)
 			.collect::<Result<_, _>>()?;
+
+		for &mut maps_file::Mapping {
+			start,
+			end,
+			ref mut pathname,
+			..
+		} in &mut mappings
+		{
+			if pathname.starts_with('[') && pathname.ends_with(']') {
+				// these won't exist in map_files
+				continue;
+			}
+
+			let map_path = format!("/proc/{pid}/map_files/{start:x}-{end:x}");
+			let target = fs::read_link(&map_path)
+				.with_context(|| {
+					format!("Cannot readlink({map_path:?}) (expected target: {pathname:?})")
+				})?
+				.into_os_string()
+				.into_string()
+				.expect("path is not valid UTF-8");
+			assert_eq!(*pathname, maps_file::escape_path(&target), "escaping bug?");
+			*pathname = target;
+		}
+
 		Ok(mappings)
 	}
 }
diff --git a/ripple/minitrace/src/maps_file.rs b/ripple/minitrace/src/maps_file.rs
index 84fc0fb..af35bde 100644
--- a/ripple/minitrace/src/maps_file.rs
+++ b/ripple/minitrace/src/maps_file.rs
@@ -121,16 +121,16 @@ pub(crate) fn parse_mapping_line(line: &str) -> anyhow::Result<Mapping> {
 
 #[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,
+	pub(crate) start: u64,
+	pub(crate) end: u64,
+	pub(crate) perm_read: bool,
+	pub(crate) perm_write: bool,
+	pub(crate) perm_exec: bool,
+	pub(crate) shared: bool,
+	pub(crate) offset: u64,
+	pub(crate) dev: (u32, u32),
+	pub(crate) inode: u64,
+	pub(crate) pathname: String,
 }
 
 impl Debug for Mapping {
@@ -184,3 +184,9 @@ fn golden_mapping() {
 	};
 	assert_eq!(mapping(line).unwrap().1, golden);
 }
+
+// NOTE: this is a surjective mapping, since backslashes are not escaped
+// ie `escape_path("\\012") == escape_path("\n")`
+pub(crate) fn escape_path(path: &str) -> String {
+	path.replace('\n', "\\012")
+}