Skip to main content

minidump_writer/linux/process_inspection/
process_reader.rs

1use super::{
2    Backend, Error, ProcessInspector,
3    maps_reader::{MappingInfo, MapsReaderError},
4};
5use crate::module_reader::ProcessModuleMemoryReader;
6
7use process_backend::local;
8
9pub type ProcessHandle = libc::pid_t;
10
11#[derive(Debug)]
12pub struct ProcessReader<'a> {
13    process_inspector: &'a ProcessInspector,
14    forced_backend: Option<ForcedBackend>,
15}
16
17#[derive(Debug)]
18enum ForcedBackend {
19    Local(local::ProcessReader),
20}
21
22impl<'a> ProcessReader<'a> {
23    pub fn new(process_inspector: &'a ProcessInspector) -> Self {
24        Self {
25            process_inspector,
26            forced_backend: None,
27        }
28    }
29    pub fn for_virtual_mem(process_inspector: &'a ProcessInspector) -> Self {
30        let forced_backend = match &process_inspector.backend {
31            Backend::Local { backend, .. } => {
32                ForcedBackend::Local(backend.process_reader_for_virtual_mem())
33            }
34        };
35        Self {
36            process_inspector,
37            forced_backend: Some(forced_backend),
38        }
39    }
40    pub fn for_file(process_inspector: &'a ProcessInspector) -> Result<Self, Error> {
41        let forced_backend = match &process_inspector.backend {
42            Backend::Local { backend, .. } => {
43                ForcedBackend::Local(backend.process_reader_for_file().map_err(Error::Local)?)
44            }
45        };
46        Ok(Self {
47            process_inspector,
48            forced_backend: Some(forced_backend),
49        })
50    }
51    pub fn for_ptrace(process_inspector: &'a ProcessInspector) -> Self {
52        let forced_backend = match &process_inspector.backend {
53            Backend::Local { backend, .. } => {
54                ForcedBackend::Local(backend.process_reader_for_ptrace())
55            }
56        };
57        Self {
58            process_inspector,
59            forced_backend: Some(forced_backend),
60        }
61    }
62
63    /// Read memory from the process into the given buffer.
64    ///
65    /// Returns the number of bytes read.
66    pub fn read(&self, src: usize, dst: &mut [u8]) -> Result<usize, CopyFromProcessError> {
67        if let Some(forced_backend) = &self.forced_backend {
68            match forced_backend {
69                ForcedBackend::Local(process_reader_backend) => process_reader_backend
70                    .read_at(src, dst)
71                    .map_err(Error::Local),
72            }
73        } else {
74            match &self.process_inspector.backend {
75                Backend::Local {
76                    process_reader_backend,
77                    ..
78                } => process_reader_backend
79                    .read_at(src, dst)
80                    .map_err(Error::Local),
81            }
82        }
83        .map_err(CopyFromProcessError::Backend)
84    }
85    /// Find the address at which a module with the given name is loaded in the process.
86    pub fn find_module(
87        &self,
88        module_name: &str,
89    ) -> Result<ProcessModuleMemoryReader<'_>, FindModuleError> {
90        MappingInfo::for_pid(self.process_inspector, self.process_inspector.pid, None)?
91            .into_iter()
92            .find_map(|m| {
93                let mmem = ProcessModuleMemoryReader::new(self, m.start_address);
94                let name = m.name.as_ref().and_then(|s| s.to_str())?;
95                if name == module_name {
96                    return Some(mmem);
97                }
98                // Check whether the SO_NAME matches the module name.
99                //
100                // For now, only check the SO_NAME of Android APKS, because libraries may be mapped
101                // directly from within an APK. See bug 1982902.
102                #[cfg(target_os = "android")]
103                if name.ends_with(".apk") {
104                    if let Ok(so_name) = crate::module_reader::read_soname_from_module(&mmem) {
105                        if so_name == name {
106                            return Some(mmem);
107                        }
108                    }
109                }
110
111                None
112            })
113            .ok_or(FindModuleError::ModuleNotFound)
114    }
115}
116
117#[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize)]
118pub enum CopyFromProcessError {
119    #[error("an error occurred calling ProcessReader")]
120    Backend(Error),
121    #[error("an invalid argument was passed")]
122    InvalidArgument,
123}
124
125#[derive(Debug, thiserror::Error, serde::Serialize)]
126pub enum FindModuleError {
127    #[error("Module not found")]
128    ModuleNotFound,
129    #[error("Failed to read process module mappings")]
130    MappingError(#[from] MapsReaderError),
131}