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