13da5c369Sopenharmony_ci//! For detailed description of the ptrace requests, consult `man ptrace`. 23da5c369Sopenharmony_ci 33da5c369Sopenharmony_ciuse crate::errno::Errno; 43da5c369Sopenharmony_ciuse crate::sys::signal::Signal; 53da5c369Sopenharmony_ciuse crate::unistd::Pid; 63da5c369Sopenharmony_ciuse crate::Result; 73da5c369Sopenharmony_ciuse cfg_if::cfg_if; 83da5c369Sopenharmony_ciuse libc::{self, c_long, c_void, siginfo_t}; 93da5c369Sopenharmony_ciuse std::{mem, ptr}; 103da5c369Sopenharmony_ci 113da5c369Sopenharmony_cipub type AddressType = *mut ::libc::c_void; 123da5c369Sopenharmony_ci 133da5c369Sopenharmony_ci#[cfg(all( 143da5c369Sopenharmony_ci target_os = "linux", 153da5c369Sopenharmony_ci any( 163da5c369Sopenharmony_ci all( 173da5c369Sopenharmony_ci target_arch = "x86_64", 183da5c369Sopenharmony_ci any(target_env = "gnu", target_env = "musl", target_env = "ohos") 193da5c369Sopenharmony_ci ), 203da5c369Sopenharmony_ci all(target_arch = "x86", target_env = "gnu") 213da5c369Sopenharmony_ci ) 223da5c369Sopenharmony_ci))] 233da5c369Sopenharmony_ciuse libc::user_regs_struct; 243da5c369Sopenharmony_ci 253da5c369Sopenharmony_cicfg_if! { 263da5c369Sopenharmony_ci if #[cfg(any(all(target_os = "linux", target_arch = "s390x"), 273da5c369Sopenharmony_ci all(target_os = "linux", target_env = "gnu"), 283da5c369Sopenharmony_ci target_env = "uclibc"))] { 293da5c369Sopenharmony_ci #[doc(hidden)] 303da5c369Sopenharmony_ci pub type RequestType = ::libc::c_uint; 313da5c369Sopenharmony_ci } else { 323da5c369Sopenharmony_ci #[doc(hidden)] 333da5c369Sopenharmony_ci pub type RequestType = ::libc::c_int; 343da5c369Sopenharmony_ci } 353da5c369Sopenharmony_ci} 363da5c369Sopenharmony_ci 373da5c369Sopenharmony_cilibc_enum! { 383da5c369Sopenharmony_ci #[cfg_attr(not(any(target_env = "musl", target_env = "ohos", target_env = "uclibc", target_os = "android")), repr(u32))] 393da5c369Sopenharmony_ci #[cfg_attr(any(target_env = "musl", target_env = "ohos", target_env = "uclibc", target_os = "android"), repr(i32))] 403da5c369Sopenharmony_ci /// Ptrace Request enum defining the action to be taken. 413da5c369Sopenharmony_ci #[non_exhaustive] 423da5c369Sopenharmony_ci pub enum Request { 433da5c369Sopenharmony_ci PTRACE_TRACEME, 443da5c369Sopenharmony_ci PTRACE_PEEKTEXT, 453da5c369Sopenharmony_ci PTRACE_PEEKDATA, 463da5c369Sopenharmony_ci PTRACE_PEEKUSER, 473da5c369Sopenharmony_ci PTRACE_POKETEXT, 483da5c369Sopenharmony_ci PTRACE_POKEDATA, 493da5c369Sopenharmony_ci PTRACE_POKEUSER, 503da5c369Sopenharmony_ci PTRACE_CONT, 513da5c369Sopenharmony_ci PTRACE_KILL, 523da5c369Sopenharmony_ci PTRACE_SINGLESTEP, 533da5c369Sopenharmony_ci #[cfg(any(all(target_os = "android", target_pointer_width = "32"), 543da5c369Sopenharmony_ci all(target_os = "linux", any(target_env = "musl", 553da5c369Sopenharmony_ci target_env = "ohos", 563da5c369Sopenharmony_ci target_arch = "mips", 573da5c369Sopenharmony_ci target_arch = "mips64", 583da5c369Sopenharmony_ci target_arch = "x86_64", 593da5c369Sopenharmony_ci target_pointer_width = "32"))))] 603da5c369Sopenharmony_ci PTRACE_GETREGS, 613da5c369Sopenharmony_ci #[cfg(any(all(target_os = "android", target_pointer_width = "32"), 623da5c369Sopenharmony_ci all(target_os = "linux", any(target_env = "musl", 633da5c369Sopenharmony_ci target_env = "ohos", 643da5c369Sopenharmony_ci target_arch = "mips", 653da5c369Sopenharmony_ci target_arch = "mips64", 663da5c369Sopenharmony_ci target_arch = "x86_64", 673da5c369Sopenharmony_ci target_pointer_width = "32"))))] 683da5c369Sopenharmony_ci PTRACE_SETREGS, 693da5c369Sopenharmony_ci #[cfg(any(all(target_os = "android", target_pointer_width = "32"), 703da5c369Sopenharmony_ci all(target_os = "linux", any(target_env = "musl", 713da5c369Sopenharmony_ci target_env = "ohos", 723da5c369Sopenharmony_ci target_arch = "mips", 733da5c369Sopenharmony_ci target_arch = "mips64", 743da5c369Sopenharmony_ci target_arch = "x86_64", 753da5c369Sopenharmony_ci target_pointer_width = "32"))))] 763da5c369Sopenharmony_ci PTRACE_GETFPREGS, 773da5c369Sopenharmony_ci #[cfg(any(all(target_os = "android", target_pointer_width = "32"), 783da5c369Sopenharmony_ci all(target_os = "linux", any(target_env = "musl", 793da5c369Sopenharmony_ci target_env = "ohos", 803da5c369Sopenharmony_ci target_arch = "mips", 813da5c369Sopenharmony_ci target_arch = "mips64", 823da5c369Sopenharmony_ci target_arch = "x86_64", 833da5c369Sopenharmony_ci target_pointer_width = "32"))))] 843da5c369Sopenharmony_ci PTRACE_SETFPREGS, 853da5c369Sopenharmony_ci PTRACE_ATTACH, 863da5c369Sopenharmony_ci PTRACE_DETACH, 873da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", any(target_env = "musl", 883da5c369Sopenharmony_ci target_env = "ohos", 893da5c369Sopenharmony_ci target_arch = "mips", 903da5c369Sopenharmony_ci target_arch = "mips64", 913da5c369Sopenharmony_ci target_arch = "x86", 923da5c369Sopenharmony_ci target_arch = "x86_64")))] 933da5c369Sopenharmony_ci PTRACE_GETFPXREGS, 943da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", any(target_env = "musl", 953da5c369Sopenharmony_ci target_env = "ohos", 963da5c369Sopenharmony_ci target_arch = "mips", 973da5c369Sopenharmony_ci target_arch = "mips64", 983da5c369Sopenharmony_ci target_arch = "x86", 993da5c369Sopenharmony_ci target_arch = "x86_64")))] 1003da5c369Sopenharmony_ci PTRACE_SETFPXREGS, 1013da5c369Sopenharmony_ci PTRACE_SYSCALL, 1023da5c369Sopenharmony_ci PTRACE_SETOPTIONS, 1033da5c369Sopenharmony_ci PTRACE_GETEVENTMSG, 1043da5c369Sopenharmony_ci PTRACE_GETSIGINFO, 1053da5c369Sopenharmony_ci PTRACE_SETSIGINFO, 1063da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", not(any(target_arch = "mips", 1073da5c369Sopenharmony_ci target_arch = "mips64"))))] 1083da5c369Sopenharmony_ci PTRACE_GETREGSET, 1093da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", not(any(target_arch = "mips", 1103da5c369Sopenharmony_ci target_arch = "mips64"))))] 1113da5c369Sopenharmony_ci PTRACE_SETREGSET, 1123da5c369Sopenharmony_ci #[cfg(target_os = "linux")] 1133da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1143da5c369Sopenharmony_ci PTRACE_SEIZE, 1153da5c369Sopenharmony_ci #[cfg(target_os = "linux")] 1163da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1173da5c369Sopenharmony_ci PTRACE_INTERRUPT, 1183da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", not(any(target_arch = "mips", 1193da5c369Sopenharmony_ci target_arch = "mips64"))))] 1203da5c369Sopenharmony_ci PTRACE_LISTEN, 1213da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", not(any(target_arch = "mips", 1223da5c369Sopenharmony_ci target_arch = "mips64"))))] 1233da5c369Sopenharmony_ci PTRACE_PEEKSIGINFO, 1243da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", target_env = "gnu", 1253da5c369Sopenharmony_ci any(target_arch = "x86", target_arch = "x86_64")))] 1263da5c369Sopenharmony_ci PTRACE_SYSEMU, 1273da5c369Sopenharmony_ci #[cfg(all(target_os = "linux", target_env = "gnu", 1283da5c369Sopenharmony_ci any(target_arch = "x86", target_arch = "x86_64")))] 1293da5c369Sopenharmony_ci PTRACE_SYSEMU_SINGLESTEP, 1303da5c369Sopenharmony_ci } 1313da5c369Sopenharmony_ci} 1323da5c369Sopenharmony_ci 1333da5c369Sopenharmony_cilibc_enum! { 1343da5c369Sopenharmony_ci #[repr(i32)] 1353da5c369Sopenharmony_ci /// Using the ptrace options the tracer can configure the tracee to stop 1363da5c369Sopenharmony_ci /// at certain events. This enum is used to define those events as defined 1373da5c369Sopenharmony_ci /// in `man ptrace`. 1383da5c369Sopenharmony_ci #[non_exhaustive] 1393da5c369Sopenharmony_ci pub enum Event { 1403da5c369Sopenharmony_ci /// Event that stops before a return from fork or clone. 1413da5c369Sopenharmony_ci PTRACE_EVENT_FORK, 1423da5c369Sopenharmony_ci /// Event that stops before a return from vfork or clone. 1433da5c369Sopenharmony_ci PTRACE_EVENT_VFORK, 1443da5c369Sopenharmony_ci /// Event that stops before a return from clone. 1453da5c369Sopenharmony_ci PTRACE_EVENT_CLONE, 1463da5c369Sopenharmony_ci /// Event that stops before a return from execve. 1473da5c369Sopenharmony_ci PTRACE_EVENT_EXEC, 1483da5c369Sopenharmony_ci /// Event for a return from vfork. 1493da5c369Sopenharmony_ci PTRACE_EVENT_VFORK_DONE, 1503da5c369Sopenharmony_ci /// Event for a stop before an exit. Unlike the waitpid Exit status program. 1513da5c369Sopenharmony_ci /// registers can still be examined 1523da5c369Sopenharmony_ci PTRACE_EVENT_EXIT, 1533da5c369Sopenharmony_ci /// Stop triggered by a seccomp rule on a tracee. 1543da5c369Sopenharmony_ci PTRACE_EVENT_SECCOMP, 1553da5c369Sopenharmony_ci /// Stop triggered by the `INTERRUPT` syscall, or a group stop, 1563da5c369Sopenharmony_ci /// or when a new child is attached. 1573da5c369Sopenharmony_ci PTRACE_EVENT_STOP, 1583da5c369Sopenharmony_ci } 1593da5c369Sopenharmony_ci} 1603da5c369Sopenharmony_ci 1613da5c369Sopenharmony_cilibc_bitflags! { 1623da5c369Sopenharmony_ci /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. 1633da5c369Sopenharmony_ci /// See `man ptrace` for more details. 1643da5c369Sopenharmony_ci pub struct Options: libc::c_int { 1653da5c369Sopenharmony_ci /// When delivering system call traps set a bit to allow tracer to 1663da5c369Sopenharmony_ci /// distinguish between normal stops or syscall stops. May not work on 1673da5c369Sopenharmony_ci /// all systems. 1683da5c369Sopenharmony_ci PTRACE_O_TRACESYSGOOD; 1693da5c369Sopenharmony_ci /// Stop tracee at next fork and start tracing the forked process. 1703da5c369Sopenharmony_ci PTRACE_O_TRACEFORK; 1713da5c369Sopenharmony_ci /// Stop tracee at next vfork call and trace the vforked process. 1723da5c369Sopenharmony_ci PTRACE_O_TRACEVFORK; 1733da5c369Sopenharmony_ci /// Stop tracee at next clone call and trace the cloned process. 1743da5c369Sopenharmony_ci PTRACE_O_TRACECLONE; 1753da5c369Sopenharmony_ci /// Stop tracee at next execve call. 1763da5c369Sopenharmony_ci PTRACE_O_TRACEEXEC; 1773da5c369Sopenharmony_ci /// Stop tracee at vfork completion. 1783da5c369Sopenharmony_ci PTRACE_O_TRACEVFORKDONE; 1793da5c369Sopenharmony_ci /// Stop tracee at next exit call. Stops before exit commences allowing 1803da5c369Sopenharmony_ci /// tracer to see location of exit and register states. 1813da5c369Sopenharmony_ci PTRACE_O_TRACEEXIT; 1823da5c369Sopenharmony_ci /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more 1833da5c369Sopenharmony_ci /// details. 1843da5c369Sopenharmony_ci PTRACE_O_TRACESECCOMP; 1853da5c369Sopenharmony_ci /// Send a SIGKILL to the tracee if the tracer exits. This is useful 1863da5c369Sopenharmony_ci /// for ptrace jailers to prevent tracees from escaping their control. 1873da5c369Sopenharmony_ci PTRACE_O_EXITKILL; 1883da5c369Sopenharmony_ci } 1893da5c369Sopenharmony_ci} 1903da5c369Sopenharmony_ci 1913da5c369Sopenharmony_cifn ptrace_peek( 1923da5c369Sopenharmony_ci request: Request, 1933da5c369Sopenharmony_ci pid: Pid, 1943da5c369Sopenharmony_ci addr: AddressType, 1953da5c369Sopenharmony_ci data: *mut c_void, 1963da5c369Sopenharmony_ci) -> Result<c_long> { 1973da5c369Sopenharmony_ci let ret = unsafe { 1983da5c369Sopenharmony_ci Errno::clear(); 1993da5c369Sopenharmony_ci libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) 2003da5c369Sopenharmony_ci }; 2013da5c369Sopenharmony_ci match Errno::result(ret) { 2023da5c369Sopenharmony_ci Ok(..) | Err(Errno::UnknownErrno) => Ok(ret), 2033da5c369Sopenharmony_ci err @ Err(..) => err, 2043da5c369Sopenharmony_ci } 2053da5c369Sopenharmony_ci} 2063da5c369Sopenharmony_ci 2073da5c369Sopenharmony_ci/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` 2083da5c369Sopenharmony_ci#[cfg(all( 2093da5c369Sopenharmony_ci target_os = "linux", 2103da5c369Sopenharmony_ci any( 2113da5c369Sopenharmony_ci all( 2123da5c369Sopenharmony_ci target_arch = "x86_64", 2133da5c369Sopenharmony_ci any(target_env = "gnu", target_env = "musl", target_env = "ohos") 2143da5c369Sopenharmony_ci ), 2153da5c369Sopenharmony_ci all(target_arch = "x86", target_env = "gnu") 2163da5c369Sopenharmony_ci ) 2173da5c369Sopenharmony_ci))] 2183da5c369Sopenharmony_cipub fn getregs(pid: Pid) -> Result<user_regs_struct> { 2193da5c369Sopenharmony_ci ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid) 2203da5c369Sopenharmony_ci} 2213da5c369Sopenharmony_ci 2223da5c369Sopenharmony_ci/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` 2233da5c369Sopenharmony_ci#[cfg(all( 2243da5c369Sopenharmony_ci target_os = "linux", 2253da5c369Sopenharmony_ci any( 2263da5c369Sopenharmony_ci all( 2273da5c369Sopenharmony_ci target_arch = "x86_64", 2283da5c369Sopenharmony_ci any(target_env = "gnu", target_env = "musl", target_env = "ohos") 2293da5c369Sopenharmony_ci ), 2303da5c369Sopenharmony_ci all(target_arch = "x86", target_env = "gnu") 2313da5c369Sopenharmony_ci ) 2323da5c369Sopenharmony_ci))] 2333da5c369Sopenharmony_cipub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { 2343da5c369Sopenharmony_ci let res = unsafe { 2353da5c369Sopenharmony_ci libc::ptrace( 2363da5c369Sopenharmony_ci Request::PTRACE_SETREGS as RequestType, 2373da5c369Sopenharmony_ci libc::pid_t::from(pid), 2383da5c369Sopenharmony_ci ptr::null_mut::<c_void>(), 2393da5c369Sopenharmony_ci ®s as *const _ as *const c_void, 2403da5c369Sopenharmony_ci ) 2413da5c369Sopenharmony_ci }; 2423da5c369Sopenharmony_ci Errno::result(res).map(drop) 2433da5c369Sopenharmony_ci} 2443da5c369Sopenharmony_ci 2453da5c369Sopenharmony_ci/// Function for ptrace requests that return values from the data field. 2463da5c369Sopenharmony_ci/// Some ptrace get requests populate structs or larger elements than `c_long` 2473da5c369Sopenharmony_ci/// and therefore use the data field to return values. This function handles these 2483da5c369Sopenharmony_ci/// requests. 2493da5c369Sopenharmony_cifn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { 2503da5c369Sopenharmony_ci let mut data = mem::MaybeUninit::uninit(); 2513da5c369Sopenharmony_ci let res = unsafe { 2523da5c369Sopenharmony_ci libc::ptrace( 2533da5c369Sopenharmony_ci request as RequestType, 2543da5c369Sopenharmony_ci libc::pid_t::from(pid), 2553da5c369Sopenharmony_ci ptr::null_mut::<T>(), 2563da5c369Sopenharmony_ci data.as_mut_ptr() as *const _ as *const c_void, 2573da5c369Sopenharmony_ci ) 2583da5c369Sopenharmony_ci }; 2593da5c369Sopenharmony_ci Errno::result(res)?; 2603da5c369Sopenharmony_ci Ok(unsafe { data.assume_init() }) 2613da5c369Sopenharmony_ci} 2623da5c369Sopenharmony_ci 2633da5c369Sopenharmony_ciunsafe fn ptrace_other( 2643da5c369Sopenharmony_ci request: Request, 2653da5c369Sopenharmony_ci pid: Pid, 2663da5c369Sopenharmony_ci addr: AddressType, 2673da5c369Sopenharmony_ci data: *mut c_void, 2683da5c369Sopenharmony_ci) -> Result<c_long> { 2693da5c369Sopenharmony_ci Errno::result(libc::ptrace( 2703da5c369Sopenharmony_ci request as RequestType, 2713da5c369Sopenharmony_ci libc::pid_t::from(pid), 2723da5c369Sopenharmony_ci addr, 2733da5c369Sopenharmony_ci data, 2743da5c369Sopenharmony_ci )) 2753da5c369Sopenharmony_ci .map(|_| 0) 2763da5c369Sopenharmony_ci} 2773da5c369Sopenharmony_ci 2783da5c369Sopenharmony_ci/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. 2793da5c369Sopenharmony_cipub fn setoptions(pid: Pid, options: Options) -> Result<()> { 2803da5c369Sopenharmony_ci let res = unsafe { 2813da5c369Sopenharmony_ci libc::ptrace( 2823da5c369Sopenharmony_ci Request::PTRACE_SETOPTIONS as RequestType, 2833da5c369Sopenharmony_ci libc::pid_t::from(pid), 2843da5c369Sopenharmony_ci ptr::null_mut::<c_void>(), 2853da5c369Sopenharmony_ci options.bits() as *mut c_void, 2863da5c369Sopenharmony_ci ) 2873da5c369Sopenharmony_ci }; 2883da5c369Sopenharmony_ci Errno::result(res).map(drop) 2893da5c369Sopenharmony_ci} 2903da5c369Sopenharmony_ci 2913da5c369Sopenharmony_ci/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` 2923da5c369Sopenharmony_cipub fn getevent(pid: Pid) -> Result<c_long> { 2933da5c369Sopenharmony_ci ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid) 2943da5c369Sopenharmony_ci} 2953da5c369Sopenharmony_ci 2963da5c369Sopenharmony_ci/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` 2973da5c369Sopenharmony_cipub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { 2983da5c369Sopenharmony_ci ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid) 2993da5c369Sopenharmony_ci} 3003da5c369Sopenharmony_ci 3013da5c369Sopenharmony_ci/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` 3023da5c369Sopenharmony_cipub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { 3033da5c369Sopenharmony_ci let ret = unsafe { 3043da5c369Sopenharmony_ci Errno::clear(); 3053da5c369Sopenharmony_ci libc::ptrace( 3063da5c369Sopenharmony_ci Request::PTRACE_SETSIGINFO as RequestType, 3073da5c369Sopenharmony_ci libc::pid_t::from(pid), 3083da5c369Sopenharmony_ci ptr::null_mut::<c_void>(), 3093da5c369Sopenharmony_ci sig as *const _ as *const c_void, 3103da5c369Sopenharmony_ci ) 3113da5c369Sopenharmony_ci }; 3123da5c369Sopenharmony_ci match Errno::result(ret) { 3133da5c369Sopenharmony_ci Ok(_) => Ok(()), 3143da5c369Sopenharmony_ci Err(e) => Err(e), 3153da5c369Sopenharmony_ci } 3163da5c369Sopenharmony_ci} 3173da5c369Sopenharmony_ci 3183da5c369Sopenharmony_ci/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` 3193da5c369Sopenharmony_ci/// 3203da5c369Sopenharmony_ci/// Indicates that this process is to be traced by its parent. 3213da5c369Sopenharmony_ci/// This is the only ptrace request to be issued by the tracee. 3223da5c369Sopenharmony_cipub fn traceme() -> Result<()> { 3233da5c369Sopenharmony_ci unsafe { 3243da5c369Sopenharmony_ci ptrace_other( 3253da5c369Sopenharmony_ci Request::PTRACE_TRACEME, 3263da5c369Sopenharmony_ci Pid::from_raw(0), 3273da5c369Sopenharmony_ci ptr::null_mut(), 3283da5c369Sopenharmony_ci ptr::null_mut(), 3293da5c369Sopenharmony_ci ) 3303da5c369Sopenharmony_ci .map(drop) // ignore the useless return value 3313da5c369Sopenharmony_ci } 3323da5c369Sopenharmony_ci} 3333da5c369Sopenharmony_ci 3343da5c369Sopenharmony_ci/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` 3353da5c369Sopenharmony_ci/// 3363da5c369Sopenharmony_ci/// Arranges for the tracee to be stopped at the next entry to or exit from a system call, 3373da5c369Sopenharmony_ci/// optionally delivering a signal specified by `sig`. 3383da5c369Sopenharmony_cipub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 3393da5c369Sopenharmony_ci let data = match sig.into() { 3403da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 3413da5c369Sopenharmony_ci None => ptr::null_mut(), 3423da5c369Sopenharmony_ci }; 3433da5c369Sopenharmony_ci unsafe { 3443da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data) 3453da5c369Sopenharmony_ci .map(drop) // ignore the useless return value 3463da5c369Sopenharmony_ci } 3473da5c369Sopenharmony_ci} 3483da5c369Sopenharmony_ci 3493da5c369Sopenharmony_ci/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` 3503da5c369Sopenharmony_ci/// 3513da5c369Sopenharmony_ci/// In contrast to the `syscall` function, the syscall stopped at will not be executed. 3523da5c369Sopenharmony_ci/// Thus the the tracee will only be stopped once per syscall, 3533da5c369Sopenharmony_ci/// optionally delivering a signal specified by `sig`. 3543da5c369Sopenharmony_ci#[cfg(all( 3553da5c369Sopenharmony_ci target_os = "linux", 3563da5c369Sopenharmony_ci target_env = "gnu", 3573da5c369Sopenharmony_ci any(target_arch = "x86", target_arch = "x86_64") 3583da5c369Sopenharmony_ci))] 3593da5c369Sopenharmony_cipub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 3603da5c369Sopenharmony_ci let data = match sig.into() { 3613da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 3623da5c369Sopenharmony_ci None => ptr::null_mut(), 3633da5c369Sopenharmony_ci }; 3643da5c369Sopenharmony_ci unsafe { 3653da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data) 3663da5c369Sopenharmony_ci .map(drop) 3673da5c369Sopenharmony_ci // ignore the useless return value 3683da5c369Sopenharmony_ci } 3693da5c369Sopenharmony_ci} 3703da5c369Sopenharmony_ci 3713da5c369Sopenharmony_ci/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` 3723da5c369Sopenharmony_ci/// 3733da5c369Sopenharmony_ci/// Attaches to the process specified by `pid`, making it a tracee of the calling process. 3743da5c369Sopenharmony_cipub fn attach(pid: Pid) -> Result<()> { 3753da5c369Sopenharmony_ci unsafe { 3763da5c369Sopenharmony_ci ptrace_other( 3773da5c369Sopenharmony_ci Request::PTRACE_ATTACH, 3783da5c369Sopenharmony_ci pid, 3793da5c369Sopenharmony_ci ptr::null_mut(), 3803da5c369Sopenharmony_ci ptr::null_mut(), 3813da5c369Sopenharmony_ci ) 3823da5c369Sopenharmony_ci .map(drop) // ignore the useless return value 3833da5c369Sopenharmony_ci } 3843da5c369Sopenharmony_ci} 3853da5c369Sopenharmony_ci 3863da5c369Sopenharmony_ci/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` 3873da5c369Sopenharmony_ci/// 3883da5c369Sopenharmony_ci/// Attaches to the process specified in pid, making it a tracee of the calling process. 3893da5c369Sopenharmony_ci#[cfg(target_os = "linux")] 3903da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 3913da5c369Sopenharmony_cipub fn seize(pid: Pid, options: Options) -> Result<()> { 3923da5c369Sopenharmony_ci unsafe { 3933da5c369Sopenharmony_ci ptrace_other( 3943da5c369Sopenharmony_ci Request::PTRACE_SEIZE, 3953da5c369Sopenharmony_ci pid, 3963da5c369Sopenharmony_ci ptr::null_mut(), 3973da5c369Sopenharmony_ci options.bits() as *mut c_void, 3983da5c369Sopenharmony_ci ) 3993da5c369Sopenharmony_ci .map(drop) // ignore the useless return value 4003da5c369Sopenharmony_ci } 4013da5c369Sopenharmony_ci} 4023da5c369Sopenharmony_ci 4033da5c369Sopenharmony_ci/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` 4043da5c369Sopenharmony_ci/// 4053da5c369Sopenharmony_ci/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a 4063da5c369Sopenharmony_ci/// signal specified by `sig`. 4073da5c369Sopenharmony_cipub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 4083da5c369Sopenharmony_ci let data = match sig.into() { 4093da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 4103da5c369Sopenharmony_ci None => ptr::null_mut(), 4113da5c369Sopenharmony_ci }; 4123da5c369Sopenharmony_ci unsafe { 4133da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data) 4143da5c369Sopenharmony_ci .map(drop) 4153da5c369Sopenharmony_ci } 4163da5c369Sopenharmony_ci} 4173da5c369Sopenharmony_ci 4183da5c369Sopenharmony_ci/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` 4193da5c369Sopenharmony_ci/// 4203da5c369Sopenharmony_ci/// Continues the execution of the process with PID `pid`, optionally 4213da5c369Sopenharmony_ci/// delivering a signal specified by `sig`. 4223da5c369Sopenharmony_cipub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 4233da5c369Sopenharmony_ci let data = match sig.into() { 4243da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 4253da5c369Sopenharmony_ci None => ptr::null_mut(), 4263da5c369Sopenharmony_ci }; 4273da5c369Sopenharmony_ci unsafe { 4283da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) 4293da5c369Sopenharmony_ci // ignore the useless return value 4303da5c369Sopenharmony_ci } 4313da5c369Sopenharmony_ci} 4323da5c369Sopenharmony_ci 4333da5c369Sopenharmony_ci/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` 4343da5c369Sopenharmony_ci/// 4353da5c369Sopenharmony_ci/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` 4363da5c369Sopenharmony_ci#[cfg(target_os = "linux")] 4373da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 4383da5c369Sopenharmony_cipub fn interrupt(pid: Pid) -> Result<()> { 4393da5c369Sopenharmony_ci unsafe { 4403da5c369Sopenharmony_ci ptrace_other( 4413da5c369Sopenharmony_ci Request::PTRACE_INTERRUPT, 4423da5c369Sopenharmony_ci pid, 4433da5c369Sopenharmony_ci ptr::null_mut(), 4443da5c369Sopenharmony_ci ptr::null_mut(), 4453da5c369Sopenharmony_ci ) 4463da5c369Sopenharmony_ci .map(drop) 4473da5c369Sopenharmony_ci } 4483da5c369Sopenharmony_ci} 4493da5c369Sopenharmony_ci 4503da5c369Sopenharmony_ci/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` 4513da5c369Sopenharmony_ci/// 4523da5c369Sopenharmony_ci/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` 4533da5c369Sopenharmony_cipub fn kill(pid: Pid) -> Result<()> { 4543da5c369Sopenharmony_ci unsafe { 4553da5c369Sopenharmony_ci ptrace_other( 4563da5c369Sopenharmony_ci Request::PTRACE_KILL, 4573da5c369Sopenharmony_ci pid, 4583da5c369Sopenharmony_ci ptr::null_mut(), 4593da5c369Sopenharmony_ci ptr::null_mut(), 4603da5c369Sopenharmony_ci ) 4613da5c369Sopenharmony_ci .map(drop) 4623da5c369Sopenharmony_ci } 4633da5c369Sopenharmony_ci} 4643da5c369Sopenharmony_ci 4653da5c369Sopenharmony_ci/// Move the stopped tracee process forward by a single step as with 4663da5c369Sopenharmony_ci/// `ptrace(PTRACE_SINGLESTEP, ...)` 4673da5c369Sopenharmony_ci/// 4683da5c369Sopenharmony_ci/// Advances the execution of the process with PID `pid` by a single step optionally delivering a 4693da5c369Sopenharmony_ci/// signal specified by `sig`. 4703da5c369Sopenharmony_ci/// 4713da5c369Sopenharmony_ci/// # Example 4723da5c369Sopenharmony_ci/// ```rust 4733da5c369Sopenharmony_ci/// use nix::sys::ptrace::step; 4743da5c369Sopenharmony_ci/// use nix::unistd::Pid; 4753da5c369Sopenharmony_ci/// use nix::sys::signal::Signal; 4763da5c369Sopenharmony_ci/// use nix::sys::wait::*; 4773da5c369Sopenharmony_ci/// 4783da5c369Sopenharmony_ci/// // If a process changes state to the stopped state because of a SIGUSR1 4793da5c369Sopenharmony_ci/// // signal, this will step the process forward and forward the user 4803da5c369Sopenharmony_ci/// // signal to the stopped process 4813da5c369Sopenharmony_ci/// match waitpid(Pid::from_raw(-1), None) { 4823da5c369Sopenharmony_ci/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { 4833da5c369Sopenharmony_ci/// let _ = step(pid, Signal::SIGUSR1); 4843da5c369Sopenharmony_ci/// } 4853da5c369Sopenharmony_ci/// _ => {}, 4863da5c369Sopenharmony_ci/// } 4873da5c369Sopenharmony_ci/// ``` 4883da5c369Sopenharmony_cipub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 4893da5c369Sopenharmony_ci let data = match sig.into() { 4903da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 4913da5c369Sopenharmony_ci None => ptr::null_mut(), 4923da5c369Sopenharmony_ci }; 4933da5c369Sopenharmony_ci unsafe { 4943da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data) 4953da5c369Sopenharmony_ci .map(drop) 4963da5c369Sopenharmony_ci } 4973da5c369Sopenharmony_ci} 4983da5c369Sopenharmony_ci 4993da5c369Sopenharmony_ci/// Move the stopped tracee process forward by a single step or stop at the next syscall 5003da5c369Sopenharmony_ci/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` 5013da5c369Sopenharmony_ci/// 5023da5c369Sopenharmony_ci/// Advances the execution by a single step or until the next syscall. 5033da5c369Sopenharmony_ci/// In case the tracee is stopped at a syscall, the syscall will not be executed. 5043da5c369Sopenharmony_ci/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. 5053da5c369Sopenharmony_ci#[cfg(all( 5063da5c369Sopenharmony_ci target_os = "linux", 5073da5c369Sopenharmony_ci target_env = "gnu", 5083da5c369Sopenharmony_ci any(target_arch = "x86", target_arch = "x86_64") 5093da5c369Sopenharmony_ci))] 5103da5c369Sopenharmony_cipub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { 5113da5c369Sopenharmony_ci let data = match sig.into() { 5123da5c369Sopenharmony_ci Some(s) => s as i32 as *mut c_void, 5133da5c369Sopenharmony_ci None => ptr::null_mut(), 5143da5c369Sopenharmony_ci }; 5153da5c369Sopenharmony_ci unsafe { 5163da5c369Sopenharmony_ci ptrace_other( 5173da5c369Sopenharmony_ci Request::PTRACE_SYSEMU_SINGLESTEP, 5183da5c369Sopenharmony_ci pid, 5193da5c369Sopenharmony_ci ptr::null_mut(), 5203da5c369Sopenharmony_ci data, 5213da5c369Sopenharmony_ci ) 5223da5c369Sopenharmony_ci .map(drop) // ignore the useless return value 5233da5c369Sopenharmony_ci } 5243da5c369Sopenharmony_ci} 5253da5c369Sopenharmony_ci 5263da5c369Sopenharmony_ci/// Reads a word from a processes memory at the given address 5273da5c369Sopenharmony_cipub fn read(pid: Pid, addr: AddressType) -> Result<c_long> { 5283da5c369Sopenharmony_ci ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) 5293da5c369Sopenharmony_ci} 5303da5c369Sopenharmony_ci 5313da5c369Sopenharmony_ci/// Writes a word into the processes memory at the given address 5323da5c369Sopenharmony_ci/// 5333da5c369Sopenharmony_ci/// # Safety 5343da5c369Sopenharmony_ci/// 5353da5c369Sopenharmony_ci/// The `data` argument is passed directly to `ptrace(2)`. Read that man page 5363da5c369Sopenharmony_ci/// for guidance. 5373da5c369Sopenharmony_cipub unsafe fn write( 5383da5c369Sopenharmony_ci pid: Pid, 5393da5c369Sopenharmony_ci addr: AddressType, 5403da5c369Sopenharmony_ci data: *mut c_void, 5413da5c369Sopenharmony_ci) -> Result<()> { 5423da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) 5433da5c369Sopenharmony_ci} 5443da5c369Sopenharmony_ci 5453da5c369Sopenharmony_ci/// Reads a word from a user area at `offset`. 5463da5c369Sopenharmony_ci/// The user struct definition can be found in `/usr/include/sys/user.h`. 5473da5c369Sopenharmony_cipub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> { 5483da5c369Sopenharmony_ci ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) 5493da5c369Sopenharmony_ci} 5503da5c369Sopenharmony_ci 5513da5c369Sopenharmony_ci/// Writes a word to a user area at `offset`. 5523da5c369Sopenharmony_ci/// The user struct definition can be found in `/usr/include/sys/user.h`. 5533da5c369Sopenharmony_ci/// 5543da5c369Sopenharmony_ci/// # Safety 5553da5c369Sopenharmony_ci/// 5563da5c369Sopenharmony_ci/// The `data` argument is passed directly to `ptrace(2)`. Read that man page 5573da5c369Sopenharmony_ci/// for guidance. 5583da5c369Sopenharmony_cipub unsafe fn write_user( 5593da5c369Sopenharmony_ci pid: Pid, 5603da5c369Sopenharmony_ci offset: AddressType, 5613da5c369Sopenharmony_ci data: *mut c_void, 5623da5c369Sopenharmony_ci) -> Result<()> { 5633da5c369Sopenharmony_ci ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) 5643da5c369Sopenharmony_ci} 565