Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ptrace utilities. #614

Merged
merged 1 commit into from
Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#556](https://github.com/nix-rust/nix/pull/556)
- Added `nix::ptr::openpty`
([#456](https://github.com/nix-rust/nix/pull/456))
- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo
and nix::Error::UnsupportedOperation}`
([#614](https://github.com/nix-rust/nix/pull/614))

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

### Removed
- Removed io::Error from nix::Error and conversion from nix::Error to Errno
([#614](https://github.com/nix-rust/nix/pull/614))

### Fixed
- Fixed multiple issues compiling under different archetectures and OSes.
Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)),
Expand Down
24 changes: 5 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;
Expand All @@ -97,6 +96,9 @@ pub enum Error {
/// The operation involved a conversion to Rust's native String type, which failed because the
/// string did not contain all valid UTF-8.
InvalidUtf8,
/// The operation is not supported by Nix, in this instance either use the libc bindings or
/// consult the module documentation to see if there is a more appropriate interface available.
UnsupportedOperation,
}

impl Error {
Expand All @@ -116,14 +118,6 @@ impl Error {
Error::Sys(errno::EINVAL)
}

/// Get the errno associated with this error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a public API, so removing this needs to be mentioned in the CHANGELOG under the Removed section.

pub fn errno(&self) -> errno::Errno {
match *self {
Error::InvalidPath => errno::Errno::EINVAL,
Error::InvalidUtf8 => errno::Errno::UnknownErrno,
Error::Sys(errno) => errno,
}
}
}

impl From<errno::Errno> for Error {
Expand All @@ -139,6 +133,7 @@ impl error::Error for Error {
match self {
&Error::InvalidPath => "Invalid path",
&Error::InvalidUtf8 => "Invalid UTF-8 string",
&Error::UnsupportedOperation => "Unsupported Operation",
&Error::Sys(ref errno) => errno.desc(),
}
}
Expand All @@ -149,21 +144,12 @@ impl fmt::Display for Error {
match self {
&Error::InvalidPath => write!(f, "Invalid path"),
&Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
&Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
&Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
}
}
}

impl From<Error> for io::Error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another public API removed, please list this in the Removed section of the CHANGELOG.

fn from(err: Error) -> Self {
match err {
Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
Error::InvalidUtf8 => io::Error::new(io::ErrorKind::Other, err),
Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
}
}
}

pub trait NixPath {
fn len(&self) -> usize;

Expand Down
45 changes: 44 additions & 1 deletion src/sys/ptrace.rs
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -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)
}
Expand All @@ -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),
}
}