summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-10-03 14:17:25 +0000
committerGitHub <noreply@github.com>2020-10-03 14:17:25 +0000
commit7ed28204ec7de979d64802ee1621d5d09be61858 (patch)
treeaa17ceb1ee39c532e540cca7674b3df94ae32757 /src/sys
parent8e3789da81212269f5a871801beb5e6fc323111b (diff)
parentb889ce3484a7be9a8c872a692042a7fee5a59821 (diff)
downloadnix-7ed28204ec7de979d64802ee1621d5d09be61858.zip
Merge #1300
1300: Add PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP support r=asomers a=voidc Closes #1249. I think @jabedude was working on this, but as there was no progress since May I went ahead and implemented it myself. I'm not completely sure about the cfg gates. Could we enable the functions for more targets? I'm also open for suggestions of better names for the new functions. Co-authored-by: Dominik Stolz <d.stolz@tum.de>
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/ptrace/linux.rs47
1 files changed, 46 insertions, 1 deletions
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index a0bae14f..8d1dd16e 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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<c_long> {