diff options
Diffstat (limited to 'ripple/minitrace/src')
-rw-r--r-- | ripple/minitrace/src/main.rs | 17 | ||||
-rw-r--r-- | ripple/minitrace/src/maps_file.rs | 186 |
2 files changed, 203 insertions, 0 deletions
diff --git a/ripple/minitrace/src/main.rs b/ripple/minitrace/src/main.rs index cf23034..0f9cb0d 100644 --- a/ripple/minitrace/src/main.rs +++ b/ripple/minitrace/src/main.rs @@ -27,6 +27,8 @@ use { }, }; +mod maps_file; + // TODO(edef): consider implementing this in terms of TID? // tgids are a strict subset of tids #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -92,6 +94,19 @@ impl Process { Ok(CString::from_vec_with_nul(buf).expect("logic error")) } + + fn read_mappings(&self) -> Result<Vec<maps_file::Mapping>> { + let contents = std::fs::read_to_string(format!("/proc/{}/maps", self.tgid.0))?; + + // 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 + .lines() + .map(maps_file::parse_mapping_line) + .collect::<Result<_, _>>()?; + Ok(mappings) + } } macro_rules! define_syscalls { @@ -384,6 +399,8 @@ fn main() -> Result<()> { cmd })?; + println!("{:#?}", process.read_mappings()?); + let options = ptrace::Options::PTRACE_O_TRACESYSGOOD | ptrace::Options::PTRACE_O_TRACECLONE | ptrace::Options::PTRACE_O_EXITKILL; 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); +} |