diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs
index b55a13e5d4aabaa233fee488be18c73f6a4e4551..5c0e8eaf4f19545e7441c2a15b09e327be50db04 100644
--- a/src/arch/x86_64/interrupt/exception.rs
+++ b/src/arch/x86_64/interrupt/exception.rs
@@ -18,8 +18,6 @@ interrupt_stack!(divide_by_zero, stack, {
 interrupt_stack!(debug, stack, {
     let mut handled = false;
 
-    let guard = ptrace::set_process_regs(stack);
-
     // Disable singlestep before there is a breakpoint, since the breakpoint
     // handler might end up setting it again but unless it does we want the
     // default to be false.
@@ -33,8 +31,6 @@ interrupt_stack!(debug, stack, {
         stack.set_singlestep(had_singlestep);
     }
 
-    drop(guard);
-
     if !handled {
         println!("Debug trap");
         stack.dump();
@@ -61,11 +57,7 @@ interrupt_stack!(breakpoint, stack, {
     // int3 instruction. After all, it's the sanest thing to do.
     stack.iret.rip -= 1;
 
-    let guard = ptrace::set_process_regs(stack);
-
     if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {
-        drop(guard);
-
         println!("Breakpoint trap");
         stack.dump();
         ksignal(SIGTRAP);
diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs
index a01196f80ffb8e5ac219c04958a48724bd16b0be..291879cdd8df672214c390f248b60bc78521a18d 100644
--- a/src/arch/x86_64/interrupt/irq.rs
+++ b/src/arch/x86_64/interrupt/irq.rs
@@ -189,7 +189,6 @@ interrupt_stack!(pit, stack, {
     timeout::trigger();
 
     if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
-        let _guard = ptrace::set_process_regs(stack);
         let _ = context::switch();
     }
 });
diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs
index 6271229b9ff277aa0c4ff1c84f480024e43a4e49..f3d54d9b3b66e4cf4af216d6b32b61a20464333d 100644
--- a/src/arch/x86_64/macros.rs
+++ b/src/arch/x86_64/macros.rs
@@ -48,9 +48,8 @@ impl ScratchRegisters {
 }
 
 macro_rules! scratch_push {
-    () => (asm!(
-        "push rax
-        push rcx
+    (without rax) => (asm!(
+        "push rcx
         push rdx
         push rdi
         push rsi
@@ -60,6 +59,10 @@ macro_rules! scratch_push {
         push r11"
         : : : : "intel", "volatile"
     ));
+    () => ({
+        asm!("push rax" : : : : "intel", "volatile");
+        scratch_push!(without rax);
+    });
 }
 
 macro_rules! scratch_pop {
@@ -332,6 +335,7 @@ macro_rules! interrupt_stack {
         pub unsafe extern fn $name () {
             #[inline(never)]
             unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptStack) {
+                let _guard = ptrace::set_process_regs($stack);
                 $func
             }
 
@@ -362,20 +366,14 @@ macro_rules! interrupt_stack {
 #[derive(Default)]
 #[repr(packed)]
 pub struct InterruptErrorStack {
-    pub fs: usize,
-    pub preserved: PreservedRegisters,
-    pub scratch: ScratchRegisters,
     pub code: usize,
-    pub iret: IretRegisters,
+    pub inner: InterruptStack,
 }
 
 impl InterruptErrorStack {
     pub fn dump(&self) {
-        self.iret.dump();
+        self.inner.dump();
         println!("CODE:  {:>016X}", { self.code });
-        self.scratch.dump();
-        self.preserved.dump();
-        println!("FS:    {:>016X}", { self.fs });
     }
 }
 
@@ -385,12 +383,23 @@ macro_rules! interrupt_error {
         #[naked]
         pub unsafe extern fn $name () {
             #[inline(never)]
-            unsafe fn inner($stack: &$crate::arch::x86_64::macros::InterruptErrorStack) {
+            unsafe fn inner($stack: &mut $crate::arch::x86_64::macros::InterruptErrorStack) {
+                let _guard = ptrace::set_process_regs(&mut $stack.inner);
                 $func
             }
 
-            // Push scratch registers
-            interrupt_push!();
+            // Swap RAX and error code, in order to push the code later and be
+            // compatible with InterruptStack.
+            asm!("xchg [rsp], rax" : : : : "intel", "volatile");
+
+            // Push all the registers (except for rax which is already pushed,
+            // in place of the error code)
+            scratch_push!(without rax);
+            preserved_push!();
+            fs_push!();
+
+            // Finally, push rax (now containing error code)
+            asm!("push rax" : : : : "intel", "volatile");
 
             // Get reference to stack variables
             let rsp: usize;
@@ -400,14 +409,14 @@ macro_rules! interrupt_error {
             $crate::arch::x86_64::pti::map();
 
             // Call inner rust function
-            inner(&*(rsp as *const $crate::arch::x86_64::macros::InterruptErrorStack));
+            inner(&mut *(rsp as *mut $crate::arch::x86_64::macros::InterruptErrorStack));
 
             // Unmap kernel
             $crate::arch::x86_64::pti::unmap();
 
-            // Pop scratch registers, error code, and return
-            interrupt_pop!();
+            // Pop error code, registers, and return
             asm!("add rsp, 8" : : : : "intel", "volatile"); // pop error code
+            interrupt_pop!();
             iret!();
         }
     };
diff --git a/src/lib.rs b/src/lib.rs
index 862794080a53943bf3f5e1646f05cdb65c11be2f..82004e768116274e42ebcc89f3d3ead35861d7ca 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -274,5 +274,11 @@ pub extern fn ksignal(signal: usize) {
             println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
         }
     }
-    syscall::exit(signal & 0x7F);
+
+    // Try running kill(getpid(), signal), but fallback to exiting
+    syscall::getpid()
+        .and_then(|pid| syscall::kill(pid, signal).map(|_| ()))
+        .unwrap_or_else(|_| {
+            syscall::exit(signal & 0x7F);
+        });
 }