1 use cfg_if::cfg_if;
2 use crate::errno::Errno;
3 use libc::{self, c_int};
4 use std::ptr;
5 use crate::sys::signal::Signal;
6 use crate::unistd::Pid;
7 use crate::Result;
8 
9 pub type RequestType = c_int;
10 
11 cfg_if! {
12     if #[cfg(any(target_os = "dragonfly",
13                  target_os = "freebsd",
14                  target_os = "macos",
15                  target_os = "openbsd"))] {
16         #[doc(hidden)]
17         pub type AddressType = *mut ::libc::c_char;
18     } else {
19         #[doc(hidden)]
pthread_self() -> Pthread20         pub type AddressType = *mut ::libc::c_void;
21     }
22 }
23 
24 libc_enum! {
25     #[repr(i32)]
26     /// Ptrace Request enum defining the action to be taken.
27     #[non_exhaustive]
28     pub enum Request {
29         PT_TRACE_ME,
30         PT_READ_I,
pthread_kill<T: Into<Option<Signal>>>(thread: Pthread, signal: T) -> Result<()>31         PT_READ_D,
32         #[cfg(target_os = "macos")]
33         PT_READ_U,
34         PT_WRITE_I,
35         PT_WRITE_D,
36         #[cfg(target_os = "macos")]
37         PT_WRITE_U,
38         PT_CONTINUE,
39         PT_KILL,
40         #[cfg(any(any(target_os = "dragonfly",
41                   target_os = "freebsd",
42                   target_os = "macos"),
43                   all(target_os = "openbsd", target_arch = "x86_64"),
44                   all(target_os = "netbsd", any(target_arch = "x86_64",
45                                                 target_arch = "powerpc"))))]
46         PT_STEP,
47         PT_ATTACH,
48         PT_DETACH,
49         #[cfg(target_os = "macos")]
50         PT_SIGEXC,
51         #[cfg(target_os = "macos")]
52         PT_THUPDATE,
53         #[cfg(target_os = "macos")]
54         PT_ATTACHEXC
55     }
56 }
57 
58 unsafe fn ptrace_other(
59     request: Request,
60     pid: Pid,
61     addr: AddressType,
62     data: c_int,
63 ) -> Result<c_int> {
64     Errno::result(libc::ptrace(
65         request as RequestType,
66         libc::pid_t::from(pid),
67         addr,
68         data,
69     )).map(|_| 0)
70 }
71 
72 /// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
73 ///
74 /// Indicates that this process is to be traced by its parent.
75 /// This is the only ptrace request to be issued by the tracee.
76 pub fn traceme() -> Result<()> {
77     unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
78 }
79 
80 /// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
81 ///
82 /// Attaches to the process specified by `pid`, making it a tracee of the calling process.
83 pub fn attach(pid: Pid) -> Result<()> {
84     unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
85 }
86 
87 /// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
88 ///
89 /// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
90 /// signal specified by `sig`.
91 pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
92     let data = match sig.into() {
93         Some(s) => s as c_int,
94         None => 0,
95     };
96     unsafe {
97         ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop)
98     }
99 }
100 
101 /// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
102 ///
103 /// Continues the execution of the process with PID `pid`, optionally
104 /// delivering a signal specified by `sig`.
105 pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
106     let data = match sig.into() {
107         Some(s) => s as c_int,
108         None => 0,
109     };
110     unsafe {
111         // Ignore the useless return value
112         ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
113     }
114 }
115 
116 /// Issues a kill request as with `ptrace(PT_KILL, ...)`
117 ///
118 /// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
119 pub fn kill(pid: Pid) -> Result<()> {
120     unsafe {
121         ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
122     }
123 }
124 
125 /// Move the stopped tracee process forward by a single step as with
126 /// `ptrace(PT_STEP, ...)`
127 ///
128 /// Advances the execution of the process with PID `pid` by a single step optionally delivering a
129 /// signal specified by `sig`.
130 ///
131 /// # Example
132 /// ```rust
133 /// use nix::sys::ptrace::step;
134 /// use nix::unistd::Pid;
135 /// use nix::sys::signal::Signal;
136 /// use nix::sys::wait::*;
137 /// // If a process changes state to the stopped state because of a SIGUSR1
138 /// // signal, this will step the process forward and forward the user
139 /// // signal to the stopped process
140 /// match waitpid(Pid::from_raw(-1), None) {
141 ///     Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
142 ///         let _ = step(pid, Signal::SIGUSR1);
143 ///     }
144 ///     _ => {},
145 /// }
146 /// ```
147 #[cfg(
148     any(
149         any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
150         all(target_os = "openbsd", target_arch = "x86_64"),
151         all(target_os = "netbsd",
152             any(target_arch = "x86_64", target_arch = "powerpc")
153         )
154     )
155 )]
156 pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
157     let data = match sig.into() {
158         Some(s) => s as c_int,
159         None => 0,
160     };
161     unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
162 }
163 
164 /// Reads a word from a processes memory at the given address
165 pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
166     unsafe {
167         // Traditionally there was a difference between reading data or
168         // instruction memory but not in modern systems.
169         ptrace_other(Request::PT_READ_D, pid, addr, 0)
170     }
171 }
172 
173 /// Writes a word into the processes memory at the given address
174 pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
175     unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
176 }
177