1#![feature(new_uninit)]
5
6#[cfg(not(target_os = "linux"))]
7compile_error!("libprocmem only supported for Linux targets");
8
9use std::fs::File;
10use std::io::{Seek, SeekFrom, Read};
11use std::mem::MaybeUninit;
12
13pub type Result<T> = std::result::Result<T, Error>;
15
16pub enum Error {
18 OpenMem(usize, std::io::Error),
20
21 ReadMem(usize, std::io::Error),
23
24 ReadMaps(usize, std::io::Error),
26
27 InvalidString(usize, std::string::FromUtf8Error),
29
30 ParseMaps(usize),
32}
33
34impl std::fmt::Debug for Error {
35 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36 match self {
37 Error::OpenMem(pid, e) =>
38 write!(f, "Failed to open memory for pid {pid}: {e}")?,
39 Error::ReadMem(pid, e) =>
40 write!(f, "Failed to read memory for pid {pid}: {e}")?,
41 Error::ReadMaps(pid, e) =>
42 write!(f, "Failed to read maps for pid {pid}: {e}")?,
43 Error::InvalidString(pid, e) =>
44 write!(f, "Failed to convert bytes to UTF-8 data \
45 for pid {pid}: {e}")?,
46 Error::ParseMaps(pid) =>
47 write!(f, "Failed to parse maps for pid {pid}")?,
48 }
49
50 Ok(())
51 }
52}
53
54pub struct Memory {
56 pid: usize,
58
59 mem: File,
61}
62
63pub struct Mapping {
65 pub base: u64,
67
68 pub end: u64,
71
72 pub r: bool,
74
75 pub w: bool,
77
78 pub x: bool,
80}
81
82impl Memory {
83 pub fn pid(pid: usize) -> Result<Self> {
85 let mem = File::open(format!("/proc/{}/mem", pid))
87 .map_err(|x| Error::OpenMem(pid, x))?;
88
89 Ok(Self {
90 pid,
91 mem,
92 })
93 }
94
95 pub fn read_nul_string(&mut self, addr: u64) -> Result<String> {
99 let mut bytes = Vec::new();
101
102 for addr in addr.. {
105 let byte = self.read::<u8>(addr)?;
106 if byte == 0 {
107 break;
108 }
109
110 bytes.push(byte);
111 }
112
113 Ok(String::from_utf8(bytes).map_err(|x| {
115 Error::InvalidString(self.pid, x)
116 })?)
117 }
118
119 pub fn query_address_space(&mut self) -> Result<Vec<Mapping>> {
121 let mut ret = Vec::new();
123
124 let maps = std::fs::read_to_string(
126 format!("/proc/{}/maps", self.pid))
127 .map_err(|x| Error::ReadMaps(self.pid, x))?;
128
129 for line in maps.lines() {
130 let mut spl = line.split(" ");
132 let addr_range = spl.next()
133 .ok_or(Error::ParseMaps(self.pid))?;
134 let perms = spl.next()
135 .ok_or(Error::ParseMaps(self.pid))?;
136
137 let mut spl = addr_range.split("-");
139 let base = u64::from_str_radix(spl.next()
140 .ok_or(Error::ParseMaps(self.pid))?, 16)
141 .map_err(|_| Error::ParseMaps(self.pid))?;
142 let end = u64::from_str_radix(spl.next()
143 .ok_or(Error::ParseMaps(self.pid))?, 16)
144 .map_err(|_| Error::ParseMaps(self.pid))?;
145
146 let r = perms.get(0..1) == Some("r");
148 let w = perms.get(1..2) == Some("w");
149 let x = perms.get(2..3) == Some("x");
150
151 ret.push(Mapping { base, end, r, w, x });
153 }
154
155 Ok(ret)
156 }
157
158 pub fn read<T: Pod>(&mut self, addr: u64) -> Result<T> {
160 let mut ret: MaybeUninit<T> = MaybeUninit::uninit();
162
163 self.mem.seek(SeekFrom::Start(addr))
165 .map_err(|x| Error::ReadMem(self.pid, x))?;
166
167 let ptr = unsafe {
169 core::slice::from_raw_parts_mut(
170 ret.as_mut_ptr() as *mut u8, core::mem::size_of_val(&ret))
171 };
172 self.mem.read_exact(ptr)
173 .map_err(|x| Error::ReadMem(self.pid, x))?;
174
175 Ok(unsafe { ret.assume_init() })
176 }
177
178 pub fn read_slice<T: Pod>(&mut self, addr: u64, elements: usize)
180 -> Result<Box<[T]>> {
181 let mut ret: Box<[MaybeUninit<T>]> = Box::new_uninit_slice(elements);
183
184 self.mem.seek(SeekFrom::Start(addr))
186 .map_err(|x| Error::ReadMem(self.pid, x))?;
187
188 let ptr = unsafe {
190 core::slice::from_raw_parts_mut(
191 ret.as_mut_ptr() as *mut u8, core::mem::size_of_val(&*ret))
192 };
193 self.mem.read_exact(ptr)
194 .map_err(|x| Error::ReadMem(self.pid, x))?;
195
196 Ok(unsafe { ret.assume_init() })
197 }
198}
199
200pub unsafe trait Pod: Copy + Sync + Send + 'static {}
206
207unsafe impl Pod for i8 {}
208unsafe impl Pod for i16 {}
209unsafe impl Pod for i32 {}
210unsafe impl Pod for i64 {}
211unsafe impl Pod for i128 {}
212unsafe impl Pod for isize {}
213unsafe impl Pod for u8 {}
214unsafe impl Pod for u16 {}
215unsafe impl Pod for u32 {}
216unsafe impl Pod for u64 {}
217unsafe impl Pod for u128 {}
218unsafe impl Pod for usize {}
219unsafe impl Pod for f32 {}
220unsafe impl Pod for f64 {}
221
222unsafe impl<const N: usize> Pod for [i8; N] {}
223unsafe impl<const N: usize> Pod for [i16; N] {}
224unsafe impl<const N: usize> Pod for [i32; N] {}
225unsafe impl<const N: usize> Pod for [i64; N] {}
226unsafe impl<const N: usize> Pod for [i128; N] {}
227unsafe impl<const N: usize> Pod for [isize; N] {}
228unsafe impl<const N: usize> Pod for [u8; N] {}
229unsafe impl<const N: usize> Pod for [u16; N] {}
230unsafe impl<const N: usize> Pod for [u32; N] {}
231unsafe impl<const N: usize> Pod for [u64; N] {}
232unsafe impl<const N: usize> Pod for [u128; N] {}
233unsafe impl<const N: usize> Pod for [usize; N] {}
234unsafe impl<const N: usize> Pod for [f32; N] {}
235unsafe impl<const N: usize> Pod for [f64; N] {}
236