1use cfg_if::cfg_if;
4use std::{mem, ptr};
5use crate::Result;
6use crate::errno::Errno;
7use libc::{self, c_void, c_long, siginfo_t};
8use crate::unistd::Pid;
9use crate::sys::signal::Signal;
10
11pub type AddressType = *mut ::libc::c_void;
12
13#[cfg(all(
14 target_os = "linux",
15 any(all(target_arch = "x86_64",
16 any(target_env = "gnu", target_env = "musl")),
17 all(target_arch = "x86", target_env = "gnu"))
18))]
19use libc::user_regs_struct;
20
21cfg_if! {
22 if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
23 all(target_os = "linux", target_env = "gnu")))] {
24 #[doc(hidden)]
25 pub type RequestType = ::libc::c_uint;
26 } else {
27 #[doc(hidden)]
28 pub type RequestType = ::libc::c_int;
29 }
30}
31
32libc_enum!{
33 #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
34 #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
35 #[non_exhaustive]
37 pub enum Request {
38 PTRACE_TRACEME,
39 PTRACE_PEEKTEXT,
40 PTRACE_PEEKDATA,
41 PTRACE_PEEKUSER,
42 PTRACE_POKETEXT,
43 PTRACE_POKEDATA,
44 PTRACE_POKEUSER,
45 PTRACE_CONT,
46 PTRACE_KILL,
47 PTRACE_SINGLESTEP,
48 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
49 all(target_os = "linux", any(target_env = "musl",
50 target_arch = "mips",
51 target_arch = "mips64",
52 target_arch = "x86_64",
53 target_pointer_width = "32"))))]
54 PTRACE_GETREGS,
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 = "mips64",
59 target_arch = "x86_64",
60 target_pointer_width = "32"))))]
61 PTRACE_SETREGS,
62 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
63 all(target_os = "linux", any(target_env = "musl",
64 target_arch = "mips",
65 target_arch = "mips64",
66 target_arch = "x86_64",
67 target_pointer_width = "32"))))]
68 PTRACE_GETFPREGS,
69 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
70 all(target_os = "linux", any(target_env = "musl",
71 target_arch = "mips",
72 target_arch = "mips64",
73 target_arch = "x86_64",
74 target_pointer_width = "32"))))]
75 PTRACE_SETFPREGS,
76 PTRACE_ATTACH,
77 PTRACE_DETACH,
78 #[cfg(all(target_os = "linux", any(target_env = "musl",
79 target_arch = "mips",
80 target_arch = "mips64",
81 target_arch = "x86",
82 target_arch = "x86_64")))]
83 PTRACE_GETFPXREGS,
84 #[cfg(all(target_os = "linux", any(target_env = "musl",
85 target_arch = "mips",
86 target_arch = "mips64",
87 target_arch = "x86",
88 target_arch = "x86_64")))]
89 PTRACE_SETFPXREGS,
90 PTRACE_SYSCALL,
91 PTRACE_SETOPTIONS,
92 PTRACE_GETEVENTMSG,
93 PTRACE_GETSIGINFO,
94 PTRACE_SETSIGINFO,
95 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
96 target_arch = "mips64"))))]
97 PTRACE_GETREGSET,
98 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
99 target_arch = "mips64"))))]
100 PTRACE_SETREGSET,
101 #[cfg(target_os = "linux")]
102 PTRACE_SEIZE,
103 #[cfg(target_os = "linux")]
104 PTRACE_INTERRUPT,
105 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
106 target_arch = "mips64"))))]
107 PTRACE_LISTEN,
108 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
109 target_arch = "mips64"))))]
110 PTRACE_PEEKSIGINFO,
111 #[cfg(all(target_os = "linux", target_env = "gnu",
112 any(target_arch = "x86", target_arch = "x86_64")))]
113 PTRACE_SYSEMU,
114 #[cfg(all(target_os = "linux", target_env = "gnu",
115 any(target_arch = "x86", target_arch = "x86_64")))]
116 PTRACE_SYSEMU_SINGLESTEP,
117 }
118}
119
120libc_enum!{
121 #[repr(i32)]
122 #[non_exhaustive]
126 pub enum Event {
127 PTRACE_EVENT_FORK,
129 PTRACE_EVENT_VFORK,
131 PTRACE_EVENT_CLONE,
133 PTRACE_EVENT_EXEC,
135 PTRACE_EVENT_VFORK_DONE,
137 PTRACE_EVENT_EXIT,
140 PTRACE_EVENT_SECCOMP,
142 PTRACE_EVENT_STOP,
145 }
146}
147
148libc_bitflags! {
149 pub struct Options: libc::c_int {
152 PTRACE_O_TRACESYSGOOD;
156 PTRACE_O_TRACEFORK;
158 PTRACE_O_TRACEVFORK;
160 PTRACE_O_TRACECLONE;
162 PTRACE_O_TRACEEXEC;
164 PTRACE_O_TRACEVFORKDONE;
166 PTRACE_O_TRACEEXIT;
169 PTRACE_O_TRACESECCOMP;
172 #[cfg(any(target_os = "android", target_os = "linux"))]
175 PTRACE_O_EXITKILL;
176 }
177}
178
179fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
180 let ret = unsafe {
181 Errno::clear();
182 libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
183 };
184 match Errno::result(ret) {
185 Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
186 err @ Err(..) => err,
187 }
188}
189
190#[cfg(all(
192 target_os = "linux",
193 any(all(target_arch = "x86_64",
194 any(target_env = "gnu", target_env = "musl")),
195 all(target_arch = "x86", target_env = "gnu"))
196))]
197pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
198 ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
199}
200
201#[cfg(all(
203 target_os = "linux",
204 any(all(target_arch = "x86_64",
205 any(target_env = "gnu", target_env = "musl")),
206 all(target_arch = "x86", target_env = "gnu"))
207))]
208pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
209 let res = unsafe {
210 libc::ptrace(Request::PTRACE_SETREGS as RequestType,
211 libc::pid_t::from(pid),
212 ptr::null_mut::<c_void>(),
213 ®s as *const _ as *const c_void)
214 };
215 Errno::result(res).map(drop)
216}
217
218fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
223 let mut data = mem::MaybeUninit::uninit();
224 let res = unsafe {
225 libc::ptrace(request as RequestType,
226 libc::pid_t::from(pid),
227 ptr::null_mut::<T>(),
228 data.as_mut_ptr() as *const _ as *const c_void)
229 };
230 Errno::result(res)?;
231 Ok(unsafe{ data.assume_init() })
232}
233
234unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
235 Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
236}
237
238pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
240 let res = unsafe {
241 libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
242 libc::pid_t::from(pid),
243 ptr::null_mut::<c_void>(),
244 options.bits() as *mut c_void)
245 };
246 Errno::result(res).map(drop)
247}
248
249pub fn getevent(pid: Pid) -> Result<c_long> {
251 ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
252}
253
254pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
256 ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
257}
258
259pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
261 let ret = unsafe{
262 Errno::clear();
263 libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
264 libc::pid_t::from(pid),
265 ptr::null_mut::<c_void>(),
266 sig as *const _ as *const c_void)
267 };
268 match Errno::result(ret) {
269 Ok(_) => Ok(()),
270 Err(e) => Err(e),
271 }
272}
273
274pub fn traceme() -> Result<()> {
279 unsafe {
280 ptrace_other(
281 Request::PTRACE_TRACEME,
282 Pid::from_raw(0),
283 ptr::null_mut(),
284 ptr::null_mut(),
285 ).map(drop) }
287}
288
289pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
294 let data = match sig.into() {
295 Some(s) => s as i32 as *mut c_void,
296 None => ptr::null_mut(),
297 };
298 unsafe {
299 ptrace_other(
300 Request::PTRACE_SYSCALL,
301 pid,
302 ptr::null_mut(),
303 data,
304 ).map(drop) }
306}
307
308#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
314pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
315 let data = match sig.into() {
316 Some(s) => s as i32 as *mut c_void,
317 None => ptr::null_mut(),
318 };
319 unsafe {
320 ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop)
321 }
323}
324
325pub fn attach(pid: Pid) -> Result<()> {
329 unsafe {
330 ptrace_other(
331 Request::PTRACE_ATTACH,
332 pid,
333 ptr::null_mut(),
334 ptr::null_mut(),
335 ).map(drop) }
337}
338
339#[cfg(target_os = "linux")]
343pub fn seize(pid: Pid, options: Options) -> Result<()> {
344 unsafe {
345 ptrace_other(
346 Request::PTRACE_SEIZE,
347 pid,
348 ptr::null_mut(),
349 options.bits() as *mut c_void,
350 ).map(drop) }
352}
353
354pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
359 let data = match sig.into() {
360 Some(s) => s as i32 as *mut c_void,
361 None => ptr::null_mut(),
362 };
363 unsafe {
364 ptrace_other(
365 Request::PTRACE_DETACH,
366 pid,
367 ptr::null_mut(),
368 data
369 ).map(drop)
370 }
371}
372
373pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
378 let data = match sig.into() {
379 Some(s) => s as i32 as *mut c_void,
380 None => ptr::null_mut(),
381 };
382 unsafe {
383 ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) }
385}
386
387#[cfg(target_os = "linux")]
391pub fn interrupt(pid: Pid) -> Result<()> {
392 unsafe {
393 ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
394 }
395}
396
397pub fn kill(pid: Pid) -> Result<()> {
401 unsafe {
402 ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
403 }
404}
405
406pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
430 let data = match sig.into() {
431 Some(s) => s as i32 as *mut c_void,
432 None => ptr::null_mut(),
433 };
434 unsafe {
435 ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
436 }
437}
438
439#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
446pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
447 let data = match sig.into() {
448 Some(s) => s as i32 as *mut c_void,
449 None => ptr::null_mut(),
450 };
451 unsafe {
452 ptrace_other(
453 Request::PTRACE_SYSEMU_SINGLESTEP,
454 pid,
455 ptr::null_mut(),
456 data,
457 )
458 .map(drop) }
460}
461
462pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
464 ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
465}
466
467pub unsafe fn write(
474 pid: Pid,
475 addr: AddressType,
476 data: *mut c_void) -> Result<()>
477{
478 ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
479}