Skip to main content

minidump_writer/linux/process_inspection/
mod.rs

1use self::process_reader::ProcessReader;
2use super::maps_reader;
3use crate::module_reader::{ModuleMemoryReadError, ReadError, ReadModuleMemory};
4use core::ffi::c_int;
5use failspot::failspot;
6use process_backend::{MAX_PATH_LEN, local, regs::*};
7use std::{
8    borrow::Cow,
9    ffi::{CString, OsString},
10    io,
11    os::unix::ffi::OsStringExt,
12    path::PathBuf,
13};
14
15pub use process_backend::regs;
16
17pub mod process_reader;
18
19#[derive(Debug)]
20pub struct ProcessInspector {
21    pid: libc::pid_t,
22    backend: Backend,
23}
24
25#[derive(Debug)]
26pub enum Backend {
27    Local {
28        backend: local::Backend,
29        process_reader_backend: local::ProcessReader,
30    },
31}
32
33impl ProcessInspector {
34    pub fn local(pid: libc::pid_t) -> Self {
35        let backend = local::Backend::new(pid);
36        let process_reader_backend = backend.process_reader();
37
38        ProcessInspector {
39            pid,
40            backend: Backend::Local {
41                backend,
42                process_reader_backend,
43            },
44        }
45    }
46    pub fn process_reader(&self) -> ProcessReader<'_> {
47        ProcessReader::new(self)
48    }
49    pub fn stop_process(&self) -> Result<(), Error> {
50        failspot!(if StopProcess {
51            return Err(Error::Local(local::Error::SigStopFailed(libc::EPERM)));
52        });
53
54        match &self.backend {
55            Backend::Local { backend, .. } => backend.stop_process().map_err(Error::Local),
56        }
57    }
58
59    pub fn continue_process(&self) -> Result<(), Error> {
60        match &self.backend {
61            Backend::Local { backend, .. } => backend.continue_process().map_err(Error::Local),
62        }
63    }
64
65    pub fn suspend_thread(&self, tid: libc::pid_t) -> Result<(), Error> {
66        match &self.backend {
67            Backend::Local { backend, .. } => backend.suspend_thread(tid).map_err(Error::Local),
68        }
69    }
70
71    pub fn resume_thread(&self, tid: libc::pid_t) -> Result<(), Error> {
72        match &self.backend {
73            Backend::Local { backend, .. } => backend.resume_thread(tid).map_err(Error::Local),
74        }
75    }
76
77    pub fn map_module_into_memory(
78        &self,
79        path: impl Into<PathBuf>,
80        offset: u64,
81    ) -> Result<MappedModuleMemoryReader, Error> {
82        let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
83        match &self.backend {
84            Backend::Local { backend, .. } => backend
85                .map_module_into_memory(&c_path, offset)
86                .map(MappedModuleMemoryReader::Local)
87                .map_err(Error::Local),
88        }
89    }
90
91    pub fn stat_file(&self, path: impl Into<PathBuf>) -> Result<libc::stat, Error> {
92        let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
93        match &self.backend {
94            Backend::Local { backend, .. } => backend.stat_file(&c_path).map_err(Error::Local),
95        }
96    }
97
98    pub fn read_file(&self, path: impl Into<PathBuf>) -> Result<FileReader, Error> {
99        let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
100        match &self.backend {
101            Backend::Local { backend, .. } => backend
102                .read_file(&c_path)
103                .map(FileReader::Local)
104                .map_err(Error::Local),
105        }
106    }
107
108    pub fn read_dir(&self, path: impl Into<PathBuf>) -> Result<DirReader, Error> {
109        let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
110        match &self.backend {
111            Backend::Local { backend, .. } => backend
112                .read_dir(&c_path)
113                .map(DirReader::Local)
114                .map_err(Error::Local),
115        }
116    }
117
118    pub fn read_link(&self, path: impl Into<PathBuf>) -> Result<PathBuf, Error> {
119        let c_path = CString::new(path.into().into_os_string().into_vec()).unwrap();
120
121        let mut buf = vec![0u8; MAX_PATH_LEN];
122
123        let len = match &self.backend {
124            Backend::Local { backend, .. } => {
125                backend.read_link(&c_path, &mut buf).map_err(Error::Local)?
126            }
127        };
128
129        buf.truncate(len);
130        Ok(PathBuf::from(OsString::from_vec(buf)))
131    }
132
133    pub fn get_gen_regs(&self, tid: libc::pid_t) -> Result<GenRegs, Error> {
134        match &self.backend {
135            Backend::Local { backend, .. } => backend.get_gen_regs(tid).map_err(Error::Local),
136        }
137    }
138
139    pub fn get_fp_regs(&self, tid: libc::pid_t) -> Result<FpRegs, Error> {
140        match &self.backend {
141            Backend::Local { backend, .. } => backend.get_fp_regs(tid).map_err(Error::Local),
142        }
143    }
144
145    #[cfg(target_arch = "x86")]
146    pub fn get_fpx_regs(&self, tid: libc::pid_t) -> Result<FpxRegs, Error> {
147        match &self.backend {
148            Backend::Local { backend, .. } => backend.get_fpx_regs(tid).map_err(Error::Local),
149        }
150    }
151
152    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
153    pub fn ptrace_peekuser(
154        &self,
155        pid: libc::pid_t,
156        addr: usize,
157    ) -> Result<[u8; core::mem::size_of::<libc::c_long>()], Error> {
158        match &self.backend {
159            Backend::Local { backend, .. } => {
160                backend.ptrace_peekuser(pid, addr).map_err(Error::Local)
161            }
162        }
163    }
164}
165
166#[derive(Debug)]
167pub enum FileReader {
168    Local(local::FileReader),
169}
170
171impl io::Read for FileReader {
172    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
173        match self {
174            Self::Local(l) => l.read(buf).map_err(Error::Local),
175        }
176        .map_err(io::Error::other)
177    }
178}
179
180#[derive(Debug)]
181pub enum DirReader {
182    Local(local::DirReader),
183}
184
185impl Iterator for DirReader {
186    type Item = Result<OsString, Error>;
187    fn next(&mut self) -> Option<Self::Item> {
188        match self {
189            Self::Local(l) => match l.read_name().map_err(Error::Local) {
190                Ok(Some(name_bytes)) => Some(Ok(OsString::from_vec(name_bytes.to_vec()))),
191                Ok(None) => None,
192                Err(e) => Some(Err(e)),
193            },
194        }
195    }
196}
197
198#[doc(hidden)]
199impl ProcessInspector {
200    pub fn fail_one_syscall_with(&self, errno: c_int) {
201        match &self.backend {
202            Backend::Local { backend, .. } => backend.fail_one_syscall_with(errno),
203        }
204    }
205}
206
207#[derive(Debug)]
208pub enum MappedModuleMemoryReader {
209    Local(local::MappedModuleMemoryReader),
210}
211
212impl MappedModuleMemoryReader {
213    pub fn read(&self, offset: u64, length: u64) -> Result<&[u8], Error> {
214        match self {
215            Self::Local(l) => l.read(offset, length).map_err(Error::Local),
216        }
217    }
218    pub fn len(&self) -> Result<usize, Error> {
219        match self {
220            Self::Local(l) => l.len().map_err(Error::Local),
221        }
222    }
223    pub fn is_empty(&self) -> Result<bool, Error> {
224        match self {
225            Self::Local(l) => l.is_empty().map_err(Error::Local),
226        }
227    }
228}
229
230impl ReadModuleMemory for MappedModuleMemoryReader {
231    fn read(&self, offset: u64, length: u64) -> Result<Cow<'_, [u8]>, ModuleMemoryReadError> {
232        self.read(offset, length)
233            .map(Cow::Borrowed)
234            .map_err(|e| ModuleMemoryReadError {
235                offset,
236                length,
237                start_address: None,
238                error: ReadError::PlatformSpecific(e),
239            })
240    }
241    fn absolute_to_relative(&self, addr: u64) -> Option<u64> {
242        Some(addr)
243    }
244    /// Calculates the absolute address of the specified relative address
245    fn relative_to_absolute(&self, addr: u64) -> Option<u64> {
246        Some(addr)
247    }
248    fn is_process_memory(&self) -> bool {
249        false
250    }
251}
252
253#[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize)]
254pub enum Error {
255    #[error("an error occurred running a syscall directly")]
256    Local(#[source] local::Error),
257}