use std::path::PathBuf;
use super::Pid;
#[derive(Debug, Copy, Clone)]
pub struct LibrarySegment {
start: u64,
end: u64,
#[allow(unused)]
offset: u64,
}
#[derive(Debug, Clone)]
pub struct Library {
pub inode: u64,
pub path: PathBuf,
pub segments: Vec<LibrarySegment>,
pub base: u64,
}
impl Library {
pub fn contains_ip(&self, ip: u64) -> bool {
for seg in &self.segments {
if ip >= seg.start && ip < seg.end {
return true;
}
}
false
}
}
#[derive(Debug, Clone)]
pub struct Libraries {
libraries: Vec<Library>,
}
impl Libraries {
pub fn new(pid: Pid) -> Result<Self, procfs::ProcError> {
use std::collections::BTreeMap;
use procfs::process::MMapPath;
let maps = {
let _open = crate::process::launch_window::TransientOpen::begin();
procfs::process::Process::new(pid.as_raw())?.maps()?
};
let mut libraries = BTreeMap::new();
for map in maps {
if let MMapPath::Path(p) = map.pathname {
let library = libraries.entry(map.inode).or_insert_with(|| Library {
inode: map.inode,
path: p,
segments: Vec::new(),
base: map.address.0,
});
library.segments.push(LibrarySegment {
start: map.address.0,
end: map.address.1,
offset: map.offset,
});
}
}
Ok(Self {
libraries: libraries.into_values().collect(),
})
}
pub fn ip_to_vaddr(&self, ip: u64) -> Option<(&Library, u64)> {
for lib in &self.libraries {
if lib.contains_ip(ip) {
return Some((lib, ip - lib.base - 1));
}
}
None
}
#[allow(unused)]
pub fn iter(&self) -> impl Iterator<Item = &Library> {
self.libraries.iter()
}
}