diff --git a/src/header/mod.rs b/src/header/mod.rs index e11ffb4c14a15fda97e3233692f0f8dc65357ec5..25203a74c90bcc2e19162d18b95f7f2b7ef0f52a 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -37,6 +37,7 @@ pub mod sys_epoll; pub mod sys_file; pub mod sys_ioctl; pub mod sys_mman; +pub mod sys_ptrace; //pub mod sys_resource; pub mod sys_select; pub mod sys_socket; @@ -45,6 +46,7 @@ pub mod sys_statvfs; pub mod sys_time; pub mod sys_timeb; //pub mod sys_times; +pub mod sys_user; pub mod _wctype; pub mod sys_uio; pub mod sys_un; diff --git a/src/header/sys_ptrace/cbindgen.toml b/src/header/sys_ptrace/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..3ecacd053429f1e8ded5635cada8ba39c08e1089 --- /dev/null +++ b/src/header/sys_ptrace/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = [] +include_guard = "_SYS_PTRACE_H" +language = "C" +style = "Tag" + +[enum] +prefix_with_name = true diff --git a/src/header/sys_ptrace/mod.rs b/src/header/sys_ptrace/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b9cef5b7ed3fa8178eedc3ceeb2ab12087b05b82 --- /dev/null +++ b/src/header/sys_ptrace/mod.rs @@ -0,0 +1,24 @@ +//! ptrace compatibility layer for Redox OS + +use platform::types::*; +use platform::{Sys, PalPtrace}; + +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; + +#[no_mangle] +pub unsafe extern "C" fn ptrace(request: c_int, mut params: ...) -> c_int { + // Musl also just grabs the arguments from the varargs... + Sys::ptrace(request, params.arg(), params.arg(), params.arg()) +} diff --git a/src/header/sys_user/cbindgen.toml b/src/header/sys_user/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..63c05e2adcf029bd5a037f149dded486f4389060 --- /dev/null +++ b/src/header/sys_user/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = [] +include_guard = "_SYS_USER_H" +language = "C" +style = "Tag" + +[enum] +prefix_with_name = true diff --git a/src/header/sys_user/mod.rs b/src/header/sys_user/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..ca14bdeaef9f8528957f96ef4443b5618dd6e72a --- /dev/null +++ b/src/header/sys_user/mod.rs @@ -0,0 +1,52 @@ +//! A part of the ptrace compatibility for Redox OS + +use platform::types::*; + +#[repr(C)] +pub struct user_fpregs_struct { + cwd: u16, + swd: u16, + ftw: u16, + fop: u16, + rip: u64, + rdp: u64, + mxcsr: u32, + mxcr_mask: u32, + st_space: [u32; 32], + xmm_space: [u32; 64], + padding: [u32; 24] +} + +#[repr(C)] +pub struct user_regs_struct { + r15: c_ulong, + r14: c_ulong, + r13: c_ulong, + r12: c_ulong, + rbp: c_ulong, + rbx: c_ulong, + r11: c_ulong, + r10: c_ulong, + r9: c_ulong, + r8: c_ulong, + rax: c_ulong, + rcx: c_ulong, + rdx: c_ulong, + rsi: c_ulong, + rdi: c_ulong, + orig_rax: c_ulong, + rip: c_ulong, + cs: c_ulong, + eflags: c_ulong, + rsp: c_ulong, + ss: c_ulong, + fs_base: c_ulong, + gs_base: c_ulong, + ds: c_ulong, + es: c_ulong, + fs: c_ulong, + gs: c_ulong +} + +#[no_mangle] +pub extern "C" fn _cbindgen_only_generates_structs_if_they_are_mentioned_which_is_dumb(a: user_fpregs_struct, b: user_regs_struct) {} diff --git a/src/lib.rs b/src/lib.rs index 3ea4a1f0613d04d5567e28ee4d4b6073e3c5f839..268c6dcc8214bde17c503213e917be12e28c1157 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] #![allow(unused_variables)] -#![feature(alloc)] #![feature(allocator_api)] #![feature(asm)] #![feature(c_variadic)] @@ -13,6 +12,7 @@ #![feature(core_intrinsics)] #![feature(global_asm)] // FIXME: Stable on nightly, remove once redox fork is updated +#![feature(alloc)] #![feature(iter_copied)] #![feature(lang_items)] #![feature(linkage)] diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index af4a1115ed5763b270d3527faf81788703cf3b30..edd7be4bc77497d06c2404dbd068a379cb26f356 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -15,6 +15,7 @@ use header::sys_utsname::utsname; use header::time::timespec; mod epoll; +mod ptrace; mod signal; mod socket; diff --git a/src/platform/linux/ptrace.rs b/src/platform/linux/ptrace.rs new file mode 100644 index 0000000000000000000000000000000000000000..e2206ce60143bcd7f4f8c7c75189d7f1f7bd9825 --- /dev/null +++ b/src/platform/linux/ptrace.rs @@ -0,0 +1,9 @@ +use super::super::types::*; +use super::super::PalPtrace; +use super::{e, Sys}; + +impl PalPtrace for Sys { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int { + unsafe { e(syscall!(PTRACE, request, pid, addr, data)) as c_int } + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 047aee80dbf97c434287d42140a5cd1030075575..979899e99cfeafa5fa5f5a497e0ca0af371b8290 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -12,7 +12,7 @@ mod allocator; #[path = "allocator/ralloc.rs"] mod allocator; -pub use self::pal::{Pal, PalEpoll, PalSignal, PalSocket}; +pub use self::pal::{Pal, PalEpoll, PalPtrace, PalSignal, PalSocket}; mod pal; diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 8c542b3a14bdcf45385be22b9eb1cf3675ddf9b2..fde80078878882f63ba2105168b6ad18ac60e63c 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -10,6 +10,9 @@ use header::time::timespec; pub use self::epoll::PalEpoll; mod epoll; +pub use self::ptrace::PalPtrace; +mod ptrace; + pub use self::signal::PalSignal; mod signal; diff --git a/src/platform/pal/ptrace.rs b/src/platform/pal/ptrace.rs new file mode 100644 index 0000000000000000000000000000000000000000..d26d84c05adfc5844431404e9be33f6bf03ae847 --- /dev/null +++ b/src/platform/pal/ptrace.rs @@ -0,0 +1,6 @@ +use super::super::types::*; +use super::super::Pal; + +pub trait PalPtrace: Pal { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int; +} diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 317fbc44d9c8ec853f64d481ce9d50e015a41b84..9f854ef8d6cd4e95533cd12176029f0ebc35a2cf 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -28,6 +28,7 @@ use super::{errno, Pal, Read}; mod epoll; mod extra; +mod ptrace; mod signal; mod socket; diff --git a/src/platform/redox/ptrace.rs b/src/platform/redox/ptrace.rs new file mode 100644 index 0000000000000000000000000000000000000000..9c3c71803515fccdd570ea052541e0ba3282ae6c --- /dev/null +++ b/src/platform/redox/ptrace.rs @@ -0,0 +1,10 @@ +use super::super::types::*; +use super::super::PalPtrace; +use super::{e, Sys}; + +impl PalPtrace for Sys { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int { + // Oh boy, this is not gonna be fun......... + unimplemented!() + } +} diff --git a/tests/Makefile b/tests/Makefile index da4d243bbfa5a08a5dc9631d15a5afbb5d7fca70..388720a45847f850f683b207592bc23c6336320f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -15,6 +15,7 @@ EXPECT_NAMES=\ libgen \ locale \ math \ + ptrace \ regex \ select \ setjmp \ diff --git a/tests/expected/ptrace.stderr b/tests/expected/ptrace.stderr new file mode 100644 index 0000000000000000000000000000000000000000..289c82a876f1984bb4f573c71f1142c498a3731e --- /dev/null +++ b/tests/expected/ptrace.stderr @@ -0,0 +1,4 @@ +This is printed to STDOUT. +Or, at least, that's what I thought. +But all write(...) syscalls are actually redirected to STDERR by the tracer. +Big surprise, right! diff --git a/tests/expected/ptrace.stdout b/tests/expected/ptrace.stdout new file mode 100644 index 0000000000000000000000000000000000000000..8cc46e622268f5ce701809404e129b6a40fa7db3 --- /dev/null +++ b/tests/expected/ptrace.stdout @@ -0,0 +1 @@ +Child exited with status 0 diff --git a/tests/ptrace.c b/tests/ptrace.c new file mode 100644 index 0000000000000000000000000000000000000000..6b4dc936c03fb625c5887fa90db5271eee6f484c --- /dev/null +++ b/tests/ptrace.c @@ -0,0 +1,64 @@ +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "test_helpers.h" + +int main() { + int pid = fork(); + ERROR_IF(fork, pid, == -1); + + if (pid == 0) { + int result = ptrace(PTRACE_TRACEME, 0, NULL, NULL); + ERROR_IF(ptrace, result, == -1); + UNEXP_IF(ptrace, result, != 0); + + // Alert parent: I'm ready + result = raise(SIGSTOP); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + + puts("This is printed to STDOUT."); + puts("Or, at least, that's what I thought."); + puts("But all write(...) syscalls are actually redirected to STDERR by the tracer."); + puts("Big surprise, right!"); + } else { + // Wait for child process to be ready + int result = waitpid(pid, NULL, 0); + ERROR_IF(close, result, == -1); + + int status; + while (true) { + // Pre-syscall: + result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + result = waitpid(pid, &status, 0); + ERROR_IF(close, result, == -1); + if (WIFEXITED(status)) { break; } + + struct user_regs_struct regs; + result = ptrace(PTRACE_GETREGS, pid, NULL, ®s); + ERROR_IF(close, result, == -1); + + if (regs.orig_rax == 1 || regs.orig_rax == 0x21000004) { // SYS_write on Redox and Linux + regs.rdi = 2; + result = ptrace(PTRACE_SETREGS, pid, NULL, ®s); + ERROR_IF(close, result, == -1); + } + + // Post-syscall: + result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + result = waitpid(pid, &status, 0); + ERROR_IF(close, result, == -1); + if (WIFEXITED(status)) { break; } + } + printf("Child exited with status %d\n", WEXITSTATUS(status)); + } +}