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 target_env = "uclibc"))] {
25 #[doc(hidden)]
26 pub type RequestType = ::libc::c_uint;
27 } else {
28 #[doc(hidden)]
29 pub type RequestType = ::libc::c_int;
30 }
31}
32
33libc_enum!{
34 #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))]
35 #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))]
36 #[non_exhaustive]
38 pub enum Request {
39 PTRACE_TRACEME,
40 PTRACE_PEEKTEXT,
41 PTRACE_PEEKDATA,
42 PTRACE_PEEKUSER,
43 PTRACE_POKETEXT,
44 PTRACE_POKEDATA,
45 PTRACE_POKEUSER,
46 PTRACE_CONT,
47 PTRACE_KILL,
48 PTRACE_SINGLESTEP,
49 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
50 all(target_os = "linux", any(target_env = "musl",
51 target_arch = "mips",
52 target_arch = "mips64",
53 target_arch = "x86_64",
54 target_pointer_width = "32"))))]
55 PTRACE_GETREGS,
56 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
57 all(target_os = "linux", any(target_env = "musl",
58 target_arch = "mips",
59 target_arch = "mips64",
60 target_arch = "x86_64",
61 target_pointer_width = "32"))))]
62 PTRACE_SETREGS,
63 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
64 all(target_os = "linux", any(target_env = "musl",
65 target_arch = "mips",
66 target_arch = "mips64",
67 target_arch = "x86_64",
68 target_pointer_width = "32"))))]
69 PTRACE_GETFPREGS,
70 #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
71 all(target_os = "linux", any(target_env = "musl",
72 target_arch = "mips",
73 target_arch = "mips64",
74 target_arch = "x86_64",
75 target_pointer_width = "32"))))]
76 PTRACE_SETFPREGS,
77 PTRACE_ATTACH,
78 PTRACE_DETACH,
79 #[cfg(all(target_os = "linux", any(target_env = "musl",
80 target_arch = "mips",
81 target_arch = "mips64",
82 target_arch = "x86",
83 target_arch = "x86_64")))]
84 PTRACE_GETFPXREGS,
85 #[cfg(all(target_os = "linux", any(target_env = "musl",
86 target_arch = "mips",
87 target_arch = "mips64",
88 target_arch = "x86",
89 target_arch = "x86_64")))]
90 PTRACE_SETFPXREGS,
91 PTRACE_SYSCALL,
92 PTRACE_SETOPTIONS,
93 PTRACE_GETEVENTMSG,
94 PTRACE_GETSIGINFO,
95 PTRACE_SETSIGINFO,
96 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
97 target_arch = "mips64"))))]
98 PTRACE_GETREGSET,
99 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
100 target_arch = "mips64"))))]
101 PTRACE_SETREGSET,
102 #[cfg(target_os = "linux")]
103 #[cfg_attr(docsrs, doc(cfg(all())))]
104 PTRACE_SEIZE,
105 #[cfg(target_os = "linux")]
106 #[cfg_attr(docsrs, doc(cfg(all())))]
107 PTRACE_INTERRUPT,
108 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
109 target_arch = "mips64"))))]
110 PTRACE_LISTEN,
111 #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
112 target_arch = "mips64"))))]
113 PTRACE_PEEKSIGINFO,
114 #[cfg(all(target_os = "linux", target_env = "gnu",
115 any(target_arch = "x86", target_arch = "x86_64")))]
116 PTRACE_SYSEMU,
117 #[cfg(all(target_os = "linux", target_env = "gnu",
118 any(target_arch = "x86", target_arch = "x86_64")))]
119 PTRACE_SYSEMU_SINGLESTEP,
120 }
121}
122
123libc_enum!{
124 #[repr(i32)]
125 #[non_exhaustive]
129 pub enum Event {
130 PTRACE_EVENT_FORK,
132 PTRACE_EVENT_VFORK,
134 PTRACE_EVENT_CLONE,
136 PTRACE_EVENT_EXEC,
138 PTRACE_EVENT_VFORK_DONE,
140 PTRACE_EVENT_EXIT,
143 PTRACE_EVENT_SECCOMP,
145 PTRACE_EVENT_STOP,
148 }
149}
150
151libc_bitflags! {
152 pub struct Options: libc::c_int {
155 PTRACE_O_TRACESYSGOOD;
159 PTRACE_O_TRACEFORK;
161 PTRACE_O_TRACEVFORK;
163 PTRACE_O_TRACECLONE;
165 PTRACE_O_TRACEEXEC;
167 PTRACE_O_TRACEVFORKDONE;
169 PTRACE_O_TRACEEXIT;
172 PTRACE_O_TRACESECCOMP;
175 PTRACE_O_EXITKILL;
178 }
179}
180
181fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
182 let ret = unsafe {
183 Errno::clear();
184 libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
185 };
186 match Errno::result(ret) {
187 Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
188 err @ Err(..) => err,
189 }
190}
191
192#[cfg(all(
194 target_os = "linux",
195 any(all(target_arch = "x86_64",
196 any(target_env = "gnu", target_env = "musl")),
197 all(target_arch = "x86", target_env = "gnu"))
198))]
199pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
200 ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
201}
202
203#[cfg(all(
205 target_os = "linux",
206 any(all(target_arch = "x86_64",
207 any(target_env = "gnu", target_env = "musl")),
208 all(target_arch = "x86", target_env = "gnu"))
209))]
210pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
211 let res = unsafe {
212 libc::ptrace(Request::PTRACE_SETREGS as RequestType,
213 libc::pid_t::from(pid),
214 ptr::null_mut::<c_void>(),
215 ®s as *const _ as *const c_void)
216 };
217 Errno::result(res).map(drop)
218}
219
220fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
225 let mut data = mem::MaybeUninit::uninit();
226 let res = unsafe {
227 libc::ptrace(request as RequestType,
228 libc::pid_t::from(pid),
229 ptr::null_mut::<T>(),
230 data.as_mut_ptr() as *const _ as *const c_void)
231 };
232 Errno::result(res)?;
233 Ok(unsafe{ data.assume_init() })
234}
235
236unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
237 Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
238}
239
240pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
242 let res = unsafe {
243 libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
244 libc::pid_t::from(pid),
245 ptr::null_mut::<c_void>(),
246 options.bits() as *mut c_void)
247 };
248 Errno::result(res).map(drop)
249}
250
251pub fn getevent(pid: Pid) -> Result<c_long> {
253 ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
254}
255
256pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
258 ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
259}
260
261pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
263 let ret = unsafe{
264 Errno::clear();
265 libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
266 libc::pid_t::from(pid),
267 ptr::null_mut::<c_void>(),
268 sig as *const _ as *const c_void)
269 };
270 match Errno::result(ret) {
271 Ok(_) => Ok(()),
272 Err(e) => Err(e),
273 }
274}
275
276pub fn traceme() -> Result<()> {
281 unsafe {
282 ptrace_other(
283 Request::PTRACE_TRACEME,
284 Pid::from_raw(0),
285 ptr::null_mut(),
286 ptr::null_mut(),
287 ).map(drop) }
289}
290
291pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
296 let data = match sig.into() {
297 Some(s) => s as i32 as *mut c_void,
298 None => ptr::null_mut(),
299 };
300 unsafe {
301 ptrace_other(
302 Request::PTRACE_SYSCALL,
303 pid,
304 ptr::null_mut(),
305 data,
306 ).map(drop) }
308}
309
310#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
316pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
317 let data = match sig.into() {
318 Some(s) => s as i32 as *mut c_void,
319 None => ptr::null_mut(),
320 };
321 unsafe {
322 ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop)
323 }
325}
326
327pub fn attach(pid: Pid) -> Result<()> {
331 unsafe {
332 ptrace_other(
333 Request::PTRACE_ATTACH,
334 pid,
335 ptr::null_mut(),
336 ptr::null_mut(),
337 ).map(drop) }
339}
340
341#[cfg(target_os = "linux")]
345#[cfg_attr(docsrs, doc(cfg(all())))]
346pub fn seize(pid: Pid, options: Options) -> Result<()> {
347 unsafe {
348 ptrace_other(
349 Request::PTRACE_SEIZE,
350 pid,
351 ptr::null_mut(),
352 options.bits() as *mut c_void,
353 ).map(drop) }
355}
356
357pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
362 let data = match sig.into() {
363 Some(s) => s as i32 as *mut c_void,
364 None => ptr::null_mut(),
365 };
366 unsafe {
367 ptrace_other(
368 Request::PTRACE_DETACH,
369 pid,
370 ptr::null_mut(),
371 data
372 ).map(drop)
373 }
374}
375
376pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
381 let data = match sig.into() {
382 Some(s) => s as i32 as *mut c_void,
383 None => ptr::null_mut(),
384 };
385 unsafe {
386 ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) }
388}
389
390#[cfg(target_os = "linux")]
394#[cfg_attr(docsrs, doc(cfg(all())))]
395pub fn interrupt(pid: Pid) -> Result<()> {
396 unsafe {
397 ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
398 }
399}
400
401pub fn kill(pid: Pid) -> Result<()> {
405 unsafe {
406 ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
407 }
408}
409
410pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
434 let data = match sig.into() {
435 Some(s) => s as i32 as *mut c_void,
436 None => ptr::null_mut(),
437 };
438 unsafe {
439 ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
440 }
441}
442
443#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
450pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
451 let data = match sig.into() {
452 Some(s) => s as i32 as *mut c_void,
453 None => ptr::null_mut(),
454 };
455 unsafe {
456 ptrace_other(
457 Request::PTRACE_SYSEMU_SINGLESTEP,
458 pid,
459 ptr::null_mut(),
460 data,
461 )
462 .map(drop) }
464}
465
466pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
468 ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
469}
470
471pub unsafe fn write(
478 pid: Pid,
479 addr: AddressType,
480 data: *mut c_void) -> Result<()>
481{
482 ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
483}