|  |  |  | @ -141,17 +141,25 @@ impl UProbe { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | fn resolve_attach_path<'a, 'b, 'c>( | 
		
	
		
			
				|  |  |  |  | fn resolve_attach_path<'a, 'b, 'c, T>( | 
		
	
		
			
				|  |  |  |  |     target: &'a Path, | 
		
	
		
			
				|  |  |  |  |     proc_map: Option<&'b ProcMap>, | 
		
	
		
			
				|  |  |  |  |     proc_map: Option<&'b ProcMap<T>>, | 
		
	
		
			
				|  |  |  |  | ) -> Result<&'c Path, UProbeError> | 
		
	
		
			
				|  |  |  |  | where | 
		
	
		
			
				|  |  |  |  |     'a: 'c, | 
		
	
		
			
				|  |  |  |  |     'b: 'c, | 
		
	
		
			
				|  |  |  |  |     T: AsRef<[u8]>, | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     proc_map | 
		
	
		
			
				|  |  |  |  |         .and_then(|proc_map| proc_map.find_lib(target)) | 
		
	
		
			
				|  |  |  |  |         .map(Ok) | 
		
	
		
			
				|  |  |  |  |         .and_then(|proc_map| { | 
		
	
		
			
				|  |  |  |  |             proc_map | 
		
	
		
			
				|  |  |  |  |                 .find_library_path_by_name(target) | 
		
	
		
			
				|  |  |  |  |                 .map_err(|source| UProbeError::ProcMap { | 
		
	
		
			
				|  |  |  |  |                     pid: proc_map.pid, | 
		
	
		
			
				|  |  |  |  |                     source, | 
		
	
		
			
				|  |  |  |  |                 }) | 
		
	
		
			
				|  |  |  |  |                 .transpose() | 
		
	
		
			
				|  |  |  |  |         }) | 
		
	
		
			
				|  |  |  |  |         .or_else(|| target.is_absolute().then(|| Ok(target))) | 
		
	
		
			
				|  |  |  |  |         .or_else(|| { | 
		
	
		
			
				|  |  |  |  |             LD_SO_CACHE | 
		
	
	
		
			
				
					|  |  |  | @ -182,11 +190,19 @@ fn test_resolve_attach_path() { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Now let's resolve the path to libc. It should exist in the current process's memory map and
 | 
		
	
		
			
				|  |  |  |  |     // then in the ld.so.cache.
 | 
		
	
		
			
				|  |  |  |  |     let libc_path = resolve_attach_path("libc".as_ref(), Some(&proc_map)).unwrap(); | 
		
	
		
			
				|  |  |  |  |     let libc_path = libc_path.to_str().unwrap(); | 
		
	
		
			
				|  |  |  |  |     let libc_path = resolve_attach_path("libc".as_ref(), Some(&proc_map)).unwrap_or_else(|err| { | 
		
	
		
			
				|  |  |  |  |         match err.source() { | 
		
	
		
			
				|  |  |  |  |             Some(source) => panic!("{err}: {source}"), | 
		
	
		
			
				|  |  |  |  |             None => panic!("{err}"), | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Make sure we got a path that contains libc.
 | 
		
	
		
			
				|  |  |  |  |     assert!(libc_path.contains("libc"), "libc_path: {}", libc_path); | 
		
	
		
			
				|  |  |  |  |     assert_matches::assert_matches!( | 
		
	
		
			
				|  |  |  |  |         libc_path.to_str(), | 
		
	
		
			
				|  |  |  |  |         Some(libc_path) if libc_path.contains("libc"), | 
		
	
		
			
				|  |  |  |  |         "libc_path: {}", libc_path.display() | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | define_link_wrapper!( | 
		
	
	
		
			
				
					|  |  |  | @ -260,47 +276,197 @@ pub enum UProbeError { | 
		
	
		
			
				|  |  |  |  |         #[source] | 
		
	
		
			
				|  |  |  |  |         io_error: io::Error, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     /// There was en error fetching the memory map for `pid`.
 | 
		
	
		
			
				|  |  |  |  |     #[error("error fetching libs for {pid}")] | 
		
	
		
			
				|  |  |  |  |     ProcMap { | 
		
	
		
			
				|  |  |  |  |         /// The pid.
 | 
		
	
		
			
				|  |  |  |  |         pid: i32, | 
		
	
		
			
				|  |  |  |  |         /// The [`ProcMapError`] that caused the error.
 | 
		
	
		
			
				|  |  |  |  |         #[source] | 
		
	
		
			
				|  |  |  |  |         source: ProcMapError, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /// Error reading from /proc/pid/maps.
 | 
		
	
		
			
				|  |  |  |  | #[derive(Debug, Error)] | 
		
	
		
			
				|  |  |  |  | pub enum ProcMapError { | 
		
	
		
			
				|  |  |  |  |     /// Unable to read /proc/pid/maps.
 | 
		
	
		
			
				|  |  |  |  |     #[error(transparent)] | 
		
	
		
			
				|  |  |  |  |     ReadFile(#[from] io::Error), | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     /// Error parsing a line of /proc/pid/maps.
 | 
		
	
		
			
				|  |  |  |  |     #[error("could not parse {:?}", OsStr::from_bytes(line))] | 
		
	
		
			
				|  |  |  |  |     ParseLine { | 
		
	
		
			
				|  |  |  |  |         /// The line that could not be parsed.
 | 
		
	
		
			
				|  |  |  |  |         line: Vec<u8>, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | /// A entry that has been parsed from /proc/`pid`/maps.
 | 
		
	
		
			
				|  |  |  |  | ///
 | 
		
	
		
			
				|  |  |  |  | /// This contains information about a mapped portion of memory
 | 
		
	
		
			
				|  |  |  |  | /// for the process, ranging from address to address_end.
 | 
		
	
		
			
				|  |  |  |  | #[derive(Debug)] | 
		
	
		
			
				|  |  |  |  | struct ProcMapEntry<'a> { | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     address: u64, | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     address_end: u64, | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     perms: &'a OsStr, | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     offset: u64, | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     dev: &'a OsStr, | 
		
	
		
			
				|  |  |  |  |     #[cfg_attr(not(test), expect(dead_code))] | 
		
	
		
			
				|  |  |  |  |     inode: u32, | 
		
	
		
			
				|  |  |  |  |     path: Option<&'a Path>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl<'a> ProcMapEntry<'a> { | 
		
	
		
			
				|  |  |  |  |     fn parse(line: &'a [u8]) -> Result<Self, ProcMapError> { | 
		
	
		
			
				|  |  |  |  |         use std::os::unix::ffi::OsStrExt as _; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let err = || ProcMapError::ParseLine { | 
		
	
		
			
				|  |  |  |  |             line: line.to_vec(), | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let mut parts = line | 
		
	
		
			
				|  |  |  |  |             .split(|b| b.is_ascii_whitespace()) | 
		
	
		
			
				|  |  |  |  |             .filter(|part| !part.is_empty()); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let mut next = || parts.next().ok_or_else(err); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let (start, end) = { | 
		
	
		
			
				|  |  |  |  |             let addr = next()?; | 
		
	
		
			
				|  |  |  |  |             let mut addr_parts = addr.split(|b| *b == b'-'); | 
		
	
		
			
				|  |  |  |  |             let mut next = || { | 
		
	
		
			
				|  |  |  |  |                 addr_parts | 
		
	
		
			
				|  |  |  |  |                     .next() | 
		
	
		
			
				|  |  |  |  |                     .ok_or(()) | 
		
	
		
			
				|  |  |  |  |                     .and_then(|part| { | 
		
	
		
			
				|  |  |  |  |                         let s = | 
		
	
		
			
				|  |  |  |  |                             std::str::from_utf8(part).map_err(|std::str::Utf8Error { .. }| ())?; | 
		
	
		
			
				|  |  |  |  |                         let n = u64::from_str_radix(s, 16) | 
		
	
		
			
				|  |  |  |  |                             .map_err(|std::num::ParseIntError { .. }| ())?; | 
		
	
		
			
				|  |  |  |  |                         Ok(n) | 
		
	
		
			
				|  |  |  |  |                     }) | 
		
	
		
			
				|  |  |  |  |                     .map_err(|()| err()) | 
		
	
		
			
				|  |  |  |  |             }; | 
		
	
		
			
				|  |  |  |  |             let start = next()?; | 
		
	
		
			
				|  |  |  |  |             let end = next()?; | 
		
	
		
			
				|  |  |  |  |             if let Some(_part) = addr_parts.next() { | 
		
	
		
			
				|  |  |  |  |                 return Err(err()); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             (start, end) | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let perms = next()?; | 
		
	
		
			
				|  |  |  |  |         let perms = OsStr::from_bytes(perms); | 
		
	
		
			
				|  |  |  |  |         let offset = next()?; | 
		
	
		
			
				|  |  |  |  |         let offset = std::str::from_utf8(offset).map_err(|std::str::Utf8Error { .. }| err())?; | 
		
	
		
			
				|  |  |  |  |         let offset = | 
		
	
		
			
				|  |  |  |  |             u64::from_str_radix(offset, 16).map_err(|std::num::ParseIntError { .. }| err())?; | 
		
	
		
			
				|  |  |  |  |         let dev = next()?; | 
		
	
		
			
				|  |  |  |  |         let dev = OsStr::from_bytes(dev); | 
		
	
		
			
				|  |  |  |  |         let inode = next()?; | 
		
	
		
			
				|  |  |  |  |         let inode = std::str::from_utf8(inode).map_err(|std::str::Utf8Error { .. }| err())?; | 
		
	
		
			
				|  |  |  |  |         let inode = inode | 
		
	
		
			
				|  |  |  |  |             .parse() | 
		
	
		
			
				|  |  |  |  |             .map_err(|std::num::ParseIntError { .. }| err())?; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         let path = parts | 
		
	
		
			
				|  |  |  |  |             .next() | 
		
	
		
			
				|  |  |  |  |             .and_then(|path| match path { | 
		
	
		
			
				|  |  |  |  |                 [b'[', .., b']'] => None, | 
		
	
		
			
				|  |  |  |  |                 path => { | 
		
	
		
			
				|  |  |  |  |                     let path = Path::new(OsStr::from_bytes(path)); | 
		
	
		
			
				|  |  |  |  |                     if !path.is_absolute() { | 
		
	
		
			
				|  |  |  |  |                         Some(Err(err())) | 
		
	
		
			
				|  |  |  |  |                     } else { | 
		
	
		
			
				|  |  |  |  |                         Some(Ok(path)) | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             }) | 
		
	
		
			
				|  |  |  |  |             .transpose()?; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         if let Some(_part) = parts.next() { | 
		
	
		
			
				|  |  |  |  |             return Err(err()); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         Ok(Self { | 
		
	
		
			
				|  |  |  |  |             address: start, | 
		
	
		
			
				|  |  |  |  |             address_end: end, | 
		
	
		
			
				|  |  |  |  |             perms, | 
		
	
		
			
				|  |  |  |  |             offset, | 
		
	
		
			
				|  |  |  |  |             dev, | 
		
	
		
			
				|  |  |  |  |             inode, | 
		
	
		
			
				|  |  |  |  |             path, | 
		
	
		
			
				|  |  |  |  |         }) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct ProcMap { | 
		
	
		
			
				|  |  |  |  |     data: Vec<u8>, | 
		
	
		
			
				|  |  |  |  | /// The memory maps of a process.
 | 
		
	
		
			
				|  |  |  |  | ///
 | 
		
	
		
			
				|  |  |  |  | /// This is read from /proc/`pid`/maps.
 | 
		
	
		
			
				|  |  |  |  | ///
 | 
		
	
		
			
				|  |  |  |  | /// The information here may be used to resolve addresses to paths.
 | 
		
	
		
			
				|  |  |  |  | struct ProcMap<T> { | 
		
	
		
			
				|  |  |  |  |     pid: pid_t, | 
		
	
		
			
				|  |  |  |  |     data: T, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl ProcMap { | 
		
	
		
			
				|  |  |  |  | impl ProcMap<Vec<u8>> { | 
		
	
		
			
				|  |  |  |  |     fn new(pid: pid_t) -> Result<Self, UProbeError> { | 
		
	
		
			
				|  |  |  |  |         let filename = PathBuf::from(format!("/proc/{pid}/maps")); | 
		
	
		
			
				|  |  |  |  |         let data = fs::read(&filename) | 
		
	
		
			
				|  |  |  |  |             .map_err(|io_error| UProbeError::FileError { filename, io_error })?; | 
		
	
		
			
				|  |  |  |  |         Ok(Self { data }) | 
		
	
		
			
				|  |  |  |  |         Ok(Self { pid, data }) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     fn libs(&self) -> impl Iterator<Item = (&OsStr, &Path)> { | 
		
	
		
			
				|  |  |  |  |         let Self { data } = self; | 
		
	
		
			
				|  |  |  |  | impl<T: AsRef<[u8]>> ProcMap<T> { | 
		
	
		
			
				|  |  |  |  |     fn libs(&self) -> impl Iterator<Item = Result<ProcMapEntry<'_>, ProcMapError>> { | 
		
	
		
			
				|  |  |  |  |         let Self { pid: _, data } = self; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         data.split(|&b| b == b'\n').filter_map(|line| { | 
		
	
		
			
				|  |  |  |  |             line.split(|b| b.is_ascii_whitespace()) | 
		
	
		
			
				|  |  |  |  |                 .filter(|p| !p.is_empty()) | 
		
	
		
			
				|  |  |  |  |                 .next_back() | 
		
	
		
			
				|  |  |  |  |                 .and_then(|path| { | 
		
	
		
			
				|  |  |  |  |                     let path = Path::new(OsStr::from_bytes(path)); | 
		
	
		
			
				|  |  |  |  |                     path.is_absolute() | 
		
	
		
			
				|  |  |  |  |                         .then_some(()) | 
		
	
		
			
				|  |  |  |  |                         .and_then(|()| path.file_name()) | 
		
	
		
			
				|  |  |  |  |                         .map(|file_name| (file_name, path)) | 
		
	
		
			
				|  |  |  |  |                 }) | 
		
	
		
			
				|  |  |  |  |         }) | 
		
	
		
			
				|  |  |  |  |         data.as_ref() | 
		
	
		
			
				|  |  |  |  |             .split(|&b| b == b'\n') | 
		
	
		
			
				|  |  |  |  |             .map(ProcMapEntry::parse) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     fn find_lib(&self, lib: &Path) -> Option<&Path> { | 
		
	
		
			
				|  |  |  |  |     // Find the full path of a library by its name.
 | 
		
	
		
			
				|  |  |  |  |     //
 | 
		
	
		
			
				|  |  |  |  |     // This isn't part of the public API since it's really only useful for
 | 
		
	
		
			
				|  |  |  |  |     // attaching uprobes.
 | 
		
	
		
			
				|  |  |  |  |     fn find_library_path_by_name(&self, lib: &Path) -> Result<Option<&Path>, ProcMapError> { | 
		
	
		
			
				|  |  |  |  |         let lib = lib.as_os_str(); | 
		
	
		
			
				|  |  |  |  |         let lib = lib.strip_suffix(OsStr::new(".so")).unwrap_or(lib); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         self.libs().find_map(|(file_name, path)| { | 
		
	
		
			
				|  |  |  |  |             file_name.strip_prefix(lib).and_then(|suffix| { | 
		
	
		
			
				|  |  |  |  |                 (suffix.starts_with(OsStr::new(".so")) || suffix.starts_with(OsStr::new("-"))) | 
		
	
		
			
				|  |  |  |  |                     .then_some(path) | 
		
	
		
			
				|  |  |  |  |             }) | 
		
	
		
			
				|  |  |  |  |         }) | 
		
	
		
			
				|  |  |  |  |         for entry in self.libs() { | 
		
	
		
			
				|  |  |  |  |             let ProcMapEntry { | 
		
	
		
			
				|  |  |  |  |                 address: _, | 
		
	
		
			
				|  |  |  |  |                 address_end: _, | 
		
	
		
			
				|  |  |  |  |                 perms: _, | 
		
	
		
			
				|  |  |  |  |                 offset: _, | 
		
	
		
			
				|  |  |  |  |                 dev: _, | 
		
	
		
			
				|  |  |  |  |                 inode: _, | 
		
	
		
			
				|  |  |  |  |                 path, | 
		
	
		
			
				|  |  |  |  |             } = entry?; | 
		
	
		
			
				|  |  |  |  |             if let Some(path) = path { | 
		
	
		
			
				|  |  |  |  |                 if let Some(filename) = path.file_name() { | 
		
	
		
			
				|  |  |  |  |                     if let Some(suffix) = filename.strip_prefix(lib) { | 
		
	
		
			
				|  |  |  |  |                         if suffix.is_empty() | 
		
	
		
			
				|  |  |  |  |                             || suffix.starts_with(OsStr::new(".so")) | 
		
	
		
			
				|  |  |  |  |                             || suffix.starts_with(OsStr::new("-")) | 
		
	
		
			
				|  |  |  |  |                         { | 
		
	
		
			
				|  |  |  |  |                             return Ok(Some(path)); | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         Ok(None) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -569,7 +735,7 @@ fn resolve_symbol(path: &Path, symbol: &str) -> Result<u64, ResolveSymbolError> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[cfg(test)] | 
		
	
		
			
				|  |  |  |  | mod tests { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     use assert_matches::assert_matches; | 
		
	
		
			
				|  |  |  |  |     use object::{Architecture, BinaryFormat, Endianness, write::SectionKind}; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     use super::*; | 
		
	
	
		
			
				
					|  |  |  | @ -736,4 +902,141 @@ mod tests { | 
		
	
		
			
				|  |  |  |  |             Err(ResolveSymbolError::BuildIdMismatch(_)) | 
		
	
		
			
				|  |  |  |  |         )); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_parse_proc_map_entry_shared_lib() { | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7ffd6fbea000-7ffd6fbec000	r-xp	00000000	00:00	0	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Ok(ProcMapEntry { | 
		
	
		
			
				|  |  |  |  |                 address: 0x7ffd6fbea000, | 
		
	
		
			
				|  |  |  |  |                 address_end: 0x7ffd6fbec000, | 
		
	
		
			
				|  |  |  |  |                 perms, | 
		
	
		
			
				|  |  |  |  |                 offset: 0, | 
		
	
		
			
				|  |  |  |  |                 dev, | 
		
	
		
			
				|  |  |  |  |                 inode: 0, | 
		
	
		
			
				|  |  |  |  |                 path: None, | 
		
	
		
			
				|  |  |  |  |             }) if perms == "r-xp" && dev == "00:00" | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_parse_proc_map_entry_absolute_path() { | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca83a000-7f1bca83c000	rw-p	00036000	fd:01	2895508	/usr/lib64/ld-linux-x86-64.so.2"), | 
		
	
		
			
				|  |  |  |  |             Ok(ProcMapEntry { | 
		
	
		
			
				|  |  |  |  |                 address: 0x7f1bca83a000, | 
		
	
		
			
				|  |  |  |  |                 address_end: 0x7f1bca83c000, | 
		
	
		
			
				|  |  |  |  |                 perms, | 
		
	
		
			
				|  |  |  |  |                 offset: 0x00036000, | 
		
	
		
			
				|  |  |  |  |                 dev, | 
		
	
		
			
				|  |  |  |  |                 inode: 2895508, | 
		
	
		
			
				|  |  |  |  |                 path: Some(path), | 
		
	
		
			
				|  |  |  |  |             }) if perms == "rw-p" && dev == "fd:01" && path == Path::new("/usr/lib64/ld-linux-x86-64.so.2") | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_parse_proc_map_entry_all_zeros() { | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000	rw-p	00000000	00:00	0"), | 
		
	
		
			
				|  |  |  |  |             Ok(ProcMapEntry { | 
		
	
		
			
				|  |  |  |  |                 address: 0x7f1bca5f9000, | 
		
	
		
			
				|  |  |  |  |                 address_end: 0x7f1bca601000, | 
		
	
		
			
				|  |  |  |  |                 perms, | 
		
	
		
			
				|  |  |  |  |                 offset: 0, | 
		
	
		
			
				|  |  |  |  |                 dev, | 
		
	
		
			
				|  |  |  |  |                 inode: 0, | 
		
	
		
			
				|  |  |  |  |                 path: None, | 
		
	
		
			
				|  |  |  |  |             }) if perms == "rw-p" && dev == "00:00" | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_parse_proc_map_entry_parse_errors() { | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"zzzz-7ffd6fbea000	r-xp	00000000	00:00	0	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"zzzz-7ffd6fbea000	r-xp	00000000	00:00	0	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000	r-xp	zzzz	00:00	0	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000	r-xp	00000000	00:00	zzzz	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f90007ffd6fbea000	r-xp	00000000	00:00	0	[vdso]"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000	r-xp	00000000"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000-deadbeef	rw-p	00000000	00:00	0"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             ProcMapEntry::parse(b"7f1bca5f9000-7f1bca601000	rw-p	00000000	00:00	0	deadbeef"), | 
		
	
		
			
				|  |  |  |  |             Err(ProcMapError::ParseLine { line: _ }) | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_proc_map_find_lib_by_name() { | 
		
	
		
			
				|  |  |  |  |         let proc_map_libs = ProcMap { | 
		
	
		
			
				|  |  |  |  |             pid: 0xdead, | 
		
	
		
			
				|  |  |  |  |             data: b"7fc4a9800000-7fc4a98ad000	r--p	00000000	00:24	18147308	/usr/lib64/libcrypto.so.3.0.9", | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             proc_map_libs.find_library_path_by_name(Path::new("libcrypto.so.3.0.9")), | 
		
	
		
			
				|  |  |  |  |             Ok(Some(path)) if path == Path::new("/usr/lib64/libcrypto.so.3.0.9") | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_proc_map_find_lib_by_partial_name() { | 
		
	
		
			
				|  |  |  |  |         let proc_map_libs = ProcMap { | 
		
	
		
			
				|  |  |  |  |             pid: 0xdead, | 
		
	
		
			
				|  |  |  |  |             data: b"7fc4a9800000-7fc4a98ad000	r--p	00000000	00:24	18147308	/usr/lib64/libcrypto.so.3.0.9", | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             proc_map_libs.find_library_path_by_name(Path::new("libcrypto")), | 
		
	
		
			
				|  |  |  |  |             Ok(Some(path)) if path == Path::new("/usr/lib64/libcrypto.so.3.0.9") | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     #[test] | 
		
	
		
			
				|  |  |  |  |     fn test_proc_map_with_multiple_lib_entries() { | 
		
	
		
			
				|  |  |  |  |         let proc_map_libs = ProcMap { | 
		
	
		
			
				|  |  |  |  |             pid: 0xdead, | 
		
	
		
			
				|  |  |  |  |             data: br#" | 
		
	
		
			
				|  |  |  |  | 7f372868000-7f3722869000	r--p	00000000	00:24	18097875	/usr/lib64/ld-linux-x86-64.so.2 | 
		
	
		
			
				|  |  |  |  | 7f3722869000-7f372288f000	r-xp	00001000	00:24	18097875	/usr/lib64/ld-linux-x86-64.so.2 | 
		
	
		
			
				|  |  |  |  | 7f372288f000-7f3722899000	r--p	00027000	00:24	18097875	/usr/lib64/ld-linux-x86-64.so.2 | 
		
	
		
			
				|  |  |  |  | 7f3722899000-7f372289b000	r--p	00030000	00:24	18097875	/usr/lib64/ld-linux-x86-64.so.2 | 
		
	
		
			
				|  |  |  |  | 7f372289b000-7f372289d000	rw-p	00032000	00:24	18097875	/usr/lib64/ld-linux-x86-64.so.2 | 
		
	
		
			
				|  |  |  |  | "# | 
		
	
		
			
				|  |  |  |  |             .trim_ascii(), | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         assert_matches!( | 
		
	
		
			
				|  |  |  |  |             proc_map_libs.find_library_path_by_name(Path::new("ld-linux-x86-64.so.2")), | 
		
	
		
			
				|  |  |  |  |             Ok(Some(path)) if path == Path::new("/usr/lib64/ld-linux-x86-64.so.2") | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |