Skip to main content

nix/sys/ptrace/
linux.rs

1//! For detailed description of the ptrace requests, consult `man ptrace`.
2
3use crate::errno::Errno;
4use crate::sys::signal::Signal;
5use crate::unistd::Pid;
6use crate::Result;
7use cfg_if::cfg_if;
8use libc::{self, c_long, c_void, siginfo_t};
9use std::{mem, ptr};
10
11pub type AddressType = *mut ::libc::c_void;
12
13#[cfg(all(
14    target_os = "linux",
15    any(
16        all(
17            any(target_arch = "x86_64", target_arch = "aarch64"),
18            any(target_env = "gnu", target_env = "musl")
19        ),
20        all(target_arch = "x86", target_env = "gnu"),
21        all(target_arch = "riscv64", target_env = "gnu"),
22    ),
23))]
24use libc::user_regs_struct;
25
26cfg_if! {
27    if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
28                 all(target_os = "linux", target_env = "gnu"),
29                 target_env = "uclibc"))] {
30        #[doc(hidden)]
31        pub type RequestType = ::libc::c_uint;
32    } else {
33        #[doc(hidden)]
34        pub type RequestType = ::libc::c_int;
35    }
36}
37
38libc_enum! {
39    #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android", target_env = "ohos")), repr(u32))]
40    #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android", target_env = "ohos"), repr(i32))]
41    /// Ptrace Request enum defining the action to be taken.
42    #[non_exhaustive]
43    pub enum Request {
44        PTRACE_TRACEME,
45        PTRACE_PEEKTEXT,
46        PTRACE_PEEKDATA,
47        PTRACE_PEEKUSER,
48        PTRACE_POKETEXT,
49        PTRACE_POKEDATA,
50        PTRACE_POKEUSER,
51        PTRACE_CONT,
52        PTRACE_KILL,
53        PTRACE_SINGLESTEP,
54        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
55                  all(target_os = "linux", any(target_env = "musl",
56                                               target_env = "ohos",
57                                               target_arch = "mips",
58                                               target_arch = "mips32r6",
59                                               target_arch = "mips64",
60                                               target_arch = "mips64r6",
61                                               target_arch = "x86_64",
62                                               target_pointer_width = "32"))))]
63        PTRACE_GETREGS,
64        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
65                  all(target_os = "linux", any(target_env = "musl",
66                                               target_env = "ohos",
67                                               target_arch = "mips",
68                                               target_arch = "mips32r6",
69                                               target_arch = "mips64",
70                                               target_arch = "mips64r6",
71                                               target_arch = "x86_64",
72                                               target_pointer_width = "32"))))]
73        PTRACE_SETREGS,
74        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
75                  all(target_os = "linux", any(target_env = "musl",
76                                               target_env = "ohos",
77                                               target_arch = "mips",
78                                               target_arch = "mips32r6",
79                                               target_arch = "mips64",
80                                               target_arch = "mips64r6",
81                                               target_arch = "x86_64",
82                                               target_pointer_width = "32"))))]
83        PTRACE_GETFPREGS,
84        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
85                  all(target_os = "linux", any(target_env = "musl",
86                                               target_env = "ohos",
87                                               target_arch = "mips",
88                                               target_arch = "mips32r6",
89                                               target_arch = "mips64",
90                                               target_arch = "mips64r6",
91                                               target_arch = "x86_64",
92                                               target_pointer_width = "32"))))]
93        PTRACE_SETFPREGS,
94        PTRACE_ATTACH,
95        PTRACE_DETACH,
96        #[cfg(all(target_os = "linux", any(target_env = "musl",
97                                           target_env = "ohos",
98                                           target_arch = "mips",
99                                           target_arch = "mips32r6",
100                                           target_arch = "mips64",
101                                           target_arch = "mips64r6",
102                                           target_arch = "x86",
103                                           target_arch = "x86_64")))]
104        PTRACE_GETFPXREGS,
105        #[cfg(all(target_os = "linux", any(target_env = "musl",
106                                           target_env = "ohos",
107                                           target_arch = "mips",
108                                           target_arch = "mips32r6",
109                                           target_arch = "mips64",
110                                           target_arch = "mips64r6",
111                                           target_arch = "x86",
112                                           target_arch = "x86_64")))]
113        PTRACE_SETFPXREGS,
114        PTRACE_SYSCALL,
115        PTRACE_SETOPTIONS,
116        PTRACE_GETEVENTMSG,
117        PTRACE_GETSIGINFO,
118        PTRACE_SETSIGINFO,
119        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
120                                               target_arch = "mips32r6",
121                                               target_arch = "mips64",
122                                               target_arch = "mips64r6"))))]
123        PTRACE_GETREGSET,
124        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
125                                               target_arch = "mips32r6",
126                                               target_arch = "mips64",
127                                               target_arch = "mips64r6"))))]
128        PTRACE_SETREGSET,
129        #[cfg(target_os = "linux")]
130        PTRACE_SEIZE,
131        #[cfg(target_os = "linux")]
132        PTRACE_INTERRUPT,
133        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
134                                               target_arch = "mips32r6",
135                                               target_arch = "mips64",
136                                               target_arch = "mips64r6"))))]
137        PTRACE_LISTEN,
138        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
139                                               target_arch = "mips32r6",
140                                               target_arch = "mips64",
141                                               target_arch = "mips64r6"))))]
142        PTRACE_PEEKSIGINFO,
143        #[cfg(all(target_os = "linux", target_env = "gnu",
144                  any(target_arch = "x86", target_arch = "x86_64")))]
145        PTRACE_SYSEMU,
146        #[cfg(all(target_os = "linux", target_env = "gnu",
147                  any(target_arch = "x86", target_arch = "x86_64")))]
148        PTRACE_SYSEMU_SINGLESTEP,
149        #[cfg(all(target_os = "linux", target_env = "gnu"))]
150        PTRACE_GET_SYSCALL_INFO,
151    }
152}
153
154libc_enum! {
155    #[repr(i32)]
156    /// Using the ptrace options the tracer can configure the tracee to stop
157    /// at certain events. This enum is used to define those events as defined
158    /// in `man ptrace`.
159    #[non_exhaustive]
160    pub enum Event {
161        /// Event that stops before a return from fork or clone.
162        PTRACE_EVENT_FORK,
163        /// Event that stops before a return from vfork or clone.
164        PTRACE_EVENT_VFORK,
165        /// Event that stops before a return from clone.
166        PTRACE_EVENT_CLONE,
167        /// Event that stops before a return from execve.
168        PTRACE_EVENT_EXEC,
169        /// Event for a return from vfork.
170        PTRACE_EVENT_VFORK_DONE,
171        /// Event for a stop before an exit. Unlike the waitpid Exit status program.
172        /// registers can still be examined
173        PTRACE_EVENT_EXIT,
174        /// Stop triggered by a seccomp rule on a tracee.
175        PTRACE_EVENT_SECCOMP,
176        /// Stop triggered by the `INTERRUPT` syscall, or a group stop,
177        /// or when a new child is attached.
178        PTRACE_EVENT_STOP,
179    }
180}
181
182#[cfg(all(
183    target_os = "linux",
184    any(
185        all(
186            target_env = "gnu",
187            any(
188                target_arch = "x86_64",
189                target_arch = "x86",
190                target_arch = "aarch64",
191                target_arch = "riscv64",
192            )
193        ),
194        all(
195            target_env = "musl",
196            target_arch = "aarch64",
197        )
198    ),
199))]
200libc_enum! {
201    #[repr(i32)]
202    /// Defines a specific register set, as used in `PTRACE_GETREGSET` and `PTRACE_SETREGSET`.
203    #[non_exhaustive]
204    pub enum RegisterSetValue {
205        NT_PRSTATUS,
206        NT_PRFPREG,
207        NT_PRPSINFO,
208        NT_TASKSTRUCT,
209        NT_AUXV,
210    }
211}
212
213#[cfg(all(
214    target_os = "linux",
215    any(
216        all(
217            target_env = "gnu",
218            any(
219                target_arch = "x86_64",
220                target_arch = "x86",
221                target_arch = "aarch64",
222                target_arch = "riscv64",
223            )
224        ),
225        all(
226            target_env = "musl",
227            target_arch = "aarch64",
228        )
229    ),
230))]
231/// Represents register set areas, such as general-purpose registers or
232/// floating-point registers.
233///
234/// # Safety
235///
236/// This trait is marked unsafe, since implementation of the trait must match
237/// ptrace's request `VALUE` and return data type `Regs`.
238pub unsafe trait RegisterSet {
239    /// Corresponding type of registers in the kernel.
240    const VALUE: RegisterSetValue;
241
242    /// Struct representing the register space.
243    type Regs;
244}
245
246
247#[cfg(all(
248    target_os = "linux",
249    any(
250        all(
251            target_env = "gnu",
252            any(
253                target_arch = "x86_64",
254                target_arch = "x86",
255                target_arch = "aarch64",
256                target_arch = "riscv64",
257            )
258        ),
259        all(
260            target_env = "musl",
261            target_arch = "aarch64",
262        )
263    ),
264))]
265/// Register sets used in [`getregset`] and [`setregset`]
266pub mod regset {
267    use super::*;
268
269    #[derive(Debug, Clone, Copy)]
270    /// General-purpose registers.
271    pub enum NT_PRSTATUS {}
272
273    unsafe impl RegisterSet for NT_PRSTATUS {
274        const VALUE: RegisterSetValue = RegisterSetValue::NT_PRSTATUS;
275        type Regs = user_regs_struct;
276    }
277
278    #[derive(Debug, Clone, Copy)]
279    /// Floating-point registers.
280    pub enum NT_PRFPREG {}
281
282    unsafe impl RegisterSet for NT_PRFPREG {
283        const VALUE: RegisterSetValue = RegisterSetValue::NT_PRFPREG;
284        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
285        type Regs = libc::user_fpregs_struct;
286        #[cfg(target_arch = "aarch64")]
287        type Regs = libc::user_fpsimd_struct;
288        #[cfg(target_arch = "riscv64")]
289        type Regs = libc::__riscv_mc_d_ext_state;
290    }
291}
292
293libc_bitflags! {
294    /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
295    /// See `man ptrace` for more details.
296    pub struct Options: libc::c_int {
297        /// When delivering system call traps set a bit to allow tracer to
298        /// distinguish between normal stops or syscall stops. May not work on
299        /// all systems.
300        PTRACE_O_TRACESYSGOOD;
301        /// Stop tracee at next fork and start tracing the forked process.
302        PTRACE_O_TRACEFORK;
303        /// Stop tracee at next vfork call and trace the vforked process.
304        PTRACE_O_TRACEVFORK;
305        /// Stop tracee at next clone call and trace the cloned process.
306        PTRACE_O_TRACECLONE;
307        /// Stop tracee at next execve call.
308        PTRACE_O_TRACEEXEC;
309        /// Stop tracee at vfork completion.
310        PTRACE_O_TRACEVFORKDONE;
311        /// Stop tracee at next exit call. Stops before exit commences allowing
312        /// tracer to see location of exit and register states.
313        PTRACE_O_TRACEEXIT;
314        /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
315        /// details.
316        PTRACE_O_TRACESECCOMP;
317        /// Send a SIGKILL to the tracee if the tracer exits.  This is useful
318        /// for ptrace jailers to prevent tracees from escaping their control.
319        PTRACE_O_EXITKILL;
320    }
321}
322
323fn ptrace_peek(
324    request: Request,
325    pid: Pid,
326    addr: AddressType,
327    data: *mut c_void,
328) -> Result<c_long> {
329    let ret = unsafe {
330        Errno::clear();
331        libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
332    };
333    match Errno::result(ret) {
334        Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
335        err @ Err(..) => err,
336    }
337}
338
339/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
340///
341/// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
342/// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
343/// on aarch64 and riscv64.
344///
345/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
346#[cfg(all(
347    target_os = "linux",
348    any(
349        all(
350            target_arch = "x86_64",
351            any(target_env = "gnu", target_env = "musl")
352        ),
353        all(target_arch = "x86", target_env = "gnu")
354    )
355))]
356pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
357    ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
358}
359
360/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
361///
362/// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
363/// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
364/// on aarch64 and riscv64.
365///
366/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
367#[cfg(all(
368    target_os = "linux",
369    any(
370        all(
371            target_arch = "aarch64",
372            any(target_env = "gnu", target_env = "musl")
373        ),
374        all(target_arch = "riscv64", target_env = "gnu")
375    )
376))]
377pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
378    getregset::<regset::NT_PRSTATUS>(pid)
379}
380
381/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
382#[cfg(all(
383    target_os = "linux",
384    any(
385        all(
386            target_env = "gnu",
387            any(
388                target_arch = "x86_64",
389                target_arch = "x86",
390                target_arch = "aarch64",
391                target_arch = "riscv64"
392            )
393        ),
394        all(target_env = "musl", target_arch = "aarch64")
395    )
396))]
397pub fn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> {
398    let request = Request::PTRACE_GETREGSET;
399    let mut data = mem::MaybeUninit::<S::Regs>::uninit();
400    let mut iov = libc::iovec {
401        iov_base: data.as_mut_ptr().cast(),
402        iov_len: mem::size_of::<S::Regs>(),
403    };
404    unsafe {
405        ptrace_other(
406            request,
407            pid,
408            S::VALUE as i32 as AddressType,
409            (&mut iov as *mut libc::iovec).cast(),
410        )?;
411    };
412    Ok(unsafe { data.assume_init() })
413}
414
415/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
416///
417/// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
418/// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
419/// on aarch64 and riscv64.
420///
421/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
422#[cfg(all(
423    target_os = "linux",
424    any(
425        all(
426            target_arch = "x86_64",
427            any(target_env = "gnu", target_env = "musl")
428        ),
429        all(target_arch = "x86", target_env = "gnu")
430    )
431))]
432pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
433    let res = unsafe {
434        libc::ptrace(
435            Request::PTRACE_SETREGS as RequestType,
436            libc::pid_t::from(pid),
437            ptr::null_mut::<c_void>(),
438            &regs as *const user_regs_struct as *const c_void,
439        )
440    };
441    Errno::result(res).map(drop)
442}
443
444/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
445///
446/// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
447/// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
448/// on aarch64 and riscv64.
449///
450/// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
451#[cfg(all(
452    target_os = "linux",
453    any(
454        all(
455            target_env = "gnu",
456            any(target_arch = "aarch64", target_arch = "riscv64")
457        ),
458        all(target_env = "musl", target_arch = "aarch64")
459    )
460))]
461pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
462    setregset::<regset::NT_PRSTATUS>(pid, regs)
463}
464
465/// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)`
466#[cfg(all(
467    target_os = "linux",
468    any(
469        all(
470            target_env = "gnu",
471            any(
472                target_arch = "x86_64",
473                target_arch = "x86",
474                target_arch = "aarch64",
475                target_arch = "riscv64"
476            )
477        ),
478        all(target_env = "musl", target_arch = "aarch64")
479    )
480))]
481pub fn setregset<S: RegisterSet>(pid: Pid, mut regs: S::Regs) -> Result<()> {
482    let mut iov = libc::iovec {
483        iov_base: (&mut regs as *mut S::Regs).cast(),
484        iov_len: mem::size_of::<S::Regs>(),
485    };
486    unsafe {
487        ptrace_other(
488            Request::PTRACE_SETREGSET,
489            pid,
490            S::VALUE as i32 as AddressType,
491            (&mut iov as *mut libc::iovec).cast(),
492        )?;
493    }
494    Ok(())
495}
496
497/// Function for ptrace requests that return values from the data field.
498/// Some ptrace get requests populate structs or larger elements than `c_long`
499/// and therefore use the data field to return values. This function handles these
500/// requests.
501fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
502    let mut data = mem::MaybeUninit::<T>::uninit();
503    let res = unsafe {
504        libc::ptrace(
505            request as RequestType,
506            libc::pid_t::from(pid),
507            std::mem::size_of::<T>(),
508            data.as_mut_ptr(),
509        )
510    };
511    Errno::result(res)?;
512    Ok(unsafe { data.assume_init() })
513}
514
515unsafe fn ptrace_other(
516    request: Request,
517    pid: Pid,
518    addr: AddressType,
519    data: *mut c_void,
520) -> Result<c_long> {
521    unsafe {
522        Errno::result(libc::ptrace(
523            request as RequestType,
524            libc::pid_t::from(pid),
525            addr,
526            data,
527        ))
528        .map(|_| 0)
529    }
530}
531
532/// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`.
533pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
534    let res = unsafe {
535        libc::ptrace(
536            Request::PTRACE_SETOPTIONS as RequestType,
537            libc::pid_t::from(pid),
538            ptr::null_mut::<c_void>(),
539            options.bits() as *mut c_void,
540        )
541    };
542    Errno::result(res).map(drop)
543}
544
545/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG, ...)`
546pub fn getevent(pid: Pid) -> Result<c_long> {
547    ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
548}
549
550/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO, ...)`
551pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
552    ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
553}
554
555/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO, ...)`
556pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
557    let ret = unsafe {
558        Errno::clear();
559        libc::ptrace(
560            Request::PTRACE_SETSIGINFO as RequestType,
561            libc::pid_t::from(pid),
562            ptr::null_mut::<c_void>(),
563            sig as *const _ as *const c_void,
564        )
565    };
566    match Errno::result(ret) {
567        Ok(_) => Ok(()),
568        Err(e) => Err(e),
569    }
570}
571
572/// Get the informations of the syscall that caused the stop, as with
573/// `ptrace(PTRACE_GET_SYSCALL_INFO, ...`.
574#[cfg(all(target_os = "linux", target_env = "gnu"))]
575pub fn syscall_info(pid: Pid) -> Result<libc::ptrace_syscall_info> {
576    ptrace_get_data::<libc::ptrace_syscall_info>(Request::PTRACE_GET_SYSCALL_INFO, pid)
577}
578
579/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
580///
581/// Indicates that this process is to be traced by its parent.
582/// This is the only ptrace request to be issued by the tracee.
583pub fn traceme() -> Result<()> {
584    unsafe {
585        ptrace_other(
586            Request::PTRACE_TRACEME,
587            Pid::from_raw(0),
588            ptr::null_mut(),
589            ptr::null_mut(),
590        )
591        .map(drop) // ignore the useless return value
592    }
593}
594
595/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
596///
597/// Arranges for the tracee to be stopped at the next entry to or exit from a system call,
598/// optionally delivering a signal specified by `sig`.
599pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
600    let data = match sig.into() {
601        Some(s) => s as i32 as *mut c_void,
602        None => ptr::null_mut(),
603    };
604    unsafe {
605        ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data)
606            .map(drop) // ignore the useless return value
607    }
608}
609
610/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)`
611///
612/// In contrast to the `syscall` function, the syscall stopped at will not be executed.
613/// Thus the the tracee will only be stopped once per syscall,
614/// optionally delivering a signal specified by `sig`.
615#[cfg(all(
616    target_os = "linux",
617    target_env = "gnu",
618    any(target_arch = "x86", target_arch = "x86_64")
619))]
620pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
621    let data = match sig.into() {
622        Some(s) => s as i32 as *mut c_void,
623        None => ptr::null_mut(),
624    };
625    unsafe {
626        ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data)
627            .map(drop)
628        // ignore the useless return value
629    }
630}
631
632/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
633///
634/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
635pub fn attach(pid: Pid) -> Result<()> {
636    unsafe {
637        ptrace_other(
638            Request::PTRACE_ATTACH,
639            pid,
640            ptr::null_mut(),
641            ptr::null_mut(),
642        )
643        .map(drop) // ignore the useless return value
644    }
645}
646
647/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)`
648///
649/// Attaches to the process specified in pid, making it a tracee of the calling process.
650#[cfg(target_os = "linux")]
651pub fn seize(pid: Pid, options: Options) -> Result<()> {
652    unsafe {
653        ptrace_other(
654            Request::PTRACE_SEIZE,
655            pid,
656            ptr::null_mut(),
657            options.bits() as *mut c_void,
658        )
659        .map(drop) // ignore the useless return value
660    }
661}
662
663/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
664///
665/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
666/// signal specified by `sig`.
667pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
668    let data = match sig.into() {
669        Some(s) => s as i32 as *mut c_void,
670        None => ptr::null_mut(),
671    };
672    unsafe {
673        ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data)
674            .map(drop)
675    }
676}
677
678/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
679///
680/// Continues the execution of the process with PID `pid`, optionally
681/// delivering a signal specified by `sig`.
682pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
683    let data = match sig.into() {
684        Some(s) => s as i32 as *mut c_void,
685        None => ptr::null_mut(),
686    };
687    unsafe {
688        ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop)
689        // ignore the useless return value
690    }
691}
692
693/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)`
694///
695/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)`
696#[cfg(target_os = "linux")]
697pub fn interrupt(pid: Pid) -> Result<()> {
698    unsafe {
699        ptrace_other(
700            Request::PTRACE_INTERRUPT,
701            pid,
702            ptr::null_mut(),
703            ptr::null_mut(),
704        )
705        .map(drop)
706    }
707}
708
709/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
710///
711/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
712pub fn kill(pid: Pid) -> Result<()> {
713    unsafe {
714        ptrace_other(
715            Request::PTRACE_KILL,
716            pid,
717            ptr::null_mut(),
718            ptr::null_mut(),
719        )
720        .map(drop)
721    }
722}
723
724/// Move the stopped tracee process forward by a single step as with
725/// `ptrace(PTRACE_SINGLESTEP, ...)`
726///
727/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
728/// signal specified by `sig`.
729///
730/// # Example
731/// ```rust
732/// use nix::sys::ptrace::step;
733/// use nix::unistd::Pid;
734/// use nix::sys::signal::Signal;
735/// use nix::sys::wait::*;
736///
737/// // If a process changes state to the stopped state because of a SIGUSR1
738/// // signal, this will step the process forward and forward the user
739/// // signal to the stopped process
740/// match waitpid(Pid::from_raw(-1), None) {
741///     Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
742///         let _ = step(pid, Signal::SIGUSR1);
743///     }
744///     _ => {},
745/// }
746/// ```
747pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
748    let data = match sig.into() {
749        Some(s) => s as i32 as *mut c_void,
750        None => ptr::null_mut(),
751    };
752    unsafe {
753        ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data)
754            .map(drop)
755    }
756}
757
758/// Move the stopped tracee process forward by a single step or stop at the next syscall
759/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)`
760///
761/// Advances the execution by a single step or until the next syscall.
762/// In case the tracee is stopped at a syscall, the syscall will not be executed.
763/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation.
764#[cfg(all(
765    target_os = "linux",
766    target_env = "gnu",
767    any(target_arch = "x86", target_arch = "x86_64")
768))]
769pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
770    let data = match sig.into() {
771        Some(s) => s as i32 as *mut c_void,
772        None => ptr::null_mut(),
773    };
774    unsafe {
775        ptrace_other(
776            Request::PTRACE_SYSEMU_SINGLESTEP,
777            pid,
778            ptr::null_mut(),
779            data,
780        )
781        .map(drop) // ignore the useless return value
782    }
783}
784
785/// Reads a word from a processes memory at the given address, as with
786/// ptrace(PTRACE_PEEKDATA, ...)
787pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
788    ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
789}
790
791/// Writes a word into the processes memory at the given address, as with
792/// ptrace(PTRACE_POKEDATA, ...)
793#[allow(clippy::not_unsafe_ptr_arg_deref)]
794pub fn write(pid: Pid, addr: AddressType, data: c_long) -> Result<()> {
795    unsafe {
796        // Safety(not_unsafe_ptr_arg_deref):
797        // `ptrace_other` is a common abstract
798        // but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
799        ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data as *mut c_void)
800            .map(drop)
801    }
802}
803
804/// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...).
805/// The user struct definition can be found in `/usr/include/sys/user.h`.
806pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
807    ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
808}
809
810/// Writes a word to a user area at `offset`, as with ptrace(PTRACE_POKEUSER, ...).
811/// The user struct definition can be found in `/usr/include/sys/user.h`.
812#[allow(clippy::not_unsafe_ptr_arg_deref)]
813pub fn write_user(pid: Pid, offset: AddressType, data: c_long) -> Result<()> {
814    unsafe {
815        // Safety(not_unsafe_ptr_arg_deref):
816        // `ptrace_other` is a common abstract
817        // but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
818        ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data as *mut c_void)
819            .map(drop)
820    }
821}