From b889ce3484a7be9a8c872a692042a7fee5a59821 Mon Sep 17 00:00:00 2001 From: Dominik Stolz Date: Sat, 3 Oct 2020 14:29:34 +0200 Subject: [PATCH] Add PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP support --- CHANGELOG.md | 2 ++ src/sys/ptrace/linux.rs | 47 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c208d7435..2073c046d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `clock_gettime`, `clock_settime`, `clock_getres`, `clock_getcpuclockid` functions and `ClockId` struct. (#[1281](https://github.com/nix-rust/nix/pull/1281)) +- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`. + (#[1300](https://github.com/nix-rust/nix/pull/1300)) ### Changed - Expose `SeekData` and `SeekHole` on all Linux targets (#[1284](https://github.com/nix-rust/nix/pull/1284)) diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index a0bae14fb5..8d1dd16e5d 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -109,6 +109,12 @@ libc_enum!{ #[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] PTRACE_PEEKSIGINFO, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU, + #[cfg(all(target_os = "linux", target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64")))] + PTRACE_SYSEMU_SINGLESTEP, } } @@ -278,7 +284,7 @@ pub fn traceme() -> Result<()> { } } -/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` /// /// Arranges for the tracee to be stopped at the next entry to or exit from a system call, /// optionally delivering a signal specified by `sig`. @@ -297,6 +303,23 @@ pub fn syscall>>(pid: Pid, sig: T) -> Result<()> { } } +/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` +/// +/// In contrast to the `syscall` function, the syscall stopped at will not be executed. +/// Thus the the tracee will only be stopped once per syscall, +/// optionally delivering a signal specified by `sig`. +#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +pub fn sysemu>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop) + // ignore the useless return value + } +} + /// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` /// /// Attaches to the process specified by `pid`, making it a tracee of the calling process. @@ -402,6 +425,28 @@ pub fn step>>(pid: Pid, sig: T) -> Result<()> { } } +/// Move the stopped tracee process forward by a single step or stop at the next syscall +/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` +/// +/// Advances the execution by a single step or until the next syscall. +/// In case the tracee is stopped at a syscall, the syscall will not be executed. +/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. +#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +pub fn sysemu_step>>(pid: Pid, sig: T) -> Result<()> { + let data = match sig.into() { + Some(s) => s as i32 as *mut c_void, + None => ptr::null_mut(), + }; + unsafe { + ptrace_other( + Request::PTRACE_SYSEMU_SINGLESTEP, + pid, + ptr::null_mut(), + data, + ) + .map(drop) // ignore the useless return value + } +} /// Reads a word from a processes memory at the given address pub fn read(pid: Pid, addr: AddressType) -> Result {