minidump_writer/linux/process_inspection/
mod.rs1use 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 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}