summaryrefslogtreecommitdiff
path: root/src/sys/ptrace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/ptrace.rs')
-rw-r--r--src/sys/ptrace.rs98
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
+ }
+}
+