1use libc::{c_int, pid_t};
2use mach::kern_return::KERN_SUCCESS;
3use mach::port::{mach_port_name_t, MACH_PORT_NULL};
4use std::process::Child;
5
6use super::{Architecture, CopyAddress, ProcessHandleExt, PutAddress, TryIntoProcessHandle};
7
8pub type Pid = pid_t;
10pub type ProcessHandle = (mach_port_name_t, Architecture);
12
13impl ProcessHandleExt for ProcessHandle {
14 #[must_use]
15 fn check_handle(&self) -> bool {
16 self.0 != 0
17 }
18 #[must_use]
19 fn null_type() -> ProcessHandle {
20 (0, Architecture::from_native())
21 }
22 #[must_use]
23 fn set_arch(self, arch: Architecture) -> Self {
24 (self.0, arch)
25 }
26}
27
28fn task_for_pid(pid: Pid) -> std::io::Result<mach_port_name_t> {
30 let mut task: mach_port_name_t = MACH_PORT_NULL;
31
32 unsafe {
33 let result =
34 mach::traps::task_for_pid(mach::traps::mach_task_self(), pid as c_int, &mut task);
35 if result != KERN_SUCCESS {
36 return Err(std::io::Error::last_os_error());
37 }
38 }
39
40 Ok(task)
41}
42
43impl TryIntoProcessHandle for Pid {
45 fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
46 Ok((task_for_pid(*self)?, Architecture::from_native()))
47 }
48}
49
50impl TryIntoProcessHandle for Child {
52 fn try_into_process_handle(&self) -> std::io::Result<ProcessHandle> {
53 #[allow(clippy::cast_possible_wrap)]
54 Pid::try_into_process_handle(&(self.id() as _))
55 }
56}
57
58impl PutAddress for ProcessHandle {
60 fn put_address(&self, addr: usize, buf: &[u8]) -> std::io::Result<()> {
61 #[allow(clippy::cast_possible_truncation)]
62 let result = unsafe {
63 mach::vm::mach_vm_write(self.0, addr as _, buf.as_ptr() as _, buf.len() as _)
64 };
65 if result != KERN_SUCCESS {
66 return Err(std::io::Error::last_os_error());
67 }
68 Ok(())
69 }
70}
71
72impl CopyAddress for ProcessHandle {
77 #[allow(clippy::inline_always)]
78 #[inline(always)]
79 fn get_pointer_width(&self) -> Architecture {
80 self.1
81 }
82
83 fn copy_address(&self, addr: usize, buf: &mut [u8]) -> std::io::Result<()> {
84 let mut read_len: u64 = 0;
85 let result = unsafe {
86 mach::vm::mach_vm_read_overwrite(
87 self.0,
88 addr as _,
89 buf.len() as _,
90 buf.as_mut_ptr() as _,
91 &mut read_len,
92 )
93 };
94
95 if result != KERN_SUCCESS {
96 return Err(std::io::Error::last_os_error());
97 }
98
99 if read_len == buf.len() as _ {
100 Ok(())
101 } else {
102 Err(std::io::Error::new(
103 std::io::ErrorKind::BrokenPipe,
104 format!(
105 "Mismatched read sizes for `vm_read_overwrite` (expected {}, got {})",
106 buf.len(),
107 read_len
108 ),
109 ))
110 }
111 }
112}