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            &regs 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