diff --git a/crates/linux/process-backend/src/lib.rs b/crates/linux/process-backend/src/lib.rs index 00d93710..62c5030b 100644 --- a/crates/linux/process-backend/src/lib.rs +++ b/crates/linux/process-backend/src/lib.rs @@ -7,3 +7,11 @@ pub mod regs; /// This is the longest path length we guarantee we can handle, since we won't be able to allocate /// in the fork of the crashed process. We can increase if necessary. pub const MAX_PATH_LEN: usize = 256; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub enum ProcessReaderKind { + Unspecified, + VirtualMem, + File, + Ptrace, +} diff --git a/crates/linux/process-backend/src/local/mod.rs b/crates/linux/process-backend/src/local/mod.rs index c8c7de06..f96c75ef 100644 --- a/crates/linux/process-backend/src/local/mod.rs +++ b/crates/linux/process-backend/src/local/mod.rs @@ -1,4 +1,4 @@ -use crate::regs::*; +use crate::{ProcessReaderKind, regs::*}; use core::{ cell::RefCell, ffi::{CStr, c_int, c_long, c_void}, @@ -22,6 +22,7 @@ type PtraceRequestType = core::ffi::c_int; #[derive(Debug)] pub struct Backend { pid: pid_t, + process_reader: process_reader::ProcessReader, syscall_invoker: RefCell, } @@ -29,11 +30,12 @@ impl Backend { pub fn new(pid: libc::pid_t) -> Self { Self { pid, + process_reader: process_reader::ProcessReader::new(pid), syscall_invoker: Default::default(), } } - pub fn process_reader(&self) -> ProcessReader { - ProcessReader(process_reader::ProcessReader::new(self.pid)) + pub fn process_reader(&self) -> ProcessReader<'_> { + ProcessReader(&self.process_reader) } pub fn stop_process(&self) -> Result<(), Error> { self.standard_syscall(|| unsafe { libc::kill(self.pid, libc::SIGSTOP) }) @@ -175,18 +177,17 @@ impl Backend { .map_err(Error::PtracePeekUserFailed) } - pub fn process_reader_for_virtual_mem(&self) -> ProcessReader { - ProcessReader(process_reader::ProcessReader::for_virtual_mem(self.pid)) - } - - pub fn process_reader_for_file(&self) -> Result { - process_reader::ProcessReader::for_file(self.pid) - .map(ProcessReader) - .map_err(Error::ProcessReader) - } - - pub fn process_reader_for_ptrace(&self) -> ProcessReader { - ProcessReader(process_reader::ProcessReader::for_ptrace(self.pid)) + pub fn force_process_reader_kind(&mut self, kind: ProcessReaderKind) -> Result<(), Error> { + use ProcessReaderKind as K; + self.process_reader = match kind { + K::Unspecified => process_reader::ProcessReader::new(self.pid), + K::VirtualMem => process_reader::ProcessReader::for_virtual_mem(self.pid), + K::File => { + process_reader::ProcessReader::for_file(self.pid).map_err(Error::ProcessReader)? + } + K::Ptrace => process_reader::ProcessReader::for_ptrace(self.pid), + }; + Ok(()) } fn open_file(&self, path: &CStr) -> Result { @@ -392,9 +393,9 @@ impl Drop for DirReader { } #[derive(Debug)] -pub struct ProcessReader(process_reader::ProcessReader); +pub struct ProcessReader<'a>(&'a process_reader::ProcessReader); -impl ProcessReader { +impl<'a> ProcessReader<'a> { pub fn read_at(&self, address: usize, buf: &mut [u8]) -> Result { self.0.read_at(address, buf).map_err(Error::ProcessReader) } diff --git a/src/bin/test.rs b/src/bin/test.rs index 1f7924f9..c5af4870 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -10,7 +10,7 @@ mod linux { super::*, error_graph::ErrorList, minidump_writer::{ - LINUX_GATE_LIBRARY_NAME, + LINUX_GATE_LIBRARY_NAME, ProcessReaderKind, minidump_writer::{MinidumpWriter, MinidumpWriterConfig}, }, std::ptr, @@ -73,7 +73,7 @@ mod linux { use minidump_writer::process_reader::ProcessReader; let ppid = getppid(); - let dumper = fail_on_soft_error!( + let mut dumper = fail_on_soft_error!( soft_errors, MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)? ); @@ -99,23 +99,39 @@ mod linux { // virtual mem { - validate(ProcessReader::for_virtual_mem(&dumper.process_inspector)) + dumper + .process_inspector + .force_process_reader_kind(ProcessReaderKind::VirtualMem) + .unwrap(); + validate(dumper.process_inspector.process_reader()) .map_err(|err| format!("failed to validate memory: {err}"))?; } // file { - let reader = ProcessReader::for_file(&dumper.process_inspector) - .map_err(|err| format!("failed to open `/proc/{ppid}/mem`: {err}"))?; - validate(reader).map_err(|err| format!("failed to validate memory: {err}"))?; + dumper + .process_inspector + .force_process_reader_kind(ProcessReaderKind::File) + .unwrap(); + validate(dumper.process_inspector.process_reader()) + .map_err(|err| format!("failed to validate memory: {err}"))?; } // ptrace { - validate(ProcessReader::for_ptrace(&dumper.process_inspector)) + dumper + .process_inspector + .force_process_reader_kind(ProcessReaderKind::Ptrace) + .unwrap(); + validate(dumper.process_inspector.process_reader()) .map_err(|err| format!("failed to validate memory: {err}"))?; } + dumper + .process_inspector + .force_process_reader_kind(ProcessReaderKind::Unspecified) + .unwrap(); + let stack_res = MinidumpWriter::copy_from_process( &dumper.process_inspector, stack_var, diff --git a/src/linux/mod.rs b/src/linux/mod.rs index b2cf19e8..4141d2a7 100644 --- a/src/linux/mod.rs +++ b/src/linux/mod.rs @@ -3,7 +3,7 @@ pub use { maps_reader::LINUX_GATE_LIBRARY_NAME, - process_inspection::{Error as BackendError, process_reader}, + process_inspection::{Error as BackendError, ProcessReaderKind, process_reader}, }; pub mod app_memory; diff --git a/src/linux/process_inspection/mod.rs b/src/linux/process_inspection/mod.rs index bbcc07ec..b186c2e1 100644 --- a/src/linux/process_inspection/mod.rs +++ b/src/linux/process_inspection/mod.rs @@ -1,9 +1,9 @@ -use self::process_reader::ProcessReader; use super::maps_reader; use crate::module_reader::{ModuleMemoryReadError, ReadError, ReadModuleMemory}; use core::ffi::c_int; use failspot::failspot; use process_backend::{MAX_PATH_LEN, local, regs::*}; +use process_reader::ProcessReader; use std::{ borrow::Cow, ffi::{CString, OsString}, @@ -14,6 +14,8 @@ use std::{ pub use process_backend::regs; +pub use process_backend::ProcessReaderKind; + pub mod process_reader; #[derive(Debug)] @@ -24,23 +26,16 @@ pub struct ProcessInspector { #[derive(Debug)] pub enum Backend { - Local { - backend: local::Backend, - process_reader_backend: local::ProcessReader, - }, + Local { backend: local::Backend }, } impl ProcessInspector { pub fn local(pid: libc::pid_t) -> Self { let backend = local::Backend::new(pid); - let process_reader_backend = backend.process_reader(); ProcessInspector { pid, - backend: Backend::Local { - backend, - process_reader_backend, - }, + backend: Backend::Local { backend }, } } pub fn process_reader(&self) -> ProcessReader<'_> { @@ -161,6 +156,14 @@ impl ProcessInspector { } } } + + pub fn force_process_reader_kind(&mut self, kind: ProcessReaderKind) -> Result<(), Error> { + match &mut self.backend { + Backend::Local { backend, .. } => backend + .force_process_reader_kind(kind) + .map_err(Error::Local), + } + } } #[derive(Debug)] diff --git a/src/linux/process_inspection/process_reader.rs b/src/linux/process_inspection/process_reader.rs index d7cc3bd9..a9f6a856 100644 --- a/src/linux/process_inspection/process_reader.rs +++ b/src/linux/process_inspection/process_reader.rs @@ -4,81 +4,27 @@ use super::{ }; use crate::module_reader::ProcessModuleMemoryReader; -use process_backend::local; - pub type ProcessHandle = libc::pid_t; #[derive(Debug)] pub struct ProcessReader<'a> { process_inspector: &'a ProcessInspector, - forced_backend: Option, -} - -#[derive(Debug)] -enum ForcedBackend { - Local(local::ProcessReader), } impl<'a> ProcessReader<'a> { pub fn new(process_inspector: &'a ProcessInspector) -> Self { - Self { - process_inspector, - forced_backend: None, - } - } - pub fn for_virtual_mem(process_inspector: &'a ProcessInspector) -> Self { - let forced_backend = match &process_inspector.backend { - Backend::Local { backend, .. } => { - ForcedBackend::Local(backend.process_reader_for_virtual_mem()) - } - }; - Self { - process_inspector, - forced_backend: Some(forced_backend), - } - } - pub fn for_file(process_inspector: &'a ProcessInspector) -> Result { - let forced_backend = match &process_inspector.backend { - Backend::Local { backend, .. } => { - ForcedBackend::Local(backend.process_reader_for_file().map_err(Error::Local)?) - } - }; - Ok(Self { - process_inspector, - forced_backend: Some(forced_backend), - }) - } - pub fn for_ptrace(process_inspector: &'a ProcessInspector) -> Self { - let forced_backend = match &process_inspector.backend { - Backend::Local { backend, .. } => { - ForcedBackend::Local(backend.process_reader_for_ptrace()) - } - }; - Self { - process_inspector, - forced_backend: Some(forced_backend), - } + Self { process_inspector } } /// Read memory from the process into the given buffer. /// /// Returns the number of bytes read. pub fn read(&self, src: usize, dst: &mut [u8]) -> Result { - if let Some(forced_backend) = &self.forced_backend { - match forced_backend { - ForcedBackend::Local(process_reader_backend) => process_reader_backend - .read_at(src, dst) - .map_err(Error::Local), - } - } else { - match &self.process_inspector.backend { - Backend::Local { - process_reader_backend, - .. - } => process_reader_backend - .read_at(src, dst) - .map_err(Error::Local), - } + match &self.process_inspector.backend { + Backend::Local { backend } => backend + .process_reader() + .read_at(src, dst) + .map_err(Error::Local), } .map_err(CopyFromProcessError::Backend) }