From 5929bcc83568242ff3f4a6173e4deeb500cd440f Mon Sep 17 00:00:00 2001 From: edef Date: Sat, 30 Jul 2022 15:12:11 +0000 Subject: ripple/minitrace: read /proc/$pid/map_files to disambiguate pathnames This differentiates \n in pathnames from \012 in pathnames. Change-Id: I2c86084c9e46f42b43ea7c824be147d97d26a800 --- ripple/minitrace/src/main.rs | 32 +++++++++++++++++++++++++++++--- ripple/minitrace/src/maps_file.rs | 26 ++++++++++++++++---------- 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> { - 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::>()?; + + 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 { #[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") +} -- cgit 1.4.1