diff --git a/Cargo.lock b/Cargo.lock
index 3e8b4a8cbeeb626ebac8548f19bb51a2c0d9e1fe..96e17e6e00c69724a11836ad9e2013851649ef70 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -152,6 +152,11 @@ name = "redox_syscall"
 version = "0.1.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "redox_syscall"
+version = "0.1.56"
+source = "git+https://gitlab.redox-os.org/redox-os/syscall#cceeae6ffe6967dc4bac0321de7bc739b2ae4da0"
+
 [[package]]
 name = "relibc"
 version = "0.1.0"
@@ -166,7 +171,7 @@ dependencies = [
  "posix-regex 0.1.0",
  "ralloc 1.0.0",
  "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall)",
  "sc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -271,6 +276,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
 "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
+"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall)" = "<none>"
 "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum sc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ebbb026ba4a707c25caec2db5ef59ad8b41f7ad77cad06257e06229c891f376"
diff --git a/Cargo.toml b/Cargo.toml
index 884f51829b4a78e8806e87baadf004f5dfcd6035..d9e36507b85f366d606b7cffbcb4a0539ec20a47 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,7 @@ optional = true
 sc = "0.2.2"
 
 [target.'cfg(target_os = "redox")'.dependencies]
-redox_syscall = "0.1.52"
+redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall" }
 spin = "0.4.10"
 
 [features]
diff --git a/include/bits/sys/wait.h b/include/bits/sys/wait.h
index 94d5a2ba0f2808a240eb166e2f410f6b67928483..7af6a82bbeca8f30bc430003d0b7fe838ebd33d6 100644
--- a/include/bits/sys/wait.h
+++ b/include/bits/sys/wait.h
@@ -1,13 +1,13 @@
 #ifndef _BITS_SYS_WAIT_H
 #define _BITS_SYS_WAIT_H
 
-#define WEXITSTATUS(s) (((s) & 0xff00) >> 8)
-#define WTERMSIG(s) ((s) & 0x7f)
+#define WEXITSTATUS(s) (((s) >> 8) & 0xff)
+#define WTERMSIG(s) (((s) & 0x7f) != 0)
 #define WSTOPSIG(s) WEXITSTATUS(s)
-#define WCOREDUMP(s) ((s) & 0x80)
-#define WIFEXITED(s) (!WTERMSIG(s))
-#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
-#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
+#define WCOREDUMP(s) (((s) & 0x80) != 0)
+#define WIFEXITED(s) (((s) & 0x7f) == 0)
+#define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
+#define WIFSIGNALED(s) (((((s) & 0x7f) + 1U) & 0x7f) >= 2) // Ends with 1111111 or 10000000
 #define WIFCONTINUED(s) ((s) == 0xffff)
 
 #endif /* _BITS_SYS_WAIT_H */
diff --git a/src/fs.rs b/src/fs.rs
index f3daf4bc20821d4127a0c5f1944f05791991e3d0..a479aeaaa96488e13ada2bab0843957c6fcdb31a 100644
--- a/src/fs.rs
+++ b/src/fs.rs
@@ -2,16 +2,10 @@ use c_str::CStr;
 use core::ops::Deref;
 use header::fcntl::O_CREAT;
 use header::unistd::{SEEK_CUR, SEEK_END, SEEK_SET};
-use io;
-use platform;
+use io::{self, last_os_error};
 use platform::types::*;
 use platform::{Pal, Sys};
 
-fn last_os_error() -> io::Error {
-    let errno = unsafe { platform::errno };
-    io::Error::from_raw_os_error(errno)
-}
-
 pub struct File {
     pub fd: c_int,
     /// To avoid self referential FILE struct that needs both a reader and a writer,
@@ -73,7 +67,7 @@ impl File {
     }
 }
 
-impl io::Read for File {
+impl io::Read for &File {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         match Sys::read(self.fd, buf) {
             -1 => Err(last_os_error()),
@@ -82,7 +76,7 @@ impl io::Read for File {
     }
 }
 
-impl io::Write for File {
+impl io::Write for &File {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         match Sys::write(self.fd, buf) {
             -1 => Err(last_os_error()),
@@ -95,7 +89,7 @@ impl io::Write for File {
     }
 }
 
-impl io::Seek for File {
+impl io::Seek for &File {
     fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
         let (offset, whence) = match pos {
             io::SeekFrom::Start(start) => (start as off_t, SEEK_SET),
@@ -110,6 +104,28 @@ impl io::Seek for File {
     }
 }
 
+impl io::Read for File {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (&mut &*self).read(buf)
+    }
+}
+
+impl io::Write for File {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&mut &*self).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&mut &*self).flush()
+    }
+}
+
+impl io::Seek for File {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        (&mut &*self).seek(pos)
+    }
+}
+
 impl Deref for File {
     type Target = c_int;
 
diff --git a/src/header/sys_ptrace/mod.rs b/src/header/sys_ptrace/mod.rs
index 8b40fa8b4e2ed980216f982fec7bb4f4493b7d8b..9a54c0725fe0e38fd9daf7ef7b85857016238ca9 100644
--- a/src/header/sys_ptrace/mod.rs
+++ b/src/header/sys_ptrace/mod.rs
@@ -19,6 +19,8 @@ pub const PTRACE_SETFPREGS: c_int = 15;
 pub const PTRACE_ATTACH: c_int = 16;
 pub const PTRACE_DETACH: c_int = 17;
 pub const PTRACE_SYSCALL: c_int = 24;
+pub const PTRACE_SYSEMU: c_int = 31;
+pub const PTRACE_SYSEMU_SINGLESTEP: c_int = 32;
 
 // Can't use "params: ..." syntax, because... guess what? Cbingen again :(
 #[no_mangle]
diff --git a/src/header/sys_user/mod.rs b/src/header/sys_user/mod.rs
index 826130ee827e6d27386b46451cf18670a9a7dd9c..2af4f4927a665b980816efe134b5f2d6c6b3f911 100644
--- a/src/header/sys_user/mod.rs
+++ b/src/header/sys_user/mod.rs
@@ -4,48 +4,48 @@ 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],
+    pub cwd: u16,
+    pub swd: u16,
+    pub ftw: u16,
+    pub fop: u16,
+    pub rip: u64,
+    pub rdp: u64,
+    pub mxcsr: u32,
+    pub mxcr_mask: u32,
+    pub st_space: [u32; 32],
+    pub xmm_space: [u32; 64],
+    pub 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,
+    pub r15: c_ulong,
+    pub r14: c_ulong,
+    pub r13: c_ulong,
+    pub r12: c_ulong,
+    pub rbp: c_ulong,
+    pub rbx: c_ulong,
+    pub r11: c_ulong,
+    pub r10: c_ulong,
+    pub r9: c_ulong,
+    pub r8: c_ulong,
+    pub rax: c_ulong,
+    pub rcx: c_ulong,
+    pub rdx: c_ulong,
+    pub rsi: c_ulong,
+    pub rdi: c_ulong,
+    pub orig_rax: c_ulong,
+    pub rip: c_ulong,
+    pub cs: c_ulong,
+    pub eflags: c_ulong,
+    pub rsp: c_ulong,
+    pub ss: c_ulong,
+    pub fs_base: c_ulong,
+    pub gs_base: c_ulong,
+    pub ds: c_ulong,
+    pub es: c_ulong,
+    pub fs: c_ulong,
+    pub gs: c_ulong,
 }
 
 #[no_mangle]
diff --git a/src/io.rs b/src/io.rs
index 42640cf1923df549dcab0b199d6b7b92f0a0b1c8..b09b83acf49362cbe5db990fb526928eec297013 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -1 +1,8 @@
 pub use core_io::*;
+
+pub fn last_os_error() -> Error {
+    use platform;
+
+    let errno = unsafe { platform::errno };
+    Error::from_raw_os_error(errno)
+}
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index 2c2c25ca22d0b6e046130165b75ad5c150435b4e..7db2c430d7de70430c02842780b979b39c52fb70 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -1,5 +1,3 @@
-//! sys/socket implementation, following http://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/socket.h.html
-
 use core::result::Result as CoreResult;
 use core::{mem, ptr, slice};
 use syscall::data::Map;
@@ -17,6 +15,7 @@ use header::sys_mman::MAP_ANON;
 use header::sys_stat::stat;
 use header::sys_statvfs::statvfs;
 use header::sys_time::{timeval, timezone};
+use header::sys_wait;
 use header::sys_utsname::{utsname, UTSLENGTH};
 use header::time::timespec;
 use header::unistd::{F_OK, R_OK, W_OK, X_OK};
@@ -909,14 +908,34 @@ impl Pal for Sys {
         if pid == !0 {
             pid = 0;
         }
+        let mut res = None;
+        let mut status = 0;
+
+        // First, allow ptrace to handle waitpid
+        let state = ptrace::init_state();
+        let sessions = state.sessions.lock();
+        if let Some(session) = sessions.get(&pid) {
+            if options & sys_wait::WNOHANG != sys_wait::WNOHANG {
+                let _ = (&mut &session.tracer).write(&[syscall::PTRACE_WAIT]);
+                res = Some(e(syscall::waitpid(pid as usize, &mut status, (options | sys_wait::WNOHANG) as usize)));
+                if res == Some(0) {
+                    // WNOHANG, just pretend ptrace SIGSTOP:ped this
+                    status = (syscall::SIGSTOP << 8) | 0x7f;
+                    res = Some(pid as usize);
+                }
+            }
+        }
+
+        // If ptrace didn't impact this waitpid, proceed as normal
+        let res = res.unwrap_or_else(|| e(syscall::waitpid(pid as usize, &mut status, options as usize)));
+
+        // If stat_loc is non-null, set that and the return
         unsafe {
-            let mut temp: usize = 0;
-            let res = e(syscall::waitpid(pid as usize, &mut temp, options as usize));
             if !stat_loc.is_null() {
-                *stat_loc = temp as c_int;
+                *stat_loc = status as c_int;
             }
-            res as pid_t
         }
+        res as pid_t
     }
 
     fn write(fd: c_int, buf: &[u8]) -> ssize_t {
diff --git a/src/platform/redox/ptrace.rs b/src/platform/redox/ptrace.rs
index 8a539c2dc43c736a007a2f92e9ee979564d16ef7..da82cd76f332aa4f99ff667bc5a4a6b053c27969 100644
--- a/src/platform/redox/ptrace.rs
+++ b/src/platform/redox/ptrace.rs
@@ -5,23 +5,152 @@
 //! compatibility. So, this module will be a hellhole.
 
 use super::super::types::*;
-use super::super::PalPtrace;
-use super::{e, Sys};
+use super::super::{errno, Pal, PalPtrace, PalSignal, Sys};
+use crate::c_str::CString;
+use crate::fs::File;
+use crate::header::sys_user::user_regs_struct;
+use crate::header::{errno as errnoh, fcntl, signal, sys_ptrace};
+use crate::io::{self, prelude::*};
 use crate::sync::{Mutex, Once};
 use alloc::collections::BTreeMap;
+use alloc::collections::btree_map::Entry;
+use syscall;
 
-#[derive(Default)]
-struct State {}
+pub struct Session {
+    pub tracer: File,
+    pub mem: File,
+    pub regs: File,
+    pub fpregs: File
+}
+pub struct State {
+    pub sessions: Mutex<BTreeMap<pid_t, Session>>
+}
+impl State {
+    fn new() -> Self {
+        Self {
+            sessions: Mutex::new(BTreeMap::new())
+        }
+    }
+}
+
+static STATE: Once<State> = Once::new();
+
+pub fn init_state() -> &'static State {
+    STATE.call_once(|| State::new())
+}
+
+fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> io::Result<c_int> {
+    let state = init_state();
+
+    if request == sys_ptrace::PTRACE_TRACEME {
+        // let pid = Sys::getpid();
+        // todo: only auto-open session on host if this happens
+        return Ok(0);
+    }
+
+    const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
 
-static STATE: Once<Mutex<State>> = Once::new();
+    let mut sessions = state.sessions.lock();
+    let session = match sessions.entry(pid) {
+        Entry::Vacant(entry) => entry.insert(Session {
+            tracer: File::open(&CString::new(format!("proc:{}/trace", pid)).unwrap(), NEW_FLAGS | fcntl::O_NONBLOCK)?,
+            mem: File::open(&CString::new(format!("proc:{}/mem", pid)).unwrap(), NEW_FLAGS)?,
+            regs: File::open(&CString::new(format!("proc:{}/regs/int", pid)).unwrap(), NEW_FLAGS)?,
+            fpregs: File::open(&CString::new(format!("proc:{}/regs/float", pid)).unwrap(), NEW_FLAGS)?,
+        }),
+        Entry::Occupied(entry) => entry.into_mut()
+    };
+    match request {
+        sys_ptrace::PTRACE_CONT | sys_ptrace::PTRACE_SINGLESTEP |
+        sys_ptrace::PTRACE_SYSCALL | sys_ptrace::PTRACE_SYSEMU |
+        sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
+            Sys::kill(pid, signal::SIGCONT as _);
 
-fn state() -> &'static Mutex<State> {
-    STATE.call_once(|| Mutex::new(State::default()))
+            (&mut &session.tracer).write(&[match request {
+                sys_ptrace::PTRACE_CONT => syscall::PTRACE_CONT,
+                sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_SINGLESTEP,
+                sys_ptrace::PTRACE_SYSCALL => syscall::PTRACE_SYSCALL,
+                sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_SYSEMU | syscall::PTRACE_SYSCALL,
+                sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => syscall::PTRACE_SYSEMU | syscall::PTRACE_SINGLESTEP,
+                _ => unreachable!("unhandled ptrace request type {}", request)
+            }])?;
+            Ok(0)
+        },
+        sys_ptrace::PTRACE_GETREGS => {
+            let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
+            let mut redox_regs = syscall::IntRegisters::default();
+            (&mut &session.regs).read(&mut redox_regs)?;
+            *c_regs = user_regs_struct {
+                r15: redox_regs.r15 as _,
+                r14: redox_regs.r14 as _,
+                r13: redox_regs.r13 as _,
+                r12: redox_regs.r12 as _,
+                rbp: redox_regs.rbp as _,
+                rbx: redox_regs.rbx as _,
+                r11: redox_regs.r11 as _,
+                r10: redox_regs.r10 as _,
+                r9: redox_regs.r9 as _,
+                r8: redox_regs.r8 as _,
+                rax: redox_regs.rax as _,
+                rcx: redox_regs.rcx as _,
+                rdx: redox_regs.rdx as _,
+                rsi: redox_regs.rsi as _,
+                rdi: redox_regs.rdi as _,
+                orig_rax: redox_regs.rax as _, // redox_regs.orig_rax as _,
+                rip: redox_regs.rip as _,
+                cs: redox_regs.cs as _,
+                eflags: redox_regs.rflags as _,
+                rsp: redox_regs.rsp as _,
+                ss: redox_regs.ss as _,
+                fs_base: 0, // fs_base: redox_regs.fs_base as _,
+                gs_base: 0, // gs_base: redox_regs.gs_base as _,
+                ds: 0, // ds: redox_regs.ds as _,
+                es: 0, // es: redox_regs.es as _,
+                fs: redox_regs.fs as _,
+                gs: 0, // gs: redox_regs.gs as _,
+            };
+            Ok(0)
+        },
+        sys_ptrace::PTRACE_SETREGS => {
+            let c_regs = unsafe { &*(data as *mut user_regs_struct) };
+            let redox_regs = syscall::IntRegisters {
+                r15: c_regs.r15 as _,
+                r14: c_regs.r14 as _,
+                r13: c_regs.r13 as _,
+                r12: c_regs.r12 as _,
+                rbp: c_regs.rbp as _,
+                rbx: c_regs.rbx as _,
+                r11: c_regs.r11 as _,
+                r10: c_regs.r10 as _,
+                r9: c_regs.r9 as _,
+                r8: c_regs.r8 as _,
+                rax: c_regs.orig_rax as _, // c_regs.rax as _,
+                rcx: c_regs.rcx as _,
+                rdx: c_regs.rdx as _,
+                rsi: c_regs.rsi as _,
+                rdi: c_regs.rdi as _,
+                // orig_rax: c_regs.orig_rax as _,
+                rip: c_regs.rip as _,
+                cs: c_regs.cs as _,
+                rflags: c_regs.eflags as _,
+                rsp: c_regs.rsp as _,
+                ss: c_regs.ss as _,
+                // fs_base: c_regs.fs_base as _,
+                // gs_base: c_regs.gs_base as _,
+                // ds: c_regs.ds as _,
+                // es: c_regs.es as _,
+                fs: c_regs.fs as _,
+                // gs: c_regs.gs as _,
+            };
+            (&mut &session.regs).write(&redox_regs)?;
+            Ok(0)
+        },
+        _ => unimplemented!()
+    }
 }
 
 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!()
