Skip to content

Commit 06850b2

Browse files
committed
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
2 parents 6783ffc + 43a2943 commit 06850b2

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1818
([#556](https://github.com/nix-rust/nix/pull/556)
1919
- Added `nix::ptr::openpty`
2020
([#456](https://github.com/nix-rust/nix/pull/456))
21+
- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo
22+
and nix::Error::UnsupportedOperation}`
23+
([#614](https://github.com/nix-rust/nix/pull/614))
2124

2225
### Changed
2326
- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.
@@ -29,6 +32,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2932
- Changed type signature of `sys::select::FdSet::contains` to make `self`
3033
immutable ([#564](https://github.com/nix-rust/nix/pull/564))
3134

35+
### Removed
36+
- Removed io::Error from nix::Error and conversion from nix::Error to Errno
37+
([#614](https://github.com/nix-rust/nix/pull/614))
38+
3239
### Fixed
3340
- Fixed multiple issues compiling under different archetectures and OSes.
3441
Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)),

src/lib.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ use std::{ptr, result};
7575
use std::ffi::{CStr, OsStr};
7676
use std::path::{Path, PathBuf};
7777
use std::os::unix::ffi::OsStrExt;
78-
use std::io;
7978
use std::fmt;
8079
use std::error;
8180
use libc::PATH_MAX;
@@ -97,6 +96,9 @@ pub enum Error {
9796
/// The operation involved a conversion to Rust's native String type, which failed because the
9897
/// string did not contain all valid UTF-8.
9998
InvalidUtf8,
99+
/// The operation is not supported by Nix, in this instance either use the libc bindings or
100+
/// consult the module documentation to see if there is a more appropriate interface available.
101+
UnsupportedOperation,
100102
}
101103

102104
impl Error {
@@ -116,14 +118,6 @@ impl Error {
116118
Error::Sys(errno::EINVAL)
117119
}
118120

119-
/// Get the errno associated with this error
120-
pub fn errno(&self) -> errno::Errno {
121-
match *self {
122-
Error::InvalidPath => errno::Errno::EINVAL,
123-
Error::InvalidUtf8 => errno::Errno::UnknownErrno,
124-
Error::Sys(errno) => errno,
125-
}
126-
}
127121
}
128122

129123
impl From<errno::Errno> for Error {
@@ -139,6 +133,7 @@ impl error::Error for Error {
139133
match self {
140134
&Error::InvalidPath => "Invalid path",
141135
&Error::InvalidUtf8 => "Invalid UTF-8 string",
136+
&Error::UnsupportedOperation => "Unsupported Operation",
142137
&Error::Sys(ref errno) => errno.desc(),
143138
}
144139
}
@@ -149,21 +144,12 @@ impl fmt::Display for Error {
149144
match self {
150145
&Error::InvalidPath => write!(f, "Invalid path"),
151146
&Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
147+
&Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
152148
&Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
153149
}
154150
}
155151
}
156152

157-
impl From<Error> for io::Error {
158-
fn from(err: Error) -> Self {
159-
match err {
160-
Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
161-
Error::InvalidUtf8 => io::Error::new(io::ErrorKind::Other, err),
162-
Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
163-
}
164-
}
165-
}
166-
167153
pub trait NixPath {
168154
fn len(&self) -> usize;
169155

src/sys/ptrace.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use std::{mem, ptr};
12
use {Errno, Error, Result};
2-
use libc::{pid_t, c_void, c_long};
3+
use libc::{pid_t, c_void, c_long, siginfo_t};
34

45
#[cfg(all(target_os = "linux",
56
any(target_arch = "x86",
@@ -71,11 +72,14 @@ mod ffi {
7172
}
7273
}
7374

75+
/// Performs a ptrace request. If the request in question is provided by a specialised function
76+
/// this function will return an unsupported operation error.
7477
pub fn ptrace(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
7578
use self::ptrace::*;
7679

7780
match request {
7881
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
82+
PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err(Error::UnsupportedOperation),
7983
_ => ptrace_other(request, pid, addr, data)
8084
}
8185
}
@@ -91,6 +95,20 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da
9195
}
9296
}
9397

98+
/// Function for ptrace requests that return values from the data field.
99+
/// Some ptrace get requests populate structs or larger elements than c_long
100+
/// and therefore use the data field to return values. This function handles these
101+
/// requests.
102+
fn ptrace_get_data<T>(request: ptrace::PtraceRequest, pid: pid_t) -> Result<T> {
103+
// Creates an uninitialized pointer to store result in
104+
let data: Box<T> = Box::new(unsafe { mem::uninitialized() });
105+
let data: *mut c_void = unsafe { mem::transmute(data) };
106+
ptrace(request, pid, ptr::null_mut(), data)?;
107+
// Convert back into the original data format and return unboxed value
108+
let data: Box<T> = unsafe { mem::transmute(data) };
109+
Ok(*data)
110+
}
111+
94112
fn ptrace_other(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
95113
Errno::result(unsafe { ffi::ptrace(request, pid, addr, data) }).map(|_| 0)
96114
}
@@ -102,3 +120,28 @@ pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<(
102120

103121
ptrace(PTRACE_SETOPTIONS, pid, ptr::null_mut(), options as *mut c_void).map(drop)
104122
}
123+
124+
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
125+
pub fn ptrace_getevent(pid: pid_t) -> Result<c_long> {
126+
use self::ptrace::*;
127+
ptrace_get_data::<c_long>(PTRACE_GETEVENTMSG, pid)
128+
}
129+
130+
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
131+
pub fn ptrace_getsiginfo(pid: pid_t) -> Result<siginfo_t> {
132+
use self::ptrace::*;
133+
ptrace_get_data::<siginfo_t>(PTRACE_GETSIGINFO, pid)
134+
}
135+
136+
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
137+
pub fn ptrace_setsiginfo(pid: pid_t, sig: &siginfo_t) -> Result<()> {
138+
use self::ptrace::*;
139+
let ret = unsafe{
140+
Errno::clear();
141+
ffi::ptrace(PTRACE_SETSIGINFO, pid, ptr::null_mut(), sig as *const _ as *const c_void)
142+
};
143+
match Errno::result(ret) {
144+
Ok(_) => Ok(()),
145+
Err(e) => Err(e),
146+
}
147+
}

0 commit comments

Comments
 (0)