diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs
index 7d58efd98267d5a185431b2bea12583e03549232..864a4c32f81c90fd27de00f44e3dbdda40360994 100644
--- a/src/arch/x86_64/interrupt/exception.rs
+++ b/src/arch/x86_64/interrupt/exception.rs
@@ -1,10 +1,5 @@
-use crate::{
-    common::unique::Unique,
-    context,
-    interrupt::stack_trace,
-    ptrace,
-    syscall::flag::*
-};
+use crate::interrupt::stack_trace;
+use crate::syscall::flag::*;
 
 extern {
     fn ksignal(signal: usize);
@@ -18,41 +13,9 @@ interrupt_stack_p!(divide_by_zero, stack, {
 });
 
 interrupt_stack!(debug, stack, {
-    match ptrace::breakpoint_callback_dryrun(true) {
-        Some(_) => {
-            {
-                let contexts = context::contexts();
-                if let Some(context) = contexts.current() {
-                    let mut context = context.write();
-                    if let Some(ref mut kstack) = context.kstack {
-                        context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(stack)));
-                    }
-                }
-            }
-
-            let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8;
-            stack.set_singlestep(false);
-            if ptrace::breakpoint_callback(true).is_none() {
-                // There is no guarantee that this is Some(_) just
-                // because the dryrun is Some(_). So, if there wasn't
-                // *actually* any breakpoint, restore the trap flag.
-                stack.set_singlestep(had_singlestep);
-            }
-
-            {
-                let contexts = context::contexts();
-                if let Some(context) = contexts.current() {
-                    let mut context = context.write();
-                    context.regs = None;
-                }
-            }
-        },
-        None => {
-            println!("Debug trap");
-            stack.dump();
-            ksignal(SIGTRAP);
-        }
-    }
+    println!("Debug trap");
+    stack.dump();
+    ksignal(SIGTRAP);
 });
 
 interrupt_stack!(non_maskable, stack, {
diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs
index fbc5bb87159574d344a5c9f9faee516aa2830f9d..6ffeb8c4271032f1ecdcb5253d75430c026f23d8 100644
--- a/src/arch/x86_64/interrupt/irq.rs
+++ b/src/arch/x86_64/interrupt/irq.rs
@@ -1,6 +1,5 @@
 use core::sync::atomic::{AtomicUsize, Ordering};
 
-use crate::common::unique::Unique;
 use crate::context;
 use crate::context::timeout;
 use crate::device::pic;
@@ -41,7 +40,7 @@ pub unsafe fn acknowledge(irq: usize) {
     }
 }
 
-interrupt_stack!(pit, stack, {
+interrupt!(pit, {
     // Saves CPU time by not sending IRQ event irq_trigger(0);
 
     const PIT_RATE: u64 = 2_250_286;
@@ -62,25 +61,7 @@ interrupt_stack!(pit, stack, {
     timeout::trigger();
 
     if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
-        {
-            let contexts = crate::context::contexts();
-            if let Some(context) = contexts.current() {
-                let mut context = context.write();
-                // Make all registers available to e.g. the proc:
-                // scheme
-                if let Some(ref mut kstack) = context.kstack {
-                    context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(stack)));
-                }
-            }
-        }
         let _ = context::switch();
-        {
-            let contexts = crate::context::contexts();
-            if let Some(context) = contexts.current() {
-                let mut context = context.write();
-                context.regs = None;
-            }
-        }
     }
 });
 
diff --git a/src/arch/x86_64/interrupt/syscall.rs b/src/arch/x86_64/interrupt/syscall.rs
index 2a4d68e74b74ebb158727b4cddf909ef30da123e..099904ffaea3f1523129653e14f99fcbb12efd01 100644
--- a/src/arch/x86_64/interrupt/syscall.rs
+++ b/src/arch/x86_64/interrupt/syscall.rs
@@ -1,74 +1,25 @@
-use crate::arch::macros::InterruptStack;
 use crate::arch::{gdt, pti};
-use crate::common::unique::Unique;
-use crate::{context, ptrace, syscall};
+use crate::syscall;
 use x86::shared::msr;
 
 pub unsafe fn init() {
     msr::wrmsr(msr::IA32_STAR, ((gdt::GDT_KERNEL_CODE as u64) << 3) << 32);
     msr::wrmsr(msr::IA32_LSTAR, syscall_instruction as u64);
-    msr::wrmsr(msr::IA32_FMASK, 0x0300); // Clear trap flag and interrupt enable
+    msr::wrmsr(msr::IA32_FMASK, 1 << 9);
     msr::wrmsr(msr::IA32_KERNEL_GS_BASE, &gdt::TSS as *const _ as u64);
 
     let efer = msr::rdmsr(msr::IA32_EFER);
     msr::wrmsr(msr::IA32_EFER, efer | 1);
 }
 
-// Not a function pointer because it somehow messes up the returning
-// from clone() (via clone_ret()). Not sure what the problem is.
-macro_rules! with_interrupt_stack {
-    (unsafe fn $wrapped:ident($stack:ident) -> usize $code:block) => {
-        /// Because of how clones work, we need a function that returns a
-        /// usize. Here, `inner` will be this function. The child process in a
-        /// clone will terminate this function with a 0 return value, and it
-        /// might also have updated the interrupt_stack pointer.
-        #[inline(never)]
-        unsafe fn $wrapped(stack: *mut SyscallStack) {
-            let stack = &mut *stack;
-            {
-                let contexts = context::contexts();
-                if let Some(context) = contexts.current() {
-                    let mut context = context.write();
-                    if let Some(ref mut kstack) = context.kstack {
-                        context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(&mut stack.interrupt_stack)));
-                    }
-                }
-            }
-
-            let is_sysemu = ptrace::breakpoint_callback(false);
-            if !is_sysemu.unwrap_or(false) {
-                // If not on a sysemu breakpoint
-                let $stack = &mut *stack;
-                $stack.interrupt_stack.scratch.rax = $code;
-
-                if is_sysemu.is_some() {
-                    // Only callback if there was a pre-syscall
-                    // callback too.
-                    ptrace::breakpoint_callback(false);
-                }
-            }
-
-            {
-                let contexts = context::contexts();
-                if let Some(context) = contexts.current() {
-                    let mut context = context.write();
-                    context.regs = None;
-                }
-            }
-        }
-    }
-}
-
 #[naked]
 pub unsafe extern fn syscall_instruction() {
-    with_interrupt_stack! {
-        unsafe fn inner(stack) -> usize {
-            let rbp;
-            asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");
-
-            let scratch = &stack.interrupt_stack.scratch;
-            syscall::syscall(scratch.rax, scratch.rdi, scratch.rsi, scratch.rdx, scratch.r10, scratch.r8, rbp, stack)
-        }
+    #[inline(never)]
+    unsafe fn inner(stack: &mut SyscallStack) -> usize {
+        let rbp;
+        asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");
+
+        syscall::syscall(stack.rax, stack.rdi, stack.rsi, stack.rdx, stack.r10, stack.r8, rbp, stack)
     }
 
     // Yes, this is magic. No, you don't need to understand
@@ -89,52 +40,76 @@ pub unsafe extern fn syscall_instruction() {
           :
           : "intel", "volatile");
 
-    // Push scratch registers
-    scratch_push!();
-    asm!("push fs
-         mov r11, 0x18
-         mov fs, r11
-         push rbx"
-         : : : : "intel", "volatile");
-
-    // Get reference to stack variables
-    let rsp: usize;
-    asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
-
-    // Map kernel
-    pti::map();
-
-    inner(rsp as *mut SyscallStack);
-
-    // Unmap kernel
-    pti::unmap();
-
-    // Interrupt return
-    asm!("pop rbx
-         pop fs"
-         : : : : "intel", "volatile");
-    scratch_pop!();
-    asm!("iretq" : : : : "intel", "volatile");
+      // Push scratch registers
+      asm!("push rax
+           push rbx
+           push rcx
+           push rdx
+           push rdi
+           push rsi
+           push r8
+           push r9
+           push r10
+           push r11
+           push fs
+           mov r11, 0x18
+           mov fs, r11"
+           : : : : "intel", "volatile");
+
+      // Get reference to stack variables
+      let rsp: usize;
+      asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
+
+      // Map kernel
+      pti::map();
+
+      let a = inner(&mut *(rsp as *mut SyscallStack));
+
+      // Unmap kernel
+      pti::unmap();
+
+      asm!("" : : "{rax}"(a) : : "intel", "volatile");
+
+      // Interrupt return
+      asm!("pop fs
+            pop r11
+            pop r10
+            pop r9
+            pop r8
+            pop rsi
+            pop rdi
+            pop rdx
+            pop rcx
+            pop rbx
+            add rsp, 8
+            iretq"
+            : : : : "intel", "volatile");
 }
 
 #[naked]
 pub unsafe extern fn syscall() {
-    with_interrupt_stack! {
-        unsafe fn inner(stack) -> usize {
-            let rbp;
-            asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");
-
-            let scratch = &stack.interrupt_stack.scratch;
-            syscall::syscall(scratch.rax, stack.rbx, scratch.rcx, scratch.rdx, scratch.rsi, scratch.rdi, rbp, stack)
-        }
+    #[inline(never)]
+    unsafe fn inner(stack: &mut SyscallStack) -> usize {
+        let rbp;
+        asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");
+
+        syscall::syscall(stack.rax, stack.rbx, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack)
     }
 
     // Push scratch registers
-    scratch_push!();
-    asm!("push fs
+    asm!("push rax
+         push rbx
+         push rcx
+         push rdx
+         push rdi
+         push rsi
+         push r8
+         push r9
+         push r10
+         push r11
+         push fs
          mov r11, 0x18
-         mov fs, r11
-         push rbx"
+         mov fs, r11"
          : : : : "intel", "volatile");
 
     // Get reference to stack variables
@@ -144,41 +119,56 @@ pub unsafe extern fn syscall() {
     // Map kernel
     pti::map();
 
-    inner(rsp as *mut SyscallStack);
+    let a = inner(&mut *(rsp as *mut SyscallStack));
 
     // Unmap kernel
     pti::unmap();
 
+    asm!("" : : "{rax}"(a) : : "intel", "volatile");
+
     // Interrupt return
-    asm!("pop rbx
-         pop fs"
-         : : : : "intel", "volatile");
-    scratch_pop!();
-    asm!("iretq" : : : : "intel", "volatile");
+    asm!("pop fs
+          pop r11
+          pop r10
+          pop r9
+          pop r8
+          pop rsi
+          pop rdi
+          pop rdx
+          pop rcx
+          pop rbx
+          add rsp, 8
+          iretq"
+          : : : : "intel", "volatile");
 }
 
 #[allow(dead_code)]
 #[repr(packed)]
 pub struct SyscallStack {
+    pub fs: usize,
+    pub r11: usize,
+    pub r10: usize,
+    pub r9: usize,
+    pub r8: usize,
+    pub rsi: usize,
+    pub rdi: usize,
+    pub rdx: usize,
+    pub rcx: usize,
     pub rbx: usize,
-    pub interrupt_stack: InterruptStack,
-
+    pub rax: usize,
+    pub rip: usize,
+    pub cs: usize,
+    pub rflags: usize,
     // Will only be present if syscall is called from another ring
     pub rsp: usize,
     pub ss: usize,
 }
 
 #[naked]
-pub unsafe extern "C" fn clone_ret() {
-    // The C x86_64 ABI specifies that rbp is pushed to save the old
-    // call frame. Popping rbp means we're using the parent's call
-    // frame and thus will not only return from this function but also
-    // from the function above this one.
-    // When this is called, the stack should have been
-    // interrupt->inner->syscall->clone
-    // then changed to
-    // interrupt->inner->clone_ret->clone
-    // so this will return from "inner".
-
-    asm!("pop rbp" : : : : "intel", "volatile");
+pub unsafe extern fn clone_ret() {
+    asm!("
+        pop rbp
+        xor rax, rax
+        "
+        : : : : "intel", "volatile");
 }
diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs
index da0b037377ce28b034b39afd355f1ff2971bdc2f..d41ee9338b0c9d0395704274b926f6c0dc792c94 100644
--- a/src/arch/x86_64/macros.rs
+++ b/src/arch/x86_64/macros.rs
@@ -1,5 +1,3 @@
-use syscall::data::IntRegisters;
-
 /// Print to console
 #[macro_export]
 macro_rules! print {
@@ -206,50 +204,6 @@ impl InterruptStack {
         self.scratch.dump();
         println!("FS:    {:>016X}", { self.fs });
     }
-    /// Saves all registers to a struct used by the proc:
-    /// scheme to read/write registers.
-    pub fn save(&self, all: &mut IntRegisters) {
-        all.fs = self.fs;
-        all.r11 = self.scratch.r11;
-        all.r10 = self.scratch.r10;
-        all.r9 = self.scratch.r9;
-        all.r8 = self.scratch.r8;
-        all.rsi = self.scratch.rsi;
-        all.rdi = self.scratch.rdi;
-        all.rdx = self.scratch.rdx;
-        all.rcx = self.scratch.rcx;
-        all.rax = self.scratch.rax;
-        all.rip = self.iret.rip;
-        all.cs = self.iret.cs;
-        all.eflags = self.iret.rflags;
-    }
-    /// Loads all registers from a struct used by the proc:
-    /// scheme to read/write registers.
-    pub fn load(&mut self, all: &IntRegisters) {
-        self.fs = all.fs;
-        self.scratch.r11 = all.r11;
-        self.scratch.r10 = all.r10;
-        self.scratch.r9 = all.r9;
-        self.scratch.r8 = all.r8;
-        self.scratch.rsi = all.rsi;
-        self.scratch.rdi = all.rdi;
-        self.scratch.rdx = all.rdx;
-        self.scratch.rcx = all.rcx;
-        self.scratch.rax = all.rax;
-        self.iret.rip = all.rip;
-        self.iret.cs = all.cs;
-        self.iret.rflags = all.eflags;
-    }
-    /// Enables the "Trap Flag" in the FLAGS register, causing the CPU
-    /// to send a Debug exception after the next instruction. This is
-    /// used for singlestep in the proc: scheme.
-    pub fn set_singlestep(&mut self, enabled: bool) {
-        if enabled {
-            self.iret.rflags |= 1 << 8;
-        } else {
-            self.iret.rflags &= !(1 << 8);
-        }
-    }
 }
 
 #[macro_export]
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 7ad826b3c8b793cd4872df57e6e4ceaea44e6d9d..29f6412e8a85bc9b664e0c39b2ea731f6bfe0ca9 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -1,3 +1,2 @@
 #[macro_use]
 pub mod int_like;
-pub mod unique;
diff --git a/src/common/unique.rs b/src/common/unique.rs
deleted file mode 100644
index 214f5b53a3a02dd1ab23f2e3f9e6d79e0f5a9d71..0000000000000000000000000000000000000000
--- a/src/common/unique.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use core::{fmt, ptr::NonNull};
-
-/// A small wrapper around NonNull<T> that is Send + Sync, which is
-/// only correct if the pointer is never accessed from multiple
-/// locations across threads. Which is always, if the pointer is
-/// unique.
-pub struct Unique<T>(NonNull<T>);
-
-impl<T> Copy for Unique<T> {}
-impl<T> Clone for Unique<T> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-unsafe impl<T> Send for Unique<T> {}
-unsafe impl<T> Sync for Unique<T> {}
-
-impl<T> Unique<T> {
-    pub fn new(ptr: *mut T) -> Self {
-        Self(NonNull::new(ptr).unwrap())
-    }
-    pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
-        Self(NonNull::new_unchecked(ptr))
-    }
-    pub fn as_ptr(&self) -> *mut T {
-        self.0.as_ptr()
-    }
-}
-impl<T> fmt::Debug for Unique<T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
diff --git a/src/context/context.rs b/src/context/context.rs
index 269b4ee4095953e4fa4302edac360205d76cfe67..c27f7de3e5341da1567086e14ce584ab0bba8ca1 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -7,16 +7,15 @@ use core::cmp::Ordering;
 use core::mem;
 use spin::Mutex;
 
-use crate::arch::{macros::InterruptStack, paging::PAGE_SIZE};
-use crate::common::unique::Unique;
+use crate::arch::paging::PAGE_SIZE;
 use crate::context::arch;
 use crate::context::file::FileDescriptor;
 use crate::context::memory::{Grant, Memory, SharedMemory, Tls};
 use crate::ipi::{ipi, IpiKind, IpiTarget};
 use crate::scheme::{SchemeNamespace, FileHandle};
-use crate::sync::WaitMap;
 use crate::syscall::data::SigAction;
 use crate::syscall::flag::SIG_DFL;
+use crate::sync::WaitMap;
 
 /// Unique identifier for a context (i.e. `pid`).
 use ::core::sync::atomic::AtomicUsize;
@@ -166,15 +165,6 @@ pub struct Context {
     pub files: Arc<Mutex<Vec<Option<FileDescriptor>>>>,
     /// Signal actions
     pub actions: Arc<Mutex<Vec<(SigAction, usize)>>>,
-    /// The pointer to the user-space registers, saved after certain
-    /// interrupts. This pointer is somewhere inside kstack, and the
-    /// kstack address at the time of creation is the first element in
-    /// this tuple.
-    pub regs: Option<(usize, Unique<InterruptStack>)>,
-    /// A somewhat hacky way to initially stop a context when creating
-    /// a new instance of the proc: scheme, entirely separate from
-    /// signals or any other way to restart a process.
-    pub ptrace_stop: bool
 }
 
 impl Context {
@@ -226,8 +216,6 @@ impl Context {
                 },
                 0
             ); 128])),
-            regs: None,
-            ptrace_stop: false
         }
     }
 
diff --git a/src/context/switch.rs b/src/context/switch.rs
index cf55220fc802dbbcbda6456318df42a4fcf20efa..7d2536575cbf55a33b3f41622e121c7705ffa271 100644
--- a/src/context/switch.rs
+++ b/src/context/switch.rs
@@ -55,7 +55,7 @@ unsafe fn update(context: &mut Context, cpu_id: usize) {
 
 unsafe fn runnable(context: &Context, cpu_id: usize) -> bool {
     // Switch to context if it needs to run, is not currently running, and is owned by the current CPU
-    !context.running && !context.ptrace_stop && context.status == Status::Runnable && context.cpu_id == Some(cpu_id)
+    !context.running && context.status == Status::Runnable && context.cpu_id == Some(cpu_id)
 }
 
 /// Switch to the next context
diff --git a/src/lib.rs b/src/lib.rs
index 24b265af194e42401320a04a2a3b7f421b610a60..109ea3914800449f84374a86d4bedd6798a94033 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -93,9 +93,6 @@ pub mod memory;
 #[cfg(not(any(feature="doc", test)))]
 pub mod panic;
 
-/// Process tracing
-pub mod ptrace;
-
 /// Schemes, filesystem handlers
 pub mod scheme;
 
diff --git a/src/ptrace.rs b/src/ptrace.rs
deleted file mode 100644
index 5f8cb2763c0a368ab750820d9d9f86965dde9a77..0000000000000000000000000000000000000000
--- a/src/ptrace.rs
+++ /dev/null
@@ -1,208 +0,0 @@
-use crate::{
-    arch::macros::InterruptStack,
-    common::unique::Unique,
-    context::{self, Context, ContextId, Status},
-    sync::WaitCondition
-};
-
-use alloc::{
-    boxed::Box,
-    collections::BTreeMap,
-    sync::Arc
-};
-use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
-use syscall::error::*;
-
-//  ____                 _                _       _
-// | __ ) _ __ ___  __ _| | ___ __   ___ (_)_ __ | |_ ___
-// |  _ \| '__/ _ \/ _` | |/ / '_ \ / _ \| | '_ \| __/ __|
-// | |_) | | |  __/ (_| |   <| |_) | (_) | | | | | |_\__ \
-// |____/|_|  \___|\__,_|_|\_\ .__/ \___/|_|_| |_|\__|___/
-//                           |_|
-
-struct Handle {
-    tracee: Arc<WaitCondition>,
-    tracer: Arc<WaitCondition>,
-    reached: bool,
-
-    sysemu: bool,
-    singlestep: bool
-}
-
-static BREAKPOINTS: Once<RwLock<BTreeMap<ContextId, Handle>>> = Once::new();
-
-fn init_breakpoints() -> RwLock<BTreeMap<ContextId, Handle>> {
-    RwLock::new(BTreeMap::new())
-}
-fn breakpoints() -> RwLockReadGuard<'static, BTreeMap<ContextId, Handle>> {
-    BREAKPOINTS.call_once(init_breakpoints).read()
-}
-fn breakpoints_mut() -> RwLockWriteGuard<'static, BTreeMap<ContextId, Handle>> {
-    BREAKPOINTS.call_once(init_breakpoints).write()
-}
-
-fn inner_cont(pid: ContextId) -> Option<Handle> {
-    // Remove the breakpoint to both save space and also make sure any
-    // yet unreached but obsolete breakpoints don't stop the program.
-    let handle = breakpoints_mut().remove(&pid)?;
-    handle.tracee.notify();
-    Some(handle)
-}
-
-/// Continue the process with the specified ID
-pub fn cont(pid: ContextId) {
-    inner_cont(pid);
-}
-
-/// Create a new breakpoint for the specified tracee, optionally with a sysemu flag
-pub fn set_breakpoint(pid: ContextId, sysemu: bool, singlestep: bool) {
-    let (tracee, tracer) = match inner_cont(pid) {
-        Some(breakpoint) => (breakpoint.tracee, breakpoint.tracer),
-        None => (
-            Arc::new(WaitCondition::new()),
-            Arc::new(WaitCondition::new())
-        )
-    };
-
-    breakpoints_mut().insert(pid, Handle {
-        tracee,
-        tracer,
-        reached: false,
-        sysemu,
-        singlestep
-    });
-}
-
-/// Wait for the tracee to stop.
-/// Note: Don't call while holding any locks, this will switch contexts
-pub fn wait_breakpoint(pid: ContextId) -> Result<()> {
-    let tracer = {
-        let breakpoints = breakpoints();
-        match breakpoints.get(&pid) {
-            Some(breakpoint) if !breakpoint.reached => Arc::clone(&breakpoint.tracer),
-            _ => return Ok(())
-        }
-    };
-    while !tracer.wait() {}
-
-    let contexts = context::contexts();
-    let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
-    let context = context.read();
-    if let Status::Exited(_) = context.status {
-        return Err(Error::new(ESRCH));
-    }
-    Ok(())
-}
-
-/// Returns the same value as breakpoint_callback would do, but
-/// doesn't actually perform the action. You should not rely too
-/// heavily on this value, as the lock *is* released between this call
-/// and another.
-pub fn breakpoint_callback_dryrun(singlestep: bool) -> Option<bool> {
-    let contexts = context::contexts();
-    let context = contexts.current()?;
-    let context = context.read();
-
-    let breakpoints = breakpoints();
-    let breakpoint = breakpoints.get(&context.id)?;
-    if breakpoint.singlestep != singlestep {
-        return None;
-    }
-    Some(breakpoint.sysemu)
-}
-
-/// Notify the tracer and await green flag to continue.
-/// Note: Don't call while holding any locks, this will switch contexts
-pub fn breakpoint_callback(singlestep: bool) -> Option<bool> {
-    // Can't hold any locks when executing wait()
-    let (tracee, sysemu) = {
-        let contexts = context::contexts();
-        let context = contexts.current()?;
-        let context = context.read();
-
-        let mut breakpoints = breakpoints_mut();
-        let breakpoint = breakpoints.get_mut(&context.id)?;
-
-        // TODO: How should singlesteps interact with syscalls? How
-        // does Linux handle this?
-
-        // if singlestep && !breakpoint.singlestep {
-        if breakpoint.singlestep != singlestep {
-            return None;
-        }
-
-        breakpoint.tracer.notify();
-        // In case no tracer is waiting, make sure the next one gets
-        // the memo
-        breakpoint.reached = true;
-
-        (
-            Arc::clone(&breakpoint.tracee),
-            breakpoint.sysemu
-        )
-    };
-
-    while !tracee.wait() {}
-
-    Some(sysemu)
-}
-
-/// Call when a context is closed to alert any tracers
-pub fn close(pid: ContextId) {
-    {
-        let breakpoints = breakpoints();
-        if let Some(breakpoint) = breakpoints.get(&pid) {
-            breakpoint.tracer.notify();
-        }
-    }
-
-    breakpoints_mut().remove(&pid);
-}
-
-//  ____            _     _
-// |  _ \ ___  __ _(_)___| |_ ___ _ __ ___
-// | |_) / _ \/ _` | / __| __/ _ \ '__/ __|
-// |  _ <  __/ (_| | \__ \ ||  __/ |  \__ \
-// |_| \_\___|\__, |_|___/\__\___|_|  |___/
-//            |___/
-
-/// Return the InterruptStack pointer, but relative to the specified
-/// stack instead of the original.
-pub unsafe fn rebase_regs_ptr(
-    regs: Option<(usize, Unique<InterruptStack>)>,
-    kstack: Option<&Box<[u8]>>
-) -> Option<*const InterruptStack> {
-    let (old_base, ptr) = regs?;
-    let new_base = kstack?.as_ptr() as usize;
-    Some((ptr.as_ptr() as usize - old_base + new_base) as *const _)
-}
-/// Return the InterruptStack pointer, but relative to the specified
-/// stack instead of the original.
-pub unsafe fn rebase_regs_ptr_mut(
-    regs: Option<(usize, Unique<InterruptStack>)>,
-    kstack: Option<&mut Box<[u8]>>
-) -> Option<*mut InterruptStack> {
-    let (old_base, ptr) = regs?;
-    let new_base = kstack?.as_mut_ptr() as usize;
-    Some((ptr.as_ptr() as usize - old_base + new_base) as *mut _)
-}
-
-/// Return a reference to the InterruptStack struct in memory. If the
-/// kernel stack has been backed up by a signal handler, this instead
-/// returns the struct inside that memory, as that will later be
-/// restored and otherwise undo all your changes. See `update(...)` in
-/// context/switch.rs.
-pub unsafe fn regs_for(context: &Context) -> Option<&InterruptStack> {
-    Some(&*match context.ksig {
-        Some((_, _, ref kstack)) => rebase_regs_ptr(context.regs, kstack.as_ref())?,
-        None => context.regs?.1.as_ptr()
-    })
-}
-
-/// Mutable version of `regs_for`
-pub unsafe fn regs_for_mut(context: &mut Context) -> Option<&mut InterruptStack> {
-    Some(&mut *match context.ksig {
-        Some((_, _, ref mut kstack)) => rebase_regs_ptr_mut(context.regs, kstack.as_mut())?,
-        None => context.regs?.1.as_ptr()
-    })
-}
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index da5f5cd783221cd86b2c8048506d58855ec0a877..4cf995830f4213a1ac9eff74e4b12943c3c52ea8 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -22,7 +22,6 @@ use self::irq::IrqScheme;
 use self::itimer::ITimerScheme;
 use self::memory::MemoryScheme;
 use self::pipe::PipeScheme;