+        inner_ptrace(request, pid, addr, data).unwrap_or(-1)
     }
 }
diff --git a/tests/ptrace.c b/tests/ptrace.c
index 6b4dc936c03fb625c5887fa90db5271eee6f484c..c2a1760b30eba9b3c50b4242c563377b4f4c0f2d 100644
--- a/tests/ptrace.c
+++ b/tests/ptrace.c
@@ -19,8 +19,8 @@ int main() {
 
         // Alert parent: I'm ready
         result = raise(SIGSTOP);
-        ERROR_IF(close, result, == -1);
-        UNEXP_IF(close, result, != 0);
+        ERROR_IF(raise, result, == -1);
+        UNEXP_IF(raise, result, != 0);
 
         puts("This is printed to STDOUT.");
         puts("Or, at least, that's what I thought.");
@@ -28,35 +28,35 @@ int main() {
         puts("Big surprise, right!");
     } else {
         // Wait for child process to be ready
-        int result = waitpid(pid, NULL, 0);
-        ERROR_IF(close, result, == -1);
+        int result = waitpid(pid, NULL, WUNTRACED);
+        ERROR_IF(waitpid, 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);
+            ERROR_IF(ptrace, result, == -1);
+            UNEXP_IF(ptrace, result, != 0);
             result = waitpid(pid, &status, 0);
-            ERROR_IF(close, result, == -1);
+            ERROR_IF(waitpid, result, == -1);
             if (WIFEXITED(status)) { break; }
 
             struct user_regs_struct regs;
             result = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
-            ERROR_IF(close, result, == -1);
+            ERROR_IF(ptrace, 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);
+                ERROR_IF(ptrace, result, == -1);
             }
 
             // Post-syscall:
             result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
-            ERROR_IF(close, result, == -1);
-            UNEXP_IF(close, result, != 0);
+            ERROR_IF(ptrace, result, == -1);
+            UNEXP_IF(ptrace, result, != 0);
             result = waitpid(pid, &status, 0);
-            ERROR_IF(close, result, == -1);
+            ERROR_IF(waitpid, result, == -1);
             if (WIFEXITED(status)) { break; }
         }
         printf("Child exited with status %d\n", WEXITSTATUS(status));