Skip to content

Commit

Permalink
Add WaitStatus::PtraceSyscall for use with PTRACE_O_TRACESYSGOOD
Browse files Browse the repository at this point in the history
The recommended way to trace syscalls with ptrace is to set the
PTRACE_O_TRACESYSGOOD option, to distinguish syscall stops from
receiving an actual SIGTRAP. In C, this would cause WSTOPSIG to return
SIGTRAP | 0x80, but nix wants to parse that as an actual signal.

Add another wait status type for syscall stops (in the language of the
ptrace(2) manpage, "PTRACE_EVENT stops" and "Syscall-stops" are
different things), and mask out bit 0x80 from signals before trying to
parse it.

Closes nix-rust#550
  • Loading branch information
geofft committed Mar 28, 2017
1 parent 0eef651 commit 7b40241
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/sys/wait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub enum WaitStatus {
Stopped(pid_t, Signal),
#[cfg(any(target_os = "linux", target_os = "android"))]
PtraceEvent(pid_t, Signal, c_int),
#[cfg(any(target_os = "linux", target_os = "android"))]
PtraceSyscall(pid_t),
Continued(pid_t),
StillAlive
}
Expand All @@ -55,6 +57,7 @@ pub enum WaitStatus {
mod status {
use sys::signal::Signal;
use libc::c_int;
use libc::SIGTRAP;

pub fn exited(status: i32) -> bool {
(status & 0x7F) == 0
Expand All @@ -81,7 +84,11 @@ mod status {
}

pub fn stop_signal(status: i32) -> Signal {
Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
Signal::from_c_int((status & 0x7F00) >> 8).unwrap()
}

pub fn syscall_stop(status: i32) -> bool {
((status & 0xFF00) >> 8) == SIGTRAP | 0x80
}

pub fn stop_additional(status: i32) -> c_int {
Expand Down Expand Up @@ -195,7 +202,9 @@ fn decode(pid : pid_t, status: i32) -> WaitStatus {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
fn decode_stopped(pid: pid_t, status: i32) -> WaitStatus {
let status_additional = status::stop_additional(status);
if status_additional == 0 {
if status::syscall_stop(status) {
WaitStatus::PtraceSyscall(pid)
} else if status_additional == 0 {
WaitStatus::Stopped(pid, status::stop_signal(status))
} else {
WaitStatus::PtraceEvent(pid, status::stop_signal(status), status::stop_additional(status))
Expand Down

0 comments on commit 7b40241

Please sign in to comment.