-use self::proc::ProcScheme;
 use self::root::RootScheme;
 use self::sys::SysScheme;
 use self::time::TimeScheme;
@@ -52,9 +51,6 @@ pub mod memory;
 /// `pipe:` - used internally by the kernel to implement `pipe`
 pub mod pipe;
 
-/// `proc:` - allows tracing processes and reading/writing their memory
-pub mod proc;
-
 /// `:` - allows the creation of userspace schemes, tightly dependent on `user`
 pub mod root;
 
@@ -132,21 +128,29 @@ impl SchemeList {
     }
 
     /// Initialize the root namespace
+    #[cfg(not(feature="live"))]
     fn new_root(&mut self) {
         // Do common namespace initialization
         let ns = self.new_ns();
 
-        // These schemes should only be available on the root
+        // Debug, Initfs and IRQ are only available in the root namespace. Pipe is special
         self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
         self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
         self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
-        self.insert(ns, Box::new(*b"proc"), |_| Arc::new(Box::new(ProcScheme::new()))).unwrap();
+        self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
+    }
 
-        #[cfg(feature = "live")] {
-            self.insert(ns, Box::new(*b"disk/live"), |_| Arc::new(Box::new(self::live::DiskScheme::new()))).unwrap();
-        }
+    /// Initialize the root namespace - with live disk
+    #[cfg(feature="live")]
+    fn new_root(&mut self) {
+        // Do common namespace initialization
+        let ns = self.new_ns();
 
-        // Pipe is special and needs to be in the root namespace
+        // Debug, Disk, Initfs and IRQ are only available in the root namespace. Pipe is special
+        self.insert(ns, Box::new(*b"debug"), |scheme_id| Arc::new(Box::new(DebugScheme::new(scheme_id)))).unwrap();
+        self.insert(ns, Box::new(*b"disk/live"), |_| Arc::new(Box::new(self::live::DiskScheme::new()))).unwrap();
+        self.insert(ns, Box::new(*b"initfs"), |_| Arc::new(Box::new(InitFsScheme::new()))).unwrap();
+        self.insert(ns, Box::new(*b"irq"), |scheme_id| Arc::new(Box::new(IrqScheme::new(scheme_id)))).unwrap();
         self.insert(ns, Box::new(*b"pipe"), |scheme_id| Arc::new(Box::new(PipeScheme::new(scheme_id)))).unwrap();
     }
 
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
deleted file mode 100644
index 6edd478571b82eb9773cb52885790a6f5877abb3..0000000000000000000000000000000000000000
--- a/src/scheme/proc.rs
+++ /dev/null
@@ -1,351 +0,0 @@
-use crate::{
-    context::{self, ContextId, Status},
-    ptrace
-};
-
-use alloc::collections::{BTreeMap, BTreeSet};
-use core::{
-    cmp,
-    mem,
-    slice,
-    sync::atomic::{AtomicUsize, Ordering}
-};
-use spin::{Mutex, RwLock};
-use syscall::{
-    data::{IntRegisters, FloatRegisters},
-    error::*,
-    flag::*,
-    scheme::Scheme
-};
-
-#[derive(Clone, Copy)]
-enum RegsKind {
-    Float,
-    Int
-}
-#[derive(Clone, Copy)]
-enum Operation {
-    Memory,
-    Regs(RegsKind),
-    Trace
-}
-
-#[derive(Clone, Copy)]
-struct Handle {
-    flags: usize,
-    pid: ContextId,
-    operation: Operation
-}
-
-pub struct ProcScheme {
-    next_id: AtomicUsize,
-    handles: RwLock<BTreeMap<usize, Handle>>,
-    traced: Mutex<BTreeSet<ContextId>>
-}
-
-impl ProcScheme {
-    pub fn new() -> Self {
-        Self {
-            next_id: AtomicUsize::new(0),
-            handles: RwLock::new(BTreeMap::new()),
-            traced: Mutex::new(BTreeSet::new())
-        }
-    }
-}
-
-impl Scheme for ProcScheme {
-    fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> {
-        let path = core::str::from_utf8(path).map_err(|_| Error::new(EINVAL))?;
-        let mut parts = path.splitn(2, '/');
-        let pid = parts.next()
-            .and_then(|s| s.parse().ok())
-            .map(ContextId::from)
-            .ok_or(Error::new(EINVAL))?;
-        let operation = match parts.next() {
-            Some("mem") => Operation::Memory,
-            Some("regs/float") => Operation::Regs(RegsKind::Float),
-            Some("regs/int") => Operation::Regs(RegsKind::Int),
-            Some("trace") => Operation::Trace,
-            _ => return Err(Error::new(EINVAL))
-        };
-
-        let contexts = context::contexts();
-        let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
-
-        {
-            // TODO: Put better security here?
-
-            let context = context.read();
-            if uid != 0 && gid != 0
-            && uid != context.euid && gid != context.egid {
-                return Err(Error::new(EPERM));
-            }
-        }
-
-        if let Operation::Trace = operation {
-            let mut traced = self.traced.lock();
-
-            if traced.contains(&pid) {
-                return Err(Error::new(EBUSY));
-            }
-            traced.insert(pid);
-
-            let mut context = context.write();
-            context.ptrace_stop = true;
-        }
-
-        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
-        self.handles.write().insert(id, Handle {
-            flags,
-            pid,
-            operation
-        });
-        Ok(id)
-    }
-
-    /// Using dup for `proc:` simply opens another operation on the same PID
-    /// ```rust,ignore
-    /// let trace = syscall::open("proc:1234/trace")?;
-    ///
-    /// // let regs = syscall::open("proc:1234/regs/int")?;
-    /// let regs = syscall::dup(trace, "regs/int")?;
-    /// ```
-    fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
-        let handle = {
-            let handles = self.handles.read();
-            *handles.get(&old_id).ok_or(Error::new(EBADF))?
-        };
-        let mut path = format!("{}/", handle.pid.into()).into_bytes();
-        path.extend_from_slice(buf);
-
-        let (uid, gid) = {
-            let contexts = context::contexts();
-            let context = contexts.current().ok_or(Error::new(ESRCH))?;
-            let context = context.read();
-            (context.euid, context.egid)
-        };
-
-        self.open(&path, handle.flags, uid, gid)
-    }
-
-    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
-        // Can't hold locks during the context switch later when
-        // waiting for a process to stop running.
-        let handle = {
-            let handles = self.handles.read();
-            *handles.get(&id).ok_or(Error::new(EBADF))?
-        };
-
-        match handle.operation {
-            Operation::Memory => {
-                // let contexts = context::contexts();
-                // let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                // let context = context.read();
-
-                // for grant in &*context.grants.lock() {
-                //     println!("Grant: {} -> {}", grant.start.get(), grant.size);
-                // }
-                // unimplemented!();
-                return Err(Error::new(EBADF));
-            },
-            Operation::Regs(kind) => {
-                union Output {
-                    _float: FloatRegisters,
-                    int: IntRegisters
-                }
-                let mut first = true;
-                let (output, size) = loop {
-                    if !first {
-                        // We've tried this before, so lets wait before retrying
-                        unsafe { context::switch(); }
-                    }
-                    first = false;
-
-                    let contexts = context::contexts();
-                    let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                    let context = context.read();
-
-                    break match kind {
-                        RegsKind::Float => {
-                            // TODO!!
-                            // (Output { float: FloatRegisters::default() }, mem::size_of::<FloatRegisters>())
-                            return Err(Error::new(EBADF));
-                        },
-                        RegsKind::Int => match unsafe { ptrace::regs_for(&context) } {
-                            None => {
-                                // Another CPU is running this process, wait until it's stopped.
-                                continue;
-                            },
-                            Some(stack) => {
-                                let mut regs = IntRegisters::default();
-
-                                stack.save(&mut regs);
-
-                                (Output { int: regs }, mem::size_of::<IntRegisters>())
-                            }
-                        }
-                    };
-                };
-
-                let bytes = unsafe {
-                    slice::from_raw_parts(&output as *const _ as *const u8, mem::size_of::<Output>())
-                };
-                let len = cmp::min(buf.len(), size);
-                buf[..len].copy_from_slice(&bytes[..len]);
-
-                Ok(len)
-            },
-            Operation::Trace => Err(Error::new(EBADF))
-        }
-    }
-
-    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
-        // Can't hold locks during the context switch later when
-        // waiting for a process to stop running.
-        let handle = {
-            let handles = self.handles.read();
-            *handles.get(&id).ok_or(Error::new(EBADF))?
-        };
-
-        let mut first = true;
-        match handle.operation {
-            Operation::Memory => {
-                // unimplemented!()
-                return Err(Error::new(EBADF));
-            },
-            Operation::Regs(kind) => loop {
-                if !first {
-                    // We've tried this before, so lets wait before retrying
-                    unsafe { context::switch(); }
-                }
-                first = false;
-
-                let contexts = context::contexts();
-                let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                let mut context = context.write();
-
-                break match kind {
-                    RegsKind::Float => {
-                        // TODO!!
-                        unimplemented!();
-                    },
-                    RegsKind::Int => match unsafe { ptrace::regs_for_mut(&mut context) } {
-                        None => {
-                            // Another CPU is running this process, wait until it's stopped.
-                            continue;
-                        },
-                        Some(stack) => {
-                            if buf.len() < mem::size_of::<IntRegisters>() {
-                                return Ok(0);
-                            }
-                            let regs = unsafe {
-                                *(buf as *const _ as *const IntRegisters)
-                            };
-
-                            stack.load(&regs);
-
-                            Ok(mem::size_of::<IntRegisters>())
-                        }
-                    }
-                };
-            },
-            Operation::Trace => {
-                if buf.len() < 1 {
-                    return Ok(0);
-                }
-                let op = buf[0];
-                let sysemu = op & PTRACE_SYSEMU == PTRACE_SYSEMU;
-
-                let mut blocking = handle.flags & O_NONBLOCK != O_NONBLOCK;
-                let mut wait_breakpoint = false;
-                let mut singlestep = false;
-
-                match op & PTRACE_OPERATIONMASK {
-                    PTRACE_CONT => { ptrace::cont(handle.pid); },
-                    PTRACE_SYSCALL | PTRACE_SINGLESTEP => { // <- not a bitwise OR
-                        singlestep = op & PTRACE_OPERATIONMASK == PTRACE_SINGLESTEP;
-                        ptrace::set_breakpoint(handle.pid, sysemu, singlestep);
-                        wait_breakpoint = true;
-                    },
-                    PTRACE_WAIT => {
-                        wait_breakpoint = true;
-                        blocking = true;
-                    },
-                    _ => return Err(Error::new(EINVAL))
-                }
-
-                let mut first = true;
-                loop {
-                    if !first {
-                        // We've tried this before, so lets wait before retrying
-                        unsafe { context::switch(); }
-                    }
-                    first = false;
-
-                    let contexts = context::contexts();
-                    let context = contexts.get(handle.pid).ok_or(Error::new(ESRCH))?;
-                    let mut context = context.write();
-                    if let Status::Exited(_) = context.status {
-                        return Err(Error::new(ESRCH));
-                    }
-
-                    if singlestep {
-                        match unsafe { ptrace::regs_for_mut(&mut context) } {
-                            None => continue,
-                            Some(stack) => stack.set_singlestep(true)
-                        }
-                    }
-
-                    context.ptrace_stop = false;
-                    break;
-                }
-
-                if wait_breakpoint && blocking {
-                    ptrace::wait_breakpoint(handle.pid)?;
-                }
-
-                Ok(1)
-            }
-        }
-    }
-
-    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
-        let mut handles = self.handles.write();
-        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
-
-        match cmd {
-            F_SETFL => { handle.flags = arg; Ok(0) },
-            F_GETFL => return Ok(handle.flags),
-            _ => return Err(Error::new(EINVAL))
-        }
-    }
-
-    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
-        let handles = self.handles.read();
-        let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
-
-        let path = format!("proc:{}/{}", handle.pid.into(), match handle.operation {
-            Operation::Memory => "mem",
-            Operation::Regs(RegsKind::Float) => "regs/float",
-            Operation::Regs(RegsKind::Int) => "regs/int",
-            Operation::Trace => "trace"
-        });
-
-        let len = cmp::min(path.len(), buf.len());
-        buf[..len].copy_from_slice(&path.as_bytes()[..len]);
-
-        Ok(len)
-    }
-
-    fn close(&self, id: usize) -> Result<usize> {
-        let handle = self.handles.write().remove(&id).ok_or(Error::new(EBADF))?;
-        ptrace::cont(handle.pid);
-
-        let contexts = context::contexts();
-        if let Some(context) = contexts.get(handle.pid) {
-            let mut context = context.write();
-            context.ptrace_stop = false;
-        }
-        Ok(0)
-    }
-}
diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs
index 853380f1dd236ff667201fc1cb56a557460fbfc0..149929869fbae8c3dde5a4a09fec1761bce9f5ce 100644
--- a/src/syscall/debug.rs
+++ b/src/syscall/debug.rs
@@ -1,4 +1,5 @@
-use core::{ascii, mem};
+use core::mem;
+use core::ops::Range;
 use alloc::string::String;
 use alloc::vec::Vec;
 
