Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/linux/maps_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
super::{
auxv::AuxvType,
module_reader::ModuleReaderError,
process_inspection::{self, ProcessInspector},
process_inspection::{self, Backend, ProcessInspector},
serializers::*,
},
crate::serializers::*,
Expand Down Expand Up @@ -136,12 +136,12 @@ fn sanitize_path(pathname: OsString) -> OsString {
impl MappingInfo {
/// Get the mappings for the given process.
pub fn for_pid(
process_inspector: &ProcessInspector,
backend: &Backend,
pid: i32,
linux_gate_loc: Option<AuxvType>,
) -> Result<Vec<Self>> {
let maps_path = format!("/proc/{}/maps", pid);
let maps_file = process_inspector
let maps_file = backend
.read_file(&maps_path)
.map_err(MapsReaderError::ReadFileFailed)?;
let maps = MemoryMaps::from_read(maps_file)?;
Expand Down
2 changes: 1 addition & 1 deletion src/linux/minidump_writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ impl MinidumpWriter {
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
// information.
self.mappings = MappingInfo::for_pid(
&self.process_inspector,
&self.process_inspector.backend,
self.process_id,
self.auxv.get_linux_gate_address(),
)
Expand Down
16 changes: 16 additions & 0 deletions src/linux/module_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,22 @@ impl<'a> ReadModuleMemory for ProcessModuleMemoryReader<'a> {
}
}

impl<'a> ReadModuleMemory for &ProcessModuleMemoryReader<'a> {
fn read(&self, offset: u64, length: u64) -> Result<Cow<'a, [u8]>, ModuleMemoryReadError> {
ProcessModuleMemoryReader::read(self, offset, length)
}
fn absolute_to_relative(&self, addr: u64) -> Option<u64> {
addr.checked_sub(self.start_address)
}
/// Calculates the absolute address of the specified relative address
fn relative_to_absolute(&self, addr: u64) -> Option<u64> {
self.start_address.checked_add(addr)
}
fn is_process_memory(&self) -> bool {
true
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
26 changes: 16 additions & 10 deletions src/linux/process_inspection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,33 @@ pub mod process_reader;
pub struct ProcessInspector {
pid: libc::pid_t,
process_reader: ProcessReader,
backend: Rc<Backend>,
pub(crate) backend: Rc<Backend>,
}

#[derive(Debug)]
pub enum Backend {
Local(local::Backend),
}

impl Backend {
pub fn read_file(&self, path: impl Into<PathBuf>) -> Result<FileReader, Error> {
let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
match self {
Backend::Local(l) => l
.read_file(&c_path)
.map(FileReader::Local)
.map_err(Error::Local),
}
}
}

impl ProcessInspector {
pub fn local(pid: libc::pid_t) -> Self {
let backend = Rc::new(Backend::Local(local::Backend::new(pid)));

ProcessInspector {
pid,
process_reader: ProcessReader::new(pid, Rc::clone(&backend)),
process_reader: ProcessReader::new_with_backend(pid, Rc::clone(&backend)),
backend,
}
}
Expand Down Expand Up @@ -93,13 +105,7 @@ impl ProcessInspector {
}

pub fn read_file(&self, path: impl Into<PathBuf>) -> Result<FileReader, Error> {
let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
match &*self.backend {
Backend::Local(l) => l
.read_file(&c_path)
.map(FileReader::Local)
.map_err(Error::Local),
}
self.backend.read_file(path)
}

pub fn read_dir(&self, path: impl Into<PathBuf>) -> Result<DirReader, Error> {
Expand Down Expand Up @@ -199,7 +205,7 @@ impl Iterator for DirReader {
#[doc(hidden)]
impl ProcessInspector {
pub fn force_pr_reset(&mut self) {
self.process_reader = ProcessReader::new(self.pid, Rc::clone(&self.backend))
self.process_reader = ProcessReader::new_with_backend(self.pid, Rc::clone(&self.backend))
}
pub fn force_pr_virtual_mem(&mut self) {
self.process_reader = ProcessReader::for_virtual_mem(self.pid, Rc::clone(&self.backend))
Expand Down
52 changes: 51 additions & 1 deletion src/linux/process_inspection/process_reader.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use {
super::{Backend, Error, FileReader},
crate::linux::maps_reader::{MappingInfo, MapsReaderError},
crate::module_reader::ProcessModuleMemoryReader,
core::{ffi::c_long, mem},
std::{ffi::CString, rc::Rc, sync::OnceLock},
};

pub type ProcessHandle = libc::pid_t;

#[derive(Debug)]
enum Style {
/// Uses [`process_vm_readv`](https://linux.die.net/man/2/process_vm_readv)
Expand Down Expand Up @@ -49,6 +53,14 @@ pub enum CopyFromProcessError {
InvalidArgument,
}

#[derive(Debug, thiserror::Error, serde::Serialize)]
pub enum FindModuleError {
#[error("Module not found")]
ModuleNotFound,
#[error("Failed to read process module mappings")]
MappingError(#[from] MapsReaderError),
}

#[derive(Debug, thiserror::Error, serde::Serialize)]
pub enum StrategyError {
#[error(transparent)]
Expand Down Expand Up @@ -82,7 +94,15 @@ impl ProcessReader {
/// Creates a [`Self`] for the specified process id, the method used will
/// be probed for on the first access
#[inline]
pub(super) fn new(pid: libc::pid_t, backend: Rc<Backend>) -> Self {
pub fn new(pid: ProcessHandle) -> Self {
Self::new_with_backend(
pid,
Rc::new(Backend::Local(super::local::Backend::new(pid))),
)
}

#[inline]
pub(super) fn new_with_backend(pid: libc::pid_t, backend: Rc<Backend>) -> Self {
Self {
pid,
style: OnceLock::default(),
Expand Down Expand Up @@ -231,4 +251,34 @@ impl ProcessReader {

Ok(dst.len())
}

pub fn find_module(
&self,
module_name: &str,
) -> Result<ProcessModuleMemoryReader<'_>, FindModuleError> {
MappingInfo::for_pid(&self.backend, self.pid, None)?
.into_iter()
.find_map(|m| {
let mmem = ProcessModuleMemoryReader::new(self, m.start_address);
let name = m.name.as_ref().and_then(|s| s.to_str())?;
if name == module_name {
return Some(mmem);
}
// Check whether the SO_NAME matches the module name.
//
// For now, only check the SO_NAME of Android APKS, because libraries may be mapped
// directly from within an APK. See bug 1982902.
#[cfg(target_os = "android")]
if name.ends_with(".apk") {
if let Ok(so_name) = crate::module_reader::read_soname_from_module(&mmem) {
if so_name == name {
return Some(mmem);
}
}
}

None
})
.ok_or(FindModuleError::ModuleNotFound)
}
}
70 changes: 0 additions & 70 deletions src/process_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,73 +157,3 @@ fn uninit_slice_as_bytes_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [u8] {
std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, size_of::<T>() * slice.len())
}
}

/*
#[derive(Debug, Error)]
pub enum ProcessReaderError {
#[error("Could not convert address {0}")]
ConvertAddressError(#[from] std::num::TryFromIntError),
#[error("Could not parse address {0}")]
ParseAddressError(#[from] std::num::ParseIntError),
#[cfg(target_os = "windows")]
#[error("Cannot enumerate the target process's modules")]
EnumProcessModulesError,
#[error("goblin failed to parse a module")]
GoblinError(#[from] goblin::error::Error),
#[error("Address was out of bounds")]
InvalidAddress,
#[error("Could not read from the target process address space")]
ReadFromProcessError(#[from] ReadError),
#[cfg(any(target_os = "windows", target_os = "macos"))]
#[error("Section was not found")]
SectionNotFound,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("Could not attach to the target process")]
AttachError(#[from] PtraceError),
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("Note not found")]
NoteNotFound,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("SONAME not found")]
SoNameNotFound,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("waitpid() failed when attaching to the process")]
WaitPidError,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("Could not parse a line in /proc/<pid>/maps")]
ProcMapsParseError,
#[error("Module not found")]
ModuleNotFound,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("IO error for file {0}")]
IOError(#[from] std::io::Error),
#[cfg(target_os = "macos")]
#[error("Failure when requesting the task information")]
TaskInfoError,
#[cfg(target_os = "macos")]
#[error("The task dyld information format is unknown or invalid")]
ImageFormatError,
}

#[derive(Debug, Error)]
pub enum ReadError {
#[cfg(target_os = "macos")]
#[error("mach call failed")]
MachError,
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("ptrace-specific error")]
PtraceError(#[from] PtraceError),
#[cfg(target_os = "windows")]
#[error("ReadProcessMemory failed")]
ReadProcessMemoryError,
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[derive(Debug, Error)]
pub enum PtraceError {
#[error("Could not read from the target process address space")]
ReadError(#[source] std::io::Error),
#[error("Could not trace the process")]
TraceError(#[source] std::io::Error),
}
*/
Loading