-
Notifications
You must be signed in to change notification settings - Fork 654
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Moved ptrace API into it's own module with cfg'ed modules exported for linux/android or BSDs. * Replicated current linux API for BSD * Added API functions to peek and poke memory to avoid needing to replicate deprecated linux API and remaining feature complete * Added helper function for `PTRACE_KILL` requests * Updated tests based on new API changes * Added addition kill calls to `test_ptrace_cont` as inferior death doesn't happen immediately on OSX which caused issues in the tests.
- Loading branch information
Showing
7 changed files
with
250 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
use errno::Errno; | ||
use libc::{self, c_int}; | ||
use std::ptr; | ||
use sys::signal::Signal; | ||
use unistd::Pid; | ||
use Result; | ||
|
||
pub type RequestType = c_int; | ||
|
||
cfg_if! { | ||
if #[cfg(any(target_os = "macos", | ||
target_os = "openbsd", | ||
target_os = "freebsd", | ||
target_os = "dragonfly"))] { | ||
#[doc(hidden)] | ||
pub type AddressType = *mut ::libc::c_char; | ||
} else { | ||
#[doc(hidden)] | ||
pub type AddressType = *mut ::libc::c_void; | ||
} | ||
} | ||
|
||
libc_enum! { | ||
#[repr(i32)] | ||
pub enum Request { | ||
PT_TRACE_ME, | ||
PT_READ_I, | ||
PT_READ_D, | ||
#[cfg(target_os = "macos")] | ||
PT_READ_U, | ||
PT_WRITE_I, | ||
PT_WRITE_D, | ||
#[cfg(target_os = "macos")] | ||
PT_WRITE_U, | ||
PT_CONTINUE, | ||
PT_KILL, | ||
#[cfg(any(any(target_os = "macos", | ||
target_os = "freebsd", | ||
target_os = "dragonfly"), | ||
all(target_os = "openbsd", target_arch = "x86_64"), | ||
all(target_os = "netbsd", any(target_arch = "x86_64", | ||
target_arch = "powerpc"))))] | ||
PT_STEP, | ||
PT_ATTACH, | ||
PT_DETACH, | ||
#[cfg(target_os = "macos")] | ||
PT_SIGEXC, | ||
#[cfg(target_os = "macos")] | ||
PT_THUPDATE, | ||
#[cfg(target_os = "macos")] | ||
PT_ATTACHEXC | ||
} | ||
} | ||
|
||
unsafe fn ptrace_other( | ||
request: Request, | ||
pid: Pid, | ||
addr: AddressType, | ||
data: c_int, | ||
) -> Result<c_int> { | ||
Errno::result(libc::ptrace( | ||
request as RequestType, | ||
libc::pid_t::from(pid), | ||
addr, | ||
data, | ||
)).map(|_| 0) | ||
} | ||
|
||
/// Sets the process as traceable, as with `ptrace(PT_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(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// Attach to a running process, as with `ptrace(PT_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(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` | ||
/// | ||
/// Detaches from the process specified in pid allowing it to run freely | ||
pub fn detach(pid: Pid) -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// 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 c_int, | ||
None => 0, | ||
}; | ||
unsafe { | ||
// Ignore the useless return value | ||
ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(|_| ()) | ||
} | ||
} | ||
|
||
/// Issues a kill request as with ptrace(PT_KILL, ..-) | ||
/// This request is equivalent to ptrace(PT_CONTINUE, ..., SIGKILL); | ||
pub fn kill(pid: Pid) -> Result<()> { | ||
unsafe { | ||
ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(|_| ()) | ||
} | ||
} | ||
|
||
/// Move the stopped tracee process forward by a single step as with | ||
/// `ptrace(PT_STEP, ...)` | ||
/// | ||
/// Advances the execution of the process with PID `pid` by a single step optionally delivering a | ||
/// signal specified by `sig`. | ||
/// | ||
/// # Example | ||
/// ```rust | ||
/// extern crate nix; | ||
/// use nix::sys::ptrace::step; | ||
/// use nix::unistd::Pid; | ||
/// use nix::sys::signal::Signal; | ||
/// use nix::sys::wait::*; | ||
/// fn main() { | ||
/// // If a process changes state to the stopped state because of a SIGUSR1 | ||
/// // signal, this will step the process forward and forward the user | ||
/// // signal to the stopped process | ||
/// match waitpid(Pid::from_raw(-1), None) { | ||
/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { | ||
/// let _ = step(pid, Signal::SIGUSR1); | ||
/// } | ||
/// _ => {}, | ||
/// } | ||
/// } | ||
/// ``` | ||
#[cfg( | ||
any( | ||
any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly"), | ||
all(target_os = "openbsd", target_arch = "x86_64"), | ||
all(target_os = "netbsd", | ||
any(target_arch = "x86_64", target_arch = "powerpc") | ||
) | ||
) | ||
)] | ||
pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { | ||
let data = match sig.into() { | ||
Some(s) => s as c_int, | ||
None => 0, | ||
}; | ||
unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(|_| ()) } | ||
} | ||
|
||
/// Reads a word from a processes memory at the given address | ||
pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { | ||
unsafe { | ||
// Traditionally there was a difference between reading data or | ||
// instruction memory but not in modern systems. | ||
ptrace_other(Request::PT_READ_D, pid, addr, 0) | ||
} | ||
} | ||
|
||
pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(|_| ()) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
///! Provides helpers for making ptrace system calls | ||
|
||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
mod linux; | ||
|
||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
pub use self::linux::*; | ||
|
||
#[cfg(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos", | ||
target_os = "netbsd", | ||
target_os = "openbsd"))] | ||
mod bsd; | ||
|
||
#[cfg(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
pub use self::bsd::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters