Browse Source

Stub for ptrace

It's happening...
jD91mZM2 5 years ago
parent
commit
e559a3e2e5

+ 2 - 0
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;

+ 7 - 0
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

+ 24 - 0
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())
+}

+ 7 - 0
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

+ 52 - 0
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) {}

+ 1 - 1
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)]

+ 1 - 0
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;
 

+ 9 - 0
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 }
+    }
+}

+ 1 - 1
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;
 

+ 3 - 0
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;
 

+ 6 - 0
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;
+}

+ 1 - 0
src/platform/redox/mod.rs

@@ -28,6 +28,7 @@ use super::{errno, Pal, Read};
 
 mod epoll;
 mod extra;
+mod ptrace;
 mod signal;
 mod socket;
 

+ 10 - 0
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!()
+    }
+}

+ 1 - 0
tests/Makefile

@@ -15,6 +15,7 @@ EXPECT_NAMES=\
 	libgen \
 	locale \
 	math \
+    ptrace \
 	regex \
 	select \
 	setjmp \

+ 4 - 0
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!

+ 1 - 0
tests/expected/ptrace.stdout

@@ -0,0 +1 @@
+Child exited with status 0

+ 64 - 0
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, &regs);
+            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, &regs);
+                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));
+    }
+}