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