diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs
index 22fe5a3cf649ade69d1cb04180acdb1d5738cd5d..6271229b9ff277aa0c4ff1c84f480024e43a4e49 100644
--- a/src/arch/x86_64/macros.rs
+++ b/src/arch/x86_64/macros.rs
@@ -1,6 +1,5 @@
 use core::mem;
 use syscall::data::IntRegisters;
-use super::gdt;
 
 /// Print to console
 #[macro_export]
@@ -216,24 +215,6 @@ pub struct InterruptStack {
 }
 
 impl InterruptStack {
-    pub fn new_usermode(ip: usize, sp: usize, arg: usize) -> Self {
-        // See which registers are set in start.rs, function `usermode`
-        Self {
-            fs: gdt::GDT_USER_TLS << 3 | 3,
-            preserved: PreservedRegisters::default(),
-            scratch: ScratchRegisters {
-                rdi: arg,
-                ..ScratchRegisters::default()
-            },
-            iret: IretRegisters {
-                rip: ip,
-                cs: gdt::GDT_USER_CODE << 3 | 3,
-                rflags: 1 << 9,
-                rsp: sp,
-                ss: gdt::GDT_USER_DATA << 3 | 3,
-            },
-        }
-    }
     pub fn dump(&self) {
         self.iret.dump();
         self.scratch.dump();
@@ -323,6 +304,10 @@ impl InterruptStack {
             self.iret.rflags &= !(1 << 8);
         }
     }
+    /// Checks if the trap flag is enabled, see `set_singlestep`
+    pub fn is_singlestep(&self) -> bool {
+        self.iret.rflags & 1 << 8 == 1 << 8
+    }
 }
 
 macro_rules! interrupt_push {
diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs
index b2bc4e5fc1efc093626ed521fe285b5239b7117a..30425f0e2033b2adce9fe9b7ceefa3cc6c94841f 100644
--- a/src/arch/x86_64/start.rs
+++ b/src/arch/x86_64/start.rs
@@ -3,7 +3,7 @@
 /// It must create the IDT with the correct entries, those entries are
 /// defined in other files inside of the `arch` module
 
-use core::{slice, mem, ptr};
+use core::slice;
 use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 
 use crate::allocator;
@@ -17,7 +17,6 @@ use crate::gdt;
 use crate::idt;
 use crate::interrupt;
 use crate::log;
-use crate::macros::InterruptStack;
 use crate::memory;
 use crate::paging;
 
@@ -234,7 +233,12 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
 }
 
 #[naked]
-pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
+pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, singlestep: bool) -> ! {
+    let mut flags = 1 << 9;
+    if singlestep {
+        flags |= 1 << 8;
+    }
+
     asm!("push r10
           push r11
           push r12
@@ -244,7 +248,7 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
           : // No output
           :   "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
               "{r11}"(sp), // Stack pointer
-              "{r12}"(1 << 9), // Flags - Set interrupt enable flag
+              "{r12}"(flags), // Flags - Set interrupt enable flag
               "{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
               "{r14}"(ip), // IP
               "{r15}"(arg) // Argument
@@ -284,31 +288,3 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
          : "intel", "volatile");
     unreachable!();
 }
-
-#[naked]
-pub unsafe fn usermode_interrupt_stack(stack: InterruptStack) -> ! {
-    // Push fake stack to the actual stack
-    let rsp: usize;
-    asm!("sub rsp, $1" : "={rsp}"(rsp) : "r"(mem::size_of::<InterruptStack>()) : : "intel", "volatile");
-    ptr::write(rsp as *mut InterruptStack, stack);
-
-    // Unmap kernel
-    pti::unmap();
-
-    // Set up floating point and TLS
-    asm!("mov ds, r14d
-         mov es, r14d
-         mov fs, r15d
-         mov gs, r14d
-         fninit"
-         : // No output because it never returns
-         :   "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
-             "{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment
-         : "ds", "es", "fs", "gs"
-         : "intel", "volatile");
-
-    // Go to usermode
-    interrupt_pop!();
-    iret!();
-    unreachable!();
-}
diff --git a/src/context/signal.rs b/src/context/signal.rs
index 78e165af4f352453d7fcc7da46a5a5d223f00fe2..05d3ff749467360a3bc44136ad9591d318839502 100644
--- a/src/context/signal.rs
+++ b/src/context/signal.rs
@@ -105,6 +105,15 @@ pub extern "C" fn signal_handler(sig: usize) {
     } else {
         // println!("Call {:X}", handler);
 
+        let singlestep = {
+            let contexts = contexts();
+            let context = contexts.current().expect("context::signal_handler userspace not inside of context");
+            let context = context.read();
+            unsafe {
+                ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false)
+            }
+        };
+
         unsafe {
             let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256;
 
@@ -113,7 +122,7 @@ pub extern "C" fn signal_handler(sig: usize) {
             sp -= mem::size_of::<usize>();
             *(sp as *mut usize) = restorer;
 
-            usermode(handler, sp, sig);
+            usermode(handler, sp, sig, singlestep);
         }
     }
 
diff --git a/src/context/switch.rs b/src/context/switch.rs
index 6e10825fcab4326d10a02bbf88d758b35740b773..851655757f6df75bd36cc870d719e107f1768bcc 100644
--- a/src/context/switch.rs
+++ b/src/context/switch.rs
@@ -1,10 +1,11 @@
 use core::sync::atomic::Ordering;
 
