1 use cfg_if::cfg_if; 2 use crate::errno::Errno; 3 use libc::{self, c_int}; 4 use std::ptr; 5 use crate::sys::signal::Signal; 6 use crate::unistd::Pid; 7 use crate::Result; 8 9 pub type RequestType = c_int; 10 11 cfg_if! { 12 if #[cfg(any(target_os = "dragonfly", 13 target_os = "freebsd", 14 target_os = "macos", 15 target_os = "openbsd"))] { 16 #[doc(hidden)] 17 pub type AddressType = *mut ::libc::c_char; 18 } else { 19 #[doc(hidden)] 20 pub type AddressType = *mut ::libc::c_void; 21 } 22 } 23 24 libc_enum! { 25 #[repr(i32)] 26 /// Ptrace Request enum defining the action to be taken. 27 pub enum Request { 28 PT_TRACE_ME, 29 PT_READ_I, 30 PT_READ_D, 31 #[cfg(target_os = "macos")] 32 PT_READ_U, 33 PT_WRITE_I, 34 PT_WRITE_D, 35 #[cfg(target_os = "macos")] 36 PT_WRITE_U, 37 PT_CONTINUE, 38 PT_KILL, 39 #[cfg(any(any(target_os = "dragonfly", 40 target_os = "freebsd", 41 target_os = "macos"), 42 all(target_os = "openbsd", target_arch = "x86_64"), 43 all(target_os = "netbsd", any(target_arch = "x86_64", 44 target_arch = "powerpc"))))] 45 PT_STEP, 46 PT_ATTACH, 47 PT_DETACH, 48 #[cfg(target_os = "macos")] 49 PT_SIGEXC, 50 #[cfg(target_os = "macos")] 51 PT_THUPDATE, 52 #[cfg(target_os = "macos")] 53 PT_ATTACHEXC 54 } 55 } 56 57 unsafe fn ptrace_other( 58 request: Request, 59 pid: Pid, 60 addr: AddressType, 61 data: c_int, 62 ) -> Result<c_int> { 63 Errno::result(libc::ptrace( 64 request as RequestType, 65 libc::pid_t::from(pid), 66 addr, 67 data, 68 )).map(|_| 0) 69 } 70 71 /// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` 72 /// 73 /// Indicates that this process is to be traced by its parent. 74 /// This is the only ptrace request to be issued by the tracee. 75 pub fn traceme() -> Result<()> { 76 unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) } 77 } 78 79 /// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` 80 /// 81 /// Attaches to the process specified by `pid`, making it a tracee of the calling process. 82 pub fn attach(pid: Pid) -> Result<()> { 83 unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) } 84 } 85 86 /// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` 87 /// 88 /// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a 89 /// signal specified by `sig`. 90 pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 91 let data = match sig.into() { 92 Some(s) => s as c_int, 93 None => 0, 94 }; 95 unsafe { 96 ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop) 97 } 98 } 99 100 /// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` 101 /// 102 /// Continues the execution of the process with PID `pid`, optionally 103 /// delivering a signal specified by `sig`. 104 pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 105 let data = match sig.into() { 106 Some(s) => s as c_int, 107 None => 0, 108 }; 109 unsafe { 110 // Ignore the useless return value 111 ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop) 112 } 113 } 114 115 /// Issues a kill request as with `ptrace(PT_KILL, ...)` 116 /// 117 /// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` 118 pub fn kill(pid: Pid) -> Result<()> { 119 unsafe { 120 ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) 121 } 122 } 123 124 /// Move the stopped tracee process forward by a single step as with 125 /// `ptrace(PT_STEP, ...)` 126 /// 127 /// Advances the execution of the process with PID `pid` by a single step optionally delivering a 128 /// signal specified by `sig`. 129 /// 130 /// # Example 131 /// ```rust 132 /// use nix::sys::ptrace::step; 133 /// use nix::unistd::Pid; 134 /// use nix::sys::signal::Signal; 135 /// use nix::sys::wait::*; 136 /// fn main() { 137 /// // If a process changes state to the stopped state because of a SIGUSR1 138 /// // signal, this will step the process forward and forward the user 139 /// // signal to the stopped process 140 /// match waitpid(Pid::from_raw(-1), None) { 141 /// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { 142 /// let _ = step(pid, Signal::SIGUSR1); 143 /// } 144 /// _ => {}, 145 /// } 146 /// } 147 /// ``` 148 #[cfg( 149 any( 150 any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), 151 all(target_os = "openbsd", target_arch = "x86_64"), 152 all(target_os = "netbsd", 153 any(target_arch = "x86_64", target_arch = "powerpc") 154 ) 155 ) 156 )] 157 pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 158 let data = match sig.into() { 159 Some(s) => s as c_int, 160 None => 0, 161 }; 162 unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) } 163 } 164 165 /// Reads a word from a processes memory at the given address 166 pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { 167 unsafe { 168 // Traditionally there was a difference between reading data or 169 // instruction memory but not in modern systems. 170 ptrace_other(Request::PT_READ_D, pid, addr, 0) 171 } 172 } 173 174 /// Writes a word into the processes memory at the given address 175 pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { 176 unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } 177 } 178