diff options
Diffstat (limited to 'src/sys/ptrace.rs')
-rw-r--r-- | src/sys/ptrace.rs | 98 |
1 files changed, 81 insertions, 17 deletions
diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs index 877bfcb0..5f0391d4 100644 --- a/src/sys/ptrace.rs +++ b/src/sys/ptrace.rs @@ -1,12 +1,22 @@ +//! For detailed description of the ptrace requests, consult `man ptrace`. + use std::{mem, ptr}; use {Errno, Error, Result}; -use libc::{c_void, c_long, siginfo_t}; +use libc::{self, c_void, c_long, siginfo_t}; use ::unistd::Pid; +use sys::signal::Signal; pub mod ptrace { use libc::c_int; - pub type PtraceRequest = c_int; + cfg_if! { + if #[cfg(any(all(target_os = "linux", arch = "s390x"), + all(target_os = "linux", target_env = "gnu")))] { + pub type PtraceRequest = ::libc::c_uint; + } else { + pub type PtraceRequest = c_int; + } + } pub const PTRACE_TRACEME: PtraceRequest = 0; pub const PTRACE_PEEKTEXT: PtraceRequest = 1; @@ -60,17 +70,13 @@ pub mod ptrace { pub const PTRACE_O_TRACESECCOMP: PtraceOptions = (1 << PTRACE_EVENT_SECCOMP); } -mod ffi { - use libc::{pid_t, c_int, c_long, c_void}; - - extern { - pub fn ptrace(request: c_int, pid: pid_t, addr: * const c_void, data: * const c_void) -> c_long; - } -} - /// Performs a ptrace request. If the request in question is provided by a specialised function /// this function will return an unsupported operation error. -pub fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { +#[deprecated( + since="0.10.0", + note="usages of `ptrace()` should be replaced with the specialized helper functions instead" +)] +pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { use self::ptrace::*; match request { @@ -83,7 +89,7 @@ pub fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { let ret = unsafe { Errno::clear(); - ffi::ptrace(request, pid.into(), addr, data) + libc::ptrace(request, libc::pid_t::from(pid), addr, data) }; match Errno::result(ret) { Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret), @@ -98,13 +104,13 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data fn ptrace_get_data<T>(request: ptrace::PtraceRequest, pid: Pid) -> Result<T> { // Creates an uninitialized pointer to store result in let data: T = unsafe { mem::uninitialized() }; - let res = unsafe { ffi::ptrace(request, pid.into(), ptr::null_mut(), &data as *const _ as *const c_void) }; + let res = unsafe { libc::ptrace(request, libc::pid_t::from(pid), ptr::null_mut::<T>(), &data as *const _ as *const c_void) }; Errno::result(res)?; Ok(data) } -fn ptrace_other(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { - Errno::result(unsafe { ffi::ptrace(request, pid.into(), addr, data) }).map(|_| 0) +unsafe fn ptrace_other(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { + Errno::result(libc::ptrace(request, libc::pid_t::from(pid), addr, data)).map(|_| 0) } /// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. @@ -112,7 +118,7 @@ pub fn setoptions(pid: Pid, options: ptrace::PtraceOptions) -> Result<()> { use self::ptrace::*; use std::ptr; - let res = unsafe { ffi::ptrace(PTRACE_SETOPTIONS, pid.into(), ptr::null_mut(), options as *mut c_void) }; + let res = unsafe { libc::ptrace(PTRACE_SETOPTIONS, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), options as *mut c_void) }; Errno::result(res).map(|_| ()) } @@ -133,10 +139,68 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { use self::ptrace::*; let ret = unsafe{ Errno::clear(); - ffi::ptrace(PTRACE_SETSIGINFO, pid.into(), ptr::null_mut(), sig as *const _ as *const c_void) + libc::ptrace(PTRACE_SETSIGINFO, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), sig as *const _ as *const c_void) }; match Errno::result(ret) { Ok(_) => Ok(()), Err(e) => Err(e), } } + +/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` +/// +/// Indicates that this process is to be traced by its parent. +/// This is the only ptrace request to be issued by the tracee. +pub fn traceme() -> Result<()> { + unsafe { + ptrace_other( + ptrace::PTRACE_TRACEME, + Pid::from_raw(0), + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` +/// +/// Arranges for the tracee to be stopped at the next entry to or exit from a system call. +pub fn syscall(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + ptrace::PTRACE_SYSCALL, + pid, + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` +/// +/// Attaches to the process specified in pid, making it a tracee of the calling process. +pub fn attach(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + ptrace::PTRACE_ATTACH, + pid, + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` +/// +/// Continues the execution of the process with PID `pid`, optionally +/// delivering a signal specified by `sig`. +pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(ptrace::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value + } +} + |