-use crate::context::{arch, contexts, Context, Status, CONTEXT_ID};
 use crate::context::signal::signal_handler;
+use crate::context::{arch, contexts, Context, Status, CONTEXT_ID};
 use crate::gdt;
-use crate::interrupt;
 use crate::interrupt::irq::PIT_TICKS;
+use crate::interrupt;
+use crate::ptrace;
 use crate::time;
 
 unsafe fn update(context: &mut Context, cpu_id: usize) {
@@ -16,6 +17,8 @@ unsafe fn update(context: &mut Context, cpu_id: usize) {
 
     // Restore from signal, must only be done from another context to avoid overwriting the stack!
     if context.ksig_restore && ! context.running {
+        let was_singlestep = ptrace::regs_for(context).map(|s| s.is_singlestep()).unwrap_or(false);
+
         let ksig = context.ksig.take().expect("context::switch: ksig not set with ksig_restore");
         context.arch = ksig.0;
 
@@ -33,6 +36,11 @@ unsafe fn update(context: &mut Context, cpu_id: usize) {
 
         context.ksig_restore = false;
 
+        // Keep singlestep flag across jumps
+        if let Some(regs) = ptrace::regs_for_mut(context) {
+            regs.set_singlestep(was_singlestep);
+        }
+
         context.unblock();
     }
 
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index e27576fd3e248ec542b0b40df67034f97ec23686..2da33bd2a5e698a17cb76185e948a889d7ddc8a7 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -6,7 +6,6 @@ use core::{intrinsics, mem};
 use core::ops::DerefMut;
 use spin::Mutex;
 
-use crate::arch::macros::InterruptStack;
 use crate::context::file::FileDescriptor;
 use crate::context::{ContextId, WaitpidKey};
 use crate::context;
@@ -21,14 +20,14 @@ use crate::paging::temporary_page::TemporaryPage;
 use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE};
 use crate::{ptrace, syscall};
 use crate::scheme::FileHandle;
-use crate::start::{usermode, usermode_interrupt_stack};
+use crate::start::usermode;
 use crate::syscall::data::{SigAction, Stat};
 use crate::syscall::error::*;
-use crate::syscall::flag::{CloneFlags, CLONE_FILES, CLONE_FS, CLONE_SIGHAND,
-                           CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, PtraceFlags, PROT_EXEC,
-                           PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, SigActionFlags,
-                           SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, WaitFlags,
-                           WCONTINUED, WNOHANG,WUNTRACED, wifcontinued, wifstopped};
+use crate::syscall::flag::{wifcontinued, wifstopped, CloneFlags, CLONE_FILES,
+                           CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags,
+                           PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT,
+                           SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM,
+                           WaitFlags, WCONTINUED, WNOHANG,WUNTRACED};
 use crate::syscall::ptrace_event;
 use crate::syscall::validate::{validate_slice, validate_slice_mut};
 
@@ -661,6 +660,7 @@ fn fexec_noreturn(
     vars: Box<[Box<[u8]>]>
 ) -> ! {
     let entry;
+    let singlestep;
     let mut sp = crate::USER_STACK_OFFSET + crate::USER_STACK_SIZE - 256;
 
     {
@@ -669,6 +669,10 @@ fn fexec_noreturn(
             let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exec_noreturn pid not found");
             let mut context = context_lock.write();
 
+            singlestep = unsafe {
+                ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false)
+            };
+
             context.name = Arc::new(Mutex::new(name));
 
             empty(&mut context, false);
@@ -712,8 +716,8 @@ fn fexec_noreturn(
                             unsafe {
                                 // Copy file data
                                 intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8,
-                                                segment.p_vaddr as *mut u8,
-                                                segment.p_filesz as usize);
+                                                 segment.p_vaddr as *mut u8,
+                                                 segment.p_filesz as usize);
                             }
 
                             let mut flags = EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE;
@@ -900,22 +904,8 @@ fn fexec_noreturn(
         }
     }
 
-    // Create dummy stack for ptrace to read from
-    let mut regs = InterruptStack::new_usermode(entry, sp, 0);
-
-    // ptrace breakpoint
-    let was_traced = {
-        let _guard = ptrace::set_process_regs(&mut regs);
-        ptrace::breakpoint_callback(PtraceFlags::PTRACE_STOP_EXEC, None).is_some()
-    };
-
-    if !was_traced {
-        // Go to usermode, fast route
-        unsafe { usermode(entry, sp, 0) }
-    } else {
-        // Go to usermode, take ptrace-modified stack into account
-        unsafe { usermode_interrupt_stack(regs) }
-    }
+    // Go to usermode
+    unsafe { usermode(entry, sp, 0, singlestep) }
 }
 
 pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option<Box<[u8]>>) -> Result<usize> {
diff --git a/syscall b/syscall
index fcebe8f225142830fa5880a27d9faa6ed6b2aeb8..122878874d3f4fee0fd1f19b8dc2b07d84d5df8b 160000
--- a/syscall
+++ b/syscall
@@ -1 +1 @@
-Subproject commit fcebe8f225142830fa5880a27d9faa6ed6b2aeb8
+Subproject commit 122878874d3f4fee0fd1f19b8dc2b07d84d5df8b