@@ -7,13 +8,47 @@ use super::flag::*;
 use super::number::*;
 use super::validate::*;
 
+// Copied from std
+pub struct EscapeDefault {
+    range: Range<usize>,
+    data: [u8; 4],
+}
+
+pub fn escape_default(c: u8) -> EscapeDefault {
+    let (data, len) = match c {
+        b'\t' => ([b'\\', b't', 0, 0], 2),
+        b'\r' => ([b'\\', b'r', 0, 0], 2),
+        b'\n' => ([b'\\', b'n', 0, 0], 2),
+        b'\\' => ([b'\\', b'\\', 0, 0], 2),
+        b'\'' => ([b'\\', b'\'', 0, 0], 2),
+        b'"' => ([b'\\', b'"', 0, 0], 2),
+        b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1),
+        _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
+    };
+
+    return EscapeDefault { range: (0.. len), data: data };
+
+    fn hexify(b: u8) -> u8 {
+        match b {
+            0 ... 9 => b'0' + b,
+            _ => b'a' + b - 10,
+        }
+    }
+}
+
+impl Iterator for EscapeDefault {
+    type Item = u8;
+    fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+}
+
 struct ByteStr<'a>(&'a[u8]);
 
 impl<'a> ::core::fmt::Debug for ByteStr<'a> {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         write!(f, "\"")?;
         for i in self.0 {
-            for ch in ascii::escape_default(*i) {
+            for ch in escape_default(*i) {
                 write!(f, "{}", ch as char)?;
             }
         }
diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs
index 360d3a4d3da9a996239eddadb3b36879eb078627..5672706f02b60fc78163b9c586f8c8d90e577a89 100644
--- a/src/syscall/driver.rs
+++ b/src/syscall/driver.rs
@@ -25,8 +25,7 @@ pub fn iopl(level: usize, stack: &mut SyscallStack) -> Result<usize> {
         return Err(Error::new(EINVAL));
     }
 
-    let iret = &mut stack.interrupt_stack.iret;
-    iret.rflags = (iret.rflags & !(3 << 12)) | ((level & 3) << 12);
+    stack.rflags = (stack.rflags & !(3 << 12)) | ((level & 3) << 12);
 
     Ok(0)
 }
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index 7d07c4191ad00baf1750211421a76451c0ab7fc7..d1a7298c66bef0768f3dddb31b063a2469bba652 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -6,21 +6,21 @@ use core::{intrinsics, mem};
 use core::ops::DerefMut;
 use spin::Mutex;
 
-use crate::context::file::FileDescriptor;
-use crate::context::{ContextId, WaitpidKey};
-use crate::context;
-#[cfg(not(feature="doc"))]
-use crate::elf::{self, program_header};
-use crate::interrupt;
-use crate::ipi::{ipi, IpiKind, IpiTarget};
 use crate::memory::allocate_frames;
+use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE};
 use crate::paging::entry::EntryFlags;
 use crate::paging::mapper::MapperFlushAll;
 use crate::paging::temporary_page::TemporaryPage;
-use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE};
-use crate::ptrace;
-use crate::scheme::FileHandle;
 use crate::start::usermode;
+use crate::interrupt;
+use crate::context;
+use crate::context::{ContextId, WaitpidKey};
+use crate::context::file::FileDescriptor;
+#[cfg(not(feature="doc"))]
+use crate::elf::{self, program_header};
+use crate::ipi::{ipi, IpiKind, IpiTarget};
+use crate::scheme::FileHandle;
+use crate::syscall;
 use crate::syscall::data::{SigAction, Stat};
 use crate::syscall::error::*;
 use crate::syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_STACK,
@@ -28,7 +28,6 @@ use crate::syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_S
                     SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM,
                     WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped};
 use crate::syscall::validate::{validate_slice, validate_slice_mut};
-use crate::syscall;
 
 pub fn brk(address: usize) -> Result<usize> {
     let contexts = context::contexts();
@@ -129,25 +128,10 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
             }
 
             if let Some(ref stack) = context.kstack {
-                // Get the relative offset to the return address of this function
-                // (base pointer - start of stack) - one
                 offset = stack_base - stack.as_ptr() as usize - mem::size_of::<usize>(); // Add clone ret
                 let mut new_stack = stack.clone();
 
                 unsafe {
-                    if let Some(regs) = ptrace::rebase_regs_ptr_mut(context.regs, Some(&mut new_stack)) {
-                        // We'll need to tell the clone that it should
-                        // return 0, but that's it. We don't actually
-                        // clone the registers, because it will then
-                        // become None and be exempt from all kinds of
-                        // ptracing until the current syscall has
-                        // completed.
-                        (*regs).scratch.rax = 0;
-                    }
-
-                    // Change the return address of the child
-                    // (previously syscall) to the arch-specific
-                    // clone_ret callback
                     let func_ptr = new_stack.as_mut_ptr().offset(offset as isize);
                     *(func_ptr as *mut usize) = interrupt::syscall::clone_ret as usize;
                 }
@@ -1068,8 +1052,6 @@ pub fn exit(status: usize) -> ! {
             context.id
         };
 
-        ptrace::close(pid);
-
         // Files must be closed while context is valid so that messages can be passed
         for (_fd, file_option) in close_files.drain(..).enumerate() {
             if let Some(file) = file_option {
diff --git a/syscall b/syscall
index f8eda5ce1bd6fe7f276302493ec54a75a7335fd0..5cdc240d1338b53a1d8b9f652b0cc628317f3109 160000
--- a/syscall
+++ b/syscall
@@ -1 +1 @@
-Subproject commit f8eda5ce1bd6fe7f276302493ec54a75a7335fd0
+Subproject commit 5cdc240d1338b53a1d8b9f652b0cc628317f3109