summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2017-06-13 18:58:16 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2017-06-13 18:58:16 +0000
commit06850b29100ac94a90b6d1ee736f2097235379b6 (patch)
treee4c7221df798f533ed93819281457507b171bd67 /src/sys
parent6783ffc206de568ca8867abe6133bdad9110211e (diff)
parent43a29431b63516b23016aae76d3c15bf083f091c (diff)
downloadnix-06850b29100ac94a90b6d1ee736f2097235379b6.zip
Merge #614
614: Added ptrace utilities. r=Susurrus Some ptrace functions return structures through the data argument. This commit adds utilities to return data through this mechanism and function specialisations for a few of these functions (getting event messages or the siginfo_t struct). Once the next version of libc is released these utilities will be expanded to include the fpregs and user_regs structs. Due to the need to use unsafe blocks to utilise these ptrace features I feel these are good candidates for inclusion into rust-nix
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/ptrace.rs45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs
index edbc9734..bf6ee8bb 100644
--- a/src/sys/ptrace.rs
+++ b/src/sys/ptrace.rs
@@ -1,5 +1,6 @@
+use std::{mem, ptr};
use {Errno, Error, Result};
-use libc::{pid_t, c_void, c_long};
+use libc::{pid_t, c_void, c_long, siginfo_t};
#[cfg(all(target_os = "linux",
any(target_arch = "x86",
@@ -71,11 +72,14 @@ mod ffi {
}
}
+/// 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_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
use self::ptrace::*;
match request {
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
+ PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err(Error::UnsupportedOperation),
_ => ptrace_other(request, pid, addr, data)
}
}
@@ -91,6 +95,20 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da
}
}
+/// Function for ptrace requests that return values from the data field.
+/// Some ptrace get requests populate structs or larger elements than c_long
+/// and therefore use the data field to return values. This function handles these
+/// requests.
+fn ptrace_get_data<T>(request: ptrace::PtraceRequest, pid: pid_t) -> Result<T> {
+ // Creates an uninitialized pointer to store result in
+ let data: Box<T> = Box::new(unsafe { mem::uninitialized() });
+ let data: *mut c_void = unsafe { mem::transmute(data) };
+ ptrace(request, pid, ptr::null_mut(), data)?;
+ // Convert back into the original data format and return unboxed value
+ let data: Box<T> = unsafe { mem::transmute(data) };
+ Ok(*data)
+}
+
fn ptrace_other(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
Errno::result(unsafe { ffi::ptrace(request, pid, addr, data) }).map(|_| 0)
}
@@ -102,3 +120,28 @@ pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<(
ptrace(PTRACE_SETOPTIONS, pid, ptr::null_mut(), options as *mut c_void).map(drop)
}
+
+/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
+pub fn ptrace_getevent(pid: pid_t) -> Result<c_long> {
+ use self::ptrace::*;
+ ptrace_get_data::<c_long>(PTRACE_GETEVENTMSG, pid)
+}
+
+/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
+pub fn ptrace_getsiginfo(pid: pid_t) -> Result<siginfo_t> {
+ use self::ptrace::*;
+ ptrace_get_data::<siginfo_t>(PTRACE_GETSIGINFO, pid)
+}
+
+/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
+pub fn ptrace_setsiginfo(pid: pid_t, sig: &siginfo_t) -> Result<()> {
+ use self::ptrace::*;
+ let ret = unsafe{
+ Errno::clear();
+ ffi::ptrace(PTRACE_SETSIGINFO, pid, ptr::null_mut(), sig as *const _ as *const c_void)
+ };
+ match Errno::result(ret) {
+ Ok(_) => Ok(()),
+ Err(e) => Err(e),
+ }
+}