13da5c369Sopenharmony_ciuse crate::errno::Errno; 23da5c369Sopenharmony_ciuse crate::sys::signal::Signal; 33da5c369Sopenharmony_ciuse crate::unistd::Pid; 43da5c369Sopenharmony_ciuse crate::Result; 53da5c369Sopenharmony_ciuse cfg_if::cfg_if; 63da5c369Sopenharmony_ciuse libc::{self, c_int}; 73da5c369Sopenharmony_ciuse std::ptr; 83da5c369Sopenharmony_ci 93da5c369Sopenharmony_cipub type RequestType = c_int; 103da5c369Sopenharmony_ci 113da5c369Sopenharmony_cicfg_if! { 123da5c369Sopenharmony_ci if #[cfg(any(target_os = "dragonfly", 133da5c369Sopenharmony_ci target_os = "freebsd", 143da5c369Sopenharmony_ci target_os = "macos", 153da5c369Sopenharmony_ci target_os = "openbsd"))] { 163da5c369Sopenharmony_ci #[doc(hidden)] 173da5c369Sopenharmony_ci pub type AddressType = *mut ::libc::c_char; 183da5c369Sopenharmony_ci } else { 193da5c369Sopenharmony_ci #[doc(hidden)] 203da5c369Sopenharmony_ci pub type AddressType = *mut ::libc::c_void; 213da5c369Sopenharmony_ci } 223da5c369Sopenharmony_ci} 233da5c369Sopenharmony_ci 243da5c369Sopenharmony_cilibc_enum! { 253da5c369Sopenharmony_ci #[repr(i32)] 263da5c369Sopenharmony_ci /// Ptrace Request enum defining the action to be taken. 273da5c369Sopenharmony_ci #[non_exhaustive] 283da5c369Sopenharmony_ci pub enum Request { 293da5c369Sopenharmony_ci PT_TRACE_ME, 303da5c369Sopenharmony_ci PT_READ_I, 313da5c369Sopenharmony_ci PT_READ_D, 323da5c369Sopenharmony_ci #[cfg(target_os = "macos")] 333da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 343da5c369Sopenharmony_ci PT_READ_U, 353da5c369Sopenharmony_ci PT_WRITE_I, 363da5c369Sopenharmony_ci PT_WRITE_D, 373da5c369Sopenharmony_ci #[cfg(target_os = "macos")] 383da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 393da5c369Sopenharmony_ci PT_WRITE_U, 403da5c369Sopenharmony_ci PT_CONTINUE, 413da5c369Sopenharmony_ci PT_KILL, 423da5c369Sopenharmony_ci #[cfg(any(any(target_os = "dragonfly", 433da5c369Sopenharmony_ci target_os = "freebsd", 443da5c369Sopenharmony_ci target_os = "macos"), 453da5c369Sopenharmony_ci all(target_os = "openbsd", target_arch = "x86_64"), 463da5c369Sopenharmony_ci all(target_os = "netbsd", any(target_arch = "x86_64", 473da5c369Sopenharmony_ci target_arch = "powerpc"))))] 483da5c369Sopenharmony_ci PT_STEP, 493da5c369Sopenharmony_ci PT_ATTACH, 503da5c369Sopenharmony_ci PT_DETACH, 513da5c369Sopenharmony_ci #[cfg(target_os = "macos")] 523da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 533da5c369Sopenharmony_ci PT_SIGEXC, 543da5c369Sopenharmony_ci #[cfg(target_os = "macos")] 553da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 563da5c369Sopenharmony_ci PT_THUPDATE, 573da5c369Sopenharmony_ci #[cfg(target_os = "macos")] 583da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 593da5c369Sopenharmony_ci PT_ATTACHEXC 603da5c369Sopenharmony_ci } 613da5c369Sopenharmony_ci} 623da5c369Sopenharmony_ci 633da5c369Sopenharmony_ciunsafe fn ptrace_other( 643da5c369Sopenharmony_ci request: Request, 653da5c369Sopenharmony_ci pid: Pid, 663da5c369Sopenharmony_ci addr: AddressType, 673da5c369Sopenharmony_ci data: c_int, 683da5c369Sopenharmony_ci) -> Result<c_int> { 693da5c369Sopenharmony_ci Errno::result(libc::ptrace( 703da5c369Sopenharmony_ci request as RequestType, 713da5c369Sopenharmony_ci libc::pid_t::from(pid), 723da5c369Sopenharmony_ci addr, 733da5c369Sopenharmony_ci data, 743da5c369Sopenharmony_ci )) 753da5c369Sopenharmony_ci .map(|_| 0) 763da5c369Sopenharmony_ci} 773da5c369Sopenharmony_ci 783da5c369Sopenharmony_ci/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` 793da5c369Sopenharmony_ci/// 803da5c369Sopenharmony_ci/// Indicates that this process is to be traced by its parent. 813da5c369Sopenharmony_ci/// This is the only ptrace request to be issued by the tracee. 823da5c369Sopenharmony_cipub fn traceme() -> Result<()> { 833da5c369Sopenharmony_ci unsafe { 843da5c369Sopenharmony_ci ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0) 853da5c369Sopenharmony_ci .map(drop) 863da5c369Sopenharmony_ci } 873da5c369Sopenharmony_ci} 883da5c369Sopenharmony_ci 893da5c369Sopenharmony_ci/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` 903da5c369Sopenharmony_ci/// 913da5c369Sopenharmony_ci/// Attaches to the process specified by `pid`, making it a tracee of the calling process. 923da5c369Sopenharmony_cipub fn attach(pid: Pid) -> Result<()> { 933da5c369Sopenharmony_ci unsafe { 943da5c369Sopenharmony_ci ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) 953da5c369Sopenharmony_ci } 963da5c369Sopenharmony_ci} 973da5c369Sopenharmony_ci 983da5c369Sopenharmony_ci/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` 993da5c369Sopenharmony_ci/// 1003da5c369Sopenharmony_ci/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a 1013da5c369Sopenharmony_ci/// signal specified by `sig`. 1023da5c369Sopenharmony_cipub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 1033da5c369Sopenharmony_ci let data = match sig.into() { 1043da5c369Sopenharmony_ci Some(s) => s as c_int, 1053da5c369Sopenharmony_ci None => 0, 1063da5c369Sopenharmony_ci }; 1073da5c369Sopenharmony_ci unsafe { 1083da5c369Sopenharmony_ci ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop) 1093da5c369Sopenharmony_ci } 1103da5c369Sopenharmony_ci} 1113da5c369Sopenharmony_ci 1123da5c369Sopenharmony_ci/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` 1133da5c369Sopenharmony_ci/// 1143da5c369Sopenharmony_ci/// Continues the execution of the process with PID `pid`, optionally 1153da5c369Sopenharmony_ci/// delivering a signal specified by `sig`. 1163da5c369Sopenharmony_cipub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 1173da5c369Sopenharmony_ci let data = match sig.into() { 1183da5c369Sopenharmony_ci Some(s) => s as c_int, 1193da5c369Sopenharmony_ci None => 0, 1203da5c369Sopenharmony_ci }; 1213da5c369Sopenharmony_ci unsafe { 1223da5c369Sopenharmony_ci // Ignore the useless return value 1233da5c369Sopenharmony_ci ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data) 1243da5c369Sopenharmony_ci .map(drop) 1253da5c369Sopenharmony_ci } 1263da5c369Sopenharmony_ci} 1273da5c369Sopenharmony_ci 1283da5c369Sopenharmony_ci/// Issues a kill request as with `ptrace(PT_KILL, ...)` 1293da5c369Sopenharmony_ci/// 1303da5c369Sopenharmony_ci/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` 1313da5c369Sopenharmony_cipub fn kill(pid: Pid) -> Result<()> { 1323da5c369Sopenharmony_ci unsafe { 1333da5c369Sopenharmony_ci ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) 1343da5c369Sopenharmony_ci } 1353da5c369Sopenharmony_ci} 1363da5c369Sopenharmony_ci 1373da5c369Sopenharmony_ci/// Move the stopped tracee process forward by a single step as with 1383da5c369Sopenharmony_ci/// `ptrace(PT_STEP, ...)` 1393da5c369Sopenharmony_ci/// 1403da5c369Sopenharmony_ci/// Advances the execution of the process with PID `pid` by a single step optionally delivering a 1413da5c369Sopenharmony_ci/// signal specified by `sig`. 1423da5c369Sopenharmony_ci/// 1433da5c369Sopenharmony_ci/// # Example 1443da5c369Sopenharmony_ci/// ```rust 1453da5c369Sopenharmony_ci/// use nix::sys::ptrace::step; 1463da5c369Sopenharmony_ci/// use nix::unistd::Pid; 1473da5c369Sopenharmony_ci/// use nix::sys::signal::Signal; 1483da5c369Sopenharmony_ci/// use nix::sys::wait::*; 1493da5c369Sopenharmony_ci/// // If a process changes state to the stopped state because of a SIGUSR1 1503da5c369Sopenharmony_ci/// // signal, this will step the process forward and forward the user 1513da5c369Sopenharmony_ci/// // signal to the stopped process 1523da5c369Sopenharmony_ci/// match waitpid(Pid::from_raw(-1), None) { 1533da5c369Sopenharmony_ci/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { 1543da5c369Sopenharmony_ci/// let _ = step(pid, Signal::SIGUSR1); 1553da5c369Sopenharmony_ci/// } 1563da5c369Sopenharmony_ci/// _ => {}, 1573da5c369Sopenharmony_ci/// } 1583da5c369Sopenharmony_ci/// ``` 1593da5c369Sopenharmony_ci#[cfg(any( 1603da5c369Sopenharmony_ci any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), 1613da5c369Sopenharmony_ci all(target_os = "openbsd", target_arch = "x86_64"), 1623da5c369Sopenharmony_ci all( 1633da5c369Sopenharmony_ci target_os = "netbsd", 1643da5c369Sopenharmony_ci any(target_arch = "x86_64", target_arch = "powerpc") 1653da5c369Sopenharmony_ci ) 1663da5c369Sopenharmony_ci))] 1673da5c369Sopenharmony_cipub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 1683da5c369Sopenharmony_ci let data = match sig.into() { 1693da5c369Sopenharmony_ci Some(s) => s as c_int, 1703da5c369Sopenharmony_ci None => 0, 1713da5c369Sopenharmony_ci }; 1723da5c369Sopenharmony_ci unsafe { 1733da5c369Sopenharmony_ci ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) 1743da5c369Sopenharmony_ci } 1753da5c369Sopenharmony_ci} 1763da5c369Sopenharmony_ci 1773da5c369Sopenharmony_ci/// Reads a word from a processes memory at the given address 1783da5c369Sopenharmony_ci// Technically, ptrace doesn't dereference the pointer. It passes it directly 1793da5c369Sopenharmony_ci// to the kernel. 1803da5c369Sopenharmony_ci#[allow(clippy::not_unsafe_ptr_arg_deref)] 1813da5c369Sopenharmony_cipub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { 1823da5c369Sopenharmony_ci unsafe { 1833da5c369Sopenharmony_ci // Traditionally there was a difference between reading data or 1843da5c369Sopenharmony_ci // instruction memory but not in modern systems. 1853da5c369Sopenharmony_ci ptrace_other(Request::PT_READ_D, pid, addr, 0) 1863da5c369Sopenharmony_ci } 1873da5c369Sopenharmony_ci} 1883da5c369Sopenharmony_ci 1893da5c369Sopenharmony_ci/// Writes a word into the processes memory at the given address 1903da5c369Sopenharmony_ci// Technically, ptrace doesn't dereference the pointer. It passes it directly 1913da5c369Sopenharmony_ci// to the kernel. 1923da5c369Sopenharmony_ci#[allow(clippy::not_unsafe_ptr_arg_deref)] 1933da5c369Sopenharmony_cipub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { 1943da5c369Sopenharmony_ci unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } 1953da5c369Sopenharmony_ci} 196