process_memory/
linux.rs

1use libc::{c_void, iovec, pid_t, process_vm_readv, process_vm_writev};
2use std::process::Child;
3
4use super::{Architecture, CopyAddress, ProcessHandleExt, PutAddress, TryIntoProcessHandle};
5
6/// On Linux a `Pid` is just a `libc::pid_t`.
7pub type Pid = pid_t;
8/// On Linux a `ProcessHandle` is just a `libc::pid_t`.
9pub type ProcessHandle = (Pid, Architecture);
10
11impl ProcessHandleExt for ProcessHandle {
12    #[must_use]
13    fn check_handle(&self) -> bool {
14        self.0 != 0
15    }
16    #[must_use]
17    fn null_type() -> Self {
18        (0, Architecture::from_native())
19    }
20    #[must_use]
21    fn set_arch(self, arch: Architecture) -> Self {
22        (self.0, arch)
23    }
24}
25
26/// A `Child` always has a pid, which is all we need on Linux.
27impl TryIntoProcessHandle for Child {
28    fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
29        #[allow(clippy::cast_possible_wrap)]
30        Ok((self.id() as Pid, Architecture::from_native()))
31    }
32}
33
34impl TryIntoProcessHandle for Pid {
35    fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
36        Ok((*self, Architecture::from_native()))
37    }
38}
39
40impl CopyAddress for ProcessHandle {
41    #[allow(clippy::inline_always)]
42    #[inline(always)]
43    fn get_pointer_width(&self) -> Architecture {
44        self.1
45    }
46
47    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> std::io::Result<()> {
48        let local_iov = iovec {
49            iov_base: buf.as_mut_ptr().cast::<c_void>(),
50            iov_len: buf.len(),
51        };
52        let remote_iov = iovec {
53            iov_base: addr as *mut c_void,
54            iov_len: buf.len(),
55        };
56        let result = unsafe { process_vm_readv(self.0, &local_iov, 1, &remote_iov, 1, 0) };
57        if result == -1 {
58            Err(std::io::Error::last_os_error())
59        } else {
60            Ok(())
61        }
62    }
63}
64
65impl PutAddress for ProcessHandle {
66    fn put_address(&self, addr: usize, buf: &[u8]) -> std::io::Result<()> {
67        let local_iov = iovec {
68            iov_base: buf.as_ptr() as *mut c_void,
69            iov_len: buf.len(),
70        };
71        let remote_iov = iovec {
72            iov_base: addr as *mut c_void,
73            iov_len: buf.len(),
74        };
75        let result = unsafe { process_vm_writev(self.0, &local_iov, 1, &remote_iov, 1, 0) };
76        if result == -1 {
77            Err(std::io::Error::last_os_error())
78        } else {
79            Ok(())
80        }
81    }
82}