Parcourir la source

Kernel: Add support for SA_SIGINFO

We currently don't really populate most of the fields, but that can
wait :^)
Ali Mohammad Pur il y a 3 ans
Parent
commit
4bd01b7fe9

+ 60 - 0
Kernel/API/POSIX/ucontext.h

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/API/POSIX/sys/types.h>
+#include <Kernel/Arch/mcontext.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __mcontext mcontext_t;
+
+typedef struct __ucontext {
+    struct __ucontext* uc_link;
+    sigset_t uc_sigmask;
+    stack_t uc_stack;
+    mcontext_t uc_mcontext;
+} ucontext_t;
+
+#define ILL_ILLOPC 0
+#define ILL_ILLOPN 1
+#define ILL_ILLADR 2
+#define ILL_ILLTRP 3
+#define ILL_PRVOPC 4
+#define ILL_PRVREG 5
+#define ILL_COPROC 6
+#define ILL_BADSTK 7
+
+#define FPE_INTDIV 0
+#define FPE_INTOVF 1
+#define FPE_FLTDIV 2
+#define FPE_FLTOVF 3
+#define FPE_FLTUND 4
+#define FPE_FLTRES 5
+#define FPE_FLTINV 6
+
+#define SEGV_MAPERR 0
+#define SEGV_ACCERR 1
+
+#define BUS_ADRALN 0
+#define BUS_ADRERR 1
+#define BUS_OBJERR 2
+
+#define TRAP_BRKPT 0
+#define TRAP_TRACE 1
+
+#define SI_USER 0x40000000
+#define SI_QUEUE 0x40000001
+#define SI_TIMER 0x40000002
+#define SI_ASYNCIO 0x40000003
+#define SI_MESGQ 0x40000004
+
+#ifdef __cplusplus
+}
+#endif

+ 15 - 0
Kernel/Arch/mcontext.h

@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, the SerenityOS developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Platform.h>
+
+#if ARCH(X86_64) || ARCH(I386)
+#    include <Kernel/Arch/x86/mcontext.h>
+#elif ARCH(AARCH64)
+#    error "Unknown architecture"
+#endif

+ 58 - 0
Kernel/Arch/x86/mcontext.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, the SerenityOS developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Platform.h>
+#include <Kernel/API/POSIX/sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct __attribute__((packed)) __mcontext {
+#if ARCH(I386)
+    uint32_t eax;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t ebx;
+    uint32_t esp;
+    uint32_t ebp;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t eip;
+    uint32_t eflags;
+#else
+    uint64_t rax;
+    uint64_t rcx;
+    uint64_t rdx;
+    uint64_t rbx;
+    uint64_t rsp;
+    uint64_t rbp;
+    uint64_t rsi;
+    uint64_t rdi;
+    uint64_t rip;
+    uint64_t r8;
+    uint64_t r9;
+    uint64_t r10;
+    uint64_t r11;
+    uint64_t r12;
+    uint64_t r13;
+    uint64_t r14;
+    uint64_t r15;
+    uint64_t rflags;
+#endif
+    uint32_t cs;
+    uint32_t ss;
+    uint32_t ds;
+    uint32_t es;
+    uint32_t fs;
+    uint32_t gs;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 33 - 27
Kernel/Process.cpp

@@ -293,63 +293,69 @@ void signal_trampoline_dummy()
     // blocking syscall, that syscall may return some special error code in eax;
     // This error code would likely be overwritten by the signal handler, so it's
     // necessary to preserve it here.
+    constexpr static auto offset_to_first_register_slot = sizeof(__ucontext) + sizeof(siginfo) + 5 * sizeof(FlatPtr);
     asm(
         ".intel_syntax noprefix\n"
         ".globl asm_signal_trampoline\n"
         "asm_signal_trampoline:\n"
-        // stack state: ret flags, ret ip, register dump, signal mask, signal, handler (alignment = 16), 0
+        // stack state: 0, ucontext, signal_info, (alignment = 16), 0, ucontext*, siginfo*, signal, (alignment = 16), handler
 
-        // save ebp
-        "push ebp\n"
-        "mov ebp, esp\n"
+        // Pop the handler into ecx
+        "pop ecx\n" // save handler
         // we have to save eax 'cause it might be the return value from a syscall
-        "push eax\n"
-        // align the stack to 16 bytes (as our current offset is 12 from the fake return addr, saved ebp and saved eax)
-        "sub esp, 4\n"
-        // push the signal code
-        "mov eax, [ebp+12]\n"
-        "push eax\n"
+        "mov [esp+%P1], eax\n"
+        // Note that the stack is currently aligned to 16 bytes as we popped the extra entries above.
+        // and it's already setup to call the handler with the expected values on the stack.
         // call the signal handler
-        "call [ebp+8]\n"
-        // Unroll stack back to the saved eax
-        "add esp, 8\n"
+        "call ecx\n"
+        // drop the 4 arguments
+        "add esp, 16\n"
+        // Current stack state is just saved_eax, ucontext, signal_info.
         // syscall SC_sigreturn
         "mov eax, %P0\n"
         "int 0x82\n"
         ".globl asm_signal_trampoline_end\n"
         "asm_signal_trampoline_end:\n"
-        ".att_syntax" ::"i"(Syscall::SC_sigreturn));
+        ".att_syntax"
+        :
+        : "i"(Syscall::SC_sigreturn),
+        "i"(offset_to_first_register_slot));
 #elif ARCH(X86_64)
     // The trampoline preserves the current rax, pushes the signal code and
     // then calls the signal handler. We do this because, when interrupting a
     // blocking syscall, that syscall may return some special error code in eax;
     // This error code would likely be overwritten by the signal handler, so it's
     // necessary to preserve it here.
+    constexpr static auto offset_to_first_register_slot = sizeof(__ucontext) + sizeof(siginfo) + 4 * sizeof(FlatPtr);
     asm(
         ".intel_syntax noprefix\n"
         ".globl asm_signal_trampoline\n"
         "asm_signal_trampoline:\n"
-        // stack state: ret flags, ret ip, register dump, signal mask, signal, handler (alignment = 16), 0
+        // stack state: 0, ucontext, signal_info (alignment = 16), ucontext*, siginfo*, signal, handler
 
-        // save rbp
-        "push rbp\n"
-        "mov rbp, rsp\n"
+        // Pop the handler into rcx
+        "pop rcx\n" // save handler
         // we have to save rax 'cause it might be the return value from a syscall
-        "push rax\n"
-        // align the stack to 16 bytes (our offset is 24 bytes from the fake return addr, saved rbp and saved rax).
-        "sub rsp, 8\n"
-        // push the signal code
-        "mov rdi, [rbp+24]\n"
+        "mov [rsp+%P1], rax\n"
+        // pop signal number into rdi (first param)
+        "pop rdi\n"
+        // pop siginfo* into rsi (second param)
+        "pop rsi\n"
+        // pop ucontext* into rdx (third param)
+        "pop rdx\n"
+        // Note that the stack is currently aligned to 16 bytes as we popped the extra entries above.
         // call the signal handler
-        "call [rbp+16]\n"
-        // unroll stack back to the saved rax
-        "add rsp, 8\n"
+        "call rcx\n"
+        // Current stack state is just saved_rax, ucontext, signal_info.
         // syscall SC_sigreturn
         "mov rax, %P0\n"
         "int 0x82\n"
         ".globl asm_signal_trampoline_end\n"
         "asm_signal_trampoline_end:\n"
-        ".att_syntax" ::"i"(Syscall::SC_sigreturn));
+        ".att_syntax"
+        :
+        : "i"(Syscall::SC_sigreturn),
+        "i"(offset_to_first_register_slot));
 #endif
 }
 

+ 21 - 50
Kernel/Syscalls/sigaction.cpp

@@ -68,8 +68,6 @@ ErrorOr<FlatPtr> Process::sys$sigaction(int signum, Userspace<const sigaction*>
     }
     if (user_act) {
         auto act = TRY(copy_typed_from_user(user_act));
-        if (act.sa_flags & SA_SIGINFO)
-            return ENOTSUP;
         action.mask = act.sa_mask;
         action.flags = act.sa_flags;
         action.handler_or_sigaction = VirtualAddress { reinterpret_cast<void*>(act.sa_sigaction) };
@@ -83,63 +81,36 @@ ErrorOr<FlatPtr> Process::sys$sigreturn([[maybe_unused]] RegisterState& register
     TRY(require_promise(Pledge::stdio));
     SmapDisabler disabler;
 
-#if ARCH(I386)
-    // Stack state (created by the signal trampoline):
-    //    ret flags, ret ip, register dump,
-    //    signal mask, signal, handler (alignment = 16),
-    //    0, ebp, eax
-
     // Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
-    FlatPtr* stack_ptr = bit_cast<FlatPtr*>(registers.userspace_esp);
-    FlatPtr smuggled_eax = *stack_ptr;
-
-    // pop the stored eax, ebp, return address, handler and signal code
-    stack_ptr += 5;
-
-    Thread::current()->m_signal_mask = *stack_ptr;
-    stack_ptr++;
-
-    // pop edi, esi, ebp, esp, ebx, edx, ecx and eax
-    memcpy(&registers.edi, stack_ptr, 8 * sizeof(FlatPtr));
-    stack_ptr += 8;
-
-    registers.eip = *stack_ptr;
-    stack_ptr++;
+    auto stack_ptr = registers.userspace_sp();
 
-    registers.eflags = (registers.eflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
-    stack_ptr++;
-
-    registers.userspace_esp = registers.esp;
-    return smuggled_eax;
-#else
     // Stack state (created by the signal trampoline):
-    //    ret flags, ret ip, register dump,
-    //    signal mask, signal, handler (alignment = 16),
-    //    0, ebp, eax
-
-    // Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
-    FlatPtr* stack_ptr = (FlatPtr*)registers.userspace_rsp;
-    FlatPtr smuggled_rax = *stack_ptr;
+    // saved_ax, ucontext, signal_info.
+    stack_ptr += sizeof(siginfo); // We don't need this here.
 
-    // pop the stored rax, rbp, return address, handler and signal code
-    stack_ptr += 5;
+    auto ucontext = TRY(copy_typed_from_user<__ucontext>(stack_ptr));
+    stack_ptr += sizeof(__ucontext);
 
-    Thread::current()->m_signal_mask = *stack_ptr;
-    stack_ptr++;
+    auto saved_ax = TRY(copy_typed_from_user<FlatPtr>(stack_ptr));
 
-    // pop rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, r8, r9, r10, r11, r12, r13, r14 and r15
-    memcpy(&registers.rdi, stack_ptr, 16 * sizeof(FlatPtr));
-    stack_ptr += 16;
-
-    registers.rip = *stack_ptr;
-    stack_ptr++;
+    Thread::current()->m_signal_mask = ucontext.uc_sigmask;
+#if ARCH(X86_64)
+    auto sp = registers.rsp;
+#elif ARCH(I386)
+    auto sp = registers.esp;
+#endif
 
-    registers.rflags = (registers.rflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
-    stack_ptr++;
+    copy_ptrace_registers_into_kernel_registers(registers, static_cast<PtraceRegisters const&>(ucontext.uc_mcontext));
 
-    registers.userspace_rsp = registers.rsp;
-    return smuggled_rax;
+#if ARCH(X86_64)
+    registers.set_userspace_sp(registers.rsp);
+    registers.rsp = sp;
+#elif ARCH(I386)
+    registers.set_userspace_sp(registers.esp);
+    registers.esp = sp;
 #endif
+
+    return saved_ax;
 }
 
 ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)

+ 73 - 62
Kernel/Thread.cpp

@@ -938,6 +938,13 @@ static ErrorOr<void> push_value_on_user_stack(FlatPtr& stack, FlatPtr data)
     return copy_to_user((FlatPtr*)stack, &data);
 }
 
+template<typename T>
+static ErrorOr<void> copy_value_on_user_stack(FlatPtr& stack, T const& data)
+{
+    stack -= sizeof(data);
+    return copy_to_user((RemoveCVReference<T>*)stack, &data);
+}
+
 void Thread::resume_from_stopped()
 {
     VERIFY(is_stopped());
@@ -976,8 +983,6 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
     }
 
     auto& action = m_process->m_signal_action_data[signal];
-    // FIXME: Implement SA_SIGINFO signal handlers.
-    VERIFY(!(action.flags & SA_SIGINFO));
 
     if (!current_trap() && !action.handler_or_sigaction.is_null()) {
         // We're trying dispatch a handled signal to a user process that was scheduled
@@ -1057,83 +1062,89 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
     bool use_alternative_stack = ((action.flags & SA_ONSTACK) != 0) && has_alternative_signal_stack() && !is_in_alternative_signal_stack();
 
     auto setup_stack = [&](RegisterState& state) -> ErrorOr<void> {
-        FlatPtr old_sp = state.userspace_sp();
         FlatPtr stack;
         if (use_alternative_stack)
             stack = m_alternative_signal_stack + m_alternative_signal_stack_size;
         else
-            stack = old_sp;
+            stack = state.userspace_sp();
+
+        dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to IP {:p}, SP {:p}", state.ip(), state.userspace_sp());
+
+        __ucontext ucontext {
+            .uc_link = nullptr,
+            .uc_sigmask = old_signal_mask,
+            .uc_stack = {
+                .ss_sp = nullptr,
+                .ss_flags = 0,
+                .ss_size = 0,
+            },
+            .uc_mcontext = {},
+        };
+        copy_kernel_registers_into_ptrace_registers(static_cast<PtraceRegisters&>(ucontext.uc_mcontext), state);
+
+        siginfo signal_info {
+            .si_signo = signal,
+            .si_code = 0, // FIXME: Signal-specific value, fill this in.
+            .si_errno = 0,
+            // FIXME: Plumb sender information here.
+            .si_pid = 0,
+            .si_uid = 0,
+            // FIXME: Fill these in.
+            .si_addr = 0,
+            .si_status = 0,
+            .si_band = 0,
+            .si_value = {
+                .sival_int = 0,
+            },
+        };
 
-        FlatPtr ret_ip = state.ip();
-        FlatPtr ret_flags = state.flags();
-
-        dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to IP {:p}, SP {:p}", ret_ip, old_sp);
-
-        FlatPtr start_of_stack;
 #if ARCH(I386)
-        // Align the stack to 16 bytes.
-        // Note that we push some elements on to the stack before the return address,
-        // so we need to account for this here.
-        constexpr static FlatPtr elements_pushed_on_stack_before_return_address = 13;
-        FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr)) % 16;
-        stack -= stack_alignment;
-        start_of_stack = stack;
-
-        TRY(push_value_on_user_stack(stack, ret_flags));
-
-        TRY(push_value_on_user_stack(stack, ret_ip));
-        TRY(push_value_on_user_stack(stack, state.eax));
-        TRY(push_value_on_user_stack(stack, state.ecx));
-        TRY(push_value_on_user_stack(stack, state.edx));
-        TRY(push_value_on_user_stack(stack, state.ebx));
-        TRY(push_value_on_user_stack(stack, old_sp));
-        TRY(push_value_on_user_stack(stack, state.ebp));
-        TRY(push_value_on_user_stack(stack, state.esi));
-        TRY(push_value_on_user_stack(stack, state.edi));
+        constexpr static FlatPtr thread_red_zone_size = 0;
+#elif ARCH(X86_64)
+        constexpr static FlatPtr thread_red_zone_size = 128;
 #else
+#    error Unknown architecture in dispatch_signal
+#endif
+
         // Align the stack to 16 bytes.
         // Note that we push some elements on to the stack before the return address,
         // so we need to account for this here.
-        // We also are not allowed to touch the thread's red-zone of 128 bytes
-        constexpr static FlatPtr elements_pushed_on_stack_before_return_address = 21;
-        FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr)) % 16;
-        stack -= 128 + stack_alignment;
-        start_of_stack = stack;
-
-        TRY(push_value_on_user_stack(stack, ret_flags));
-
-        TRY(push_value_on_user_stack(stack, ret_ip));
-        TRY(push_value_on_user_stack(stack, state.r15));
-        TRY(push_value_on_user_stack(stack, state.r14));
-        TRY(push_value_on_user_stack(stack, state.r13));
-        TRY(push_value_on_user_stack(stack, state.r12));
-        TRY(push_value_on_user_stack(stack, state.r11));
-        TRY(push_value_on_user_stack(stack, state.r10));
-        TRY(push_value_on_user_stack(stack, state.r9));
-        TRY(push_value_on_user_stack(stack, state.r8));
-        TRY(push_value_on_user_stack(stack, state.rax));
-        TRY(push_value_on_user_stack(stack, state.rcx));
-        TRY(push_value_on_user_stack(stack, state.rdx));
-        TRY(push_value_on_user_stack(stack, state.rbx));
-        TRY(push_value_on_user_stack(stack, old_sp));
-        TRY(push_value_on_user_stack(stack, state.rbp));
-        TRY(push_value_on_user_stack(stack, state.rsi));
-        TRY(push_value_on_user_stack(stack, state.rdi));
-#endif
+        constexpr static FlatPtr elements_pushed_on_stack_before_handler_address = 1; // one slot for a saved register
+        FlatPtr const extra_bytes_pushed_on_stack_before_handler_address = sizeof(ucontext) + sizeof(signal_info);
+        FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) + extra_bytes_pushed_on_stack_before_handler_address) % 16;
+        // Also note that we have to skip the thread red-zone (if needed), so do that here.
+        stack -= thread_red_zone_size + stack_alignment;
+        auto start_of_stack = stack;
 
-        // PUSH old_signal_mask
-        TRY(push_value_on_user_stack(stack, old_signal_mask));
+        TRY(push_value_on_user_stack(stack, 0)); // syscall return value slot
 
-        TRY(push_value_on_user_stack(stack, signal));
-        TRY(push_value_on_user_stack(stack, handler_vaddr.get()));
+        TRY(copy_value_on_user_stack(stack, ucontext));
+        auto pointer_to_ucontext = stack;
+
+        TRY(copy_value_on_user_stack(stack, signal_info));
+        auto pointer_to_signal_info = stack;
 
         // Make sure we actually pushed as many elements as we claimed to have pushed.
-        if (start_of_stack - stack != elements_pushed_on_stack_before_return_address * sizeof(FlatPtr))
-            PANIC("Stack in invalid state after signal trampoline, expected {:x} but got {:x}", start_of_stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr), stack);
+        if (start_of_stack - stack != elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) + extra_bytes_pushed_on_stack_before_handler_address) {
+            PANIC("Stack in invalid state after signal trampoline, expected {:x} but got {:x}",
+                start_of_stack - elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) - extra_bytes_pushed_on_stack_before_handler_address, stack);
+        }
+
+        VERIFY(stack % 16 == 0);
+
+#if ARCH(I386)
+        // Leave one empty slot to align the stack for a handler call.
+        TRY(push_value_on_user_stack(stack, 0));
+#endif
+        TRY(push_value_on_user_stack(stack, pointer_to_ucontext));
+        TRY(push_value_on_user_stack(stack, pointer_to_signal_info));
+        TRY(push_value_on_user_stack(stack, signal));
 
+#if ARCH(I386)
         VERIFY(stack % 16 == 0);
+#endif
 
-        TRY(push_value_on_user_stack(stack, 0)); // push fake return address
+        TRY(push_value_on_user_stack(stack, handler_vaddr.get()));
 
         // We write back the adjusted stack value into the register state.
         // We have to do this because we can't just pass around a reference to a packed field, as it's UB.

+ 1 - 0
Kernel/UnixTypes.h

@@ -31,4 +31,5 @@
 #include <Kernel/API/POSIX/sys/wait.h>
 #include <Kernel/API/POSIX/termios.h>
 #include <Kernel/API/POSIX/time.h>
+#include <Kernel/API/POSIX/ucontext.h>
 #include <Kernel/API/POSIX/unistd.h>

+ 1 - 0
Tests/Kernel/CMakeLists.txt

@@ -15,6 +15,7 @@ set(TEST_SOURCES
     path-resolution-race.cpp
     pthread-cond-timedwait-example.cpp
     setpgid-across-sessions-without-leader.cpp
+    siginfo-example.cpp
     stress-truncate.cpp
     stress-writeread.cpp
     uaf-close-while-blocked-in-read.cpp

+ 108 - 0
Tests/Kernel/siginfo-example.cpp

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2020-2022, the SerenityOS developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// Supposed to use volatile everywhere here but good lord does C++ make that a pain
+volatile sig_atomic_t saved_signal;
+volatile siginfo_t saved_siginfo;
+volatile ucontext_t saved_ucontext;
+siginfo_t* sig_info_addr;
+ucontext_t* ucontext_addr;
+void* stack_ptr;
+volatile bool signal_was_delivered = false;
+
+static void signal_handler(int sig, siginfo_t* sig_info, void* u_context)
+{
+    int x;
+    stack_ptr = &x;
+    signal_was_delivered = true;
+
+    saved_signal = sig;
+    // grumble grumble, assignment operator on volatile types not a thing
+    // grumble grumble more, can't memcpy voltile either, that casts away volatile
+    // grumble grumble even more, can't std::copy to volatile.
+    // screw it, just write all the fields
+    sig_info_addr = sig_info;
+    saved_siginfo.si_status = sig_info->si_status;
+    saved_siginfo.si_signo = sig_info->si_signo;
+    saved_siginfo.si_code = sig_info->si_code;
+    saved_siginfo.si_pid = sig_info->si_pid;
+    saved_siginfo.si_uid = sig_info->si_uid;
+    saved_siginfo.si_value.sival_int = sig_info->si_value.sival_int;
+    auto user_context = (ucontext_t*)u_context;
+    ucontext_addr = user_context;
+    saved_ucontext.uc_link = user_context->uc_link;
+    saved_ucontext.uc_sigmask = user_context->uc_sigmask;
+    saved_ucontext.uc_stack.ss_sp = user_context->uc_stack.ss_sp;
+    saved_ucontext.uc_stack.ss_size = user_context->uc_stack.ss_size;
+    saved_ucontext.uc_stack.ss_flags = user_context->uc_stack.ss_flags;
+    // saved_ucontext.uc_mcontext = user_context->uc_mcontext;
+}
+
+static int print_signal_results()
+{
+    if (!signal_was_delivered) {
+        fprintf(stderr, "Where was my signal bro?\n");
+        return 2;
+    }
+
+    sig_atomic_t read_the_signal = saved_signal;
+    siginfo_t read_the_siginfo = {};
+    read_the_siginfo.si_status = saved_siginfo.si_status;
+    read_the_siginfo.si_signo = saved_siginfo.si_signo;
+    read_the_siginfo.si_code = saved_siginfo.si_code;
+    read_the_siginfo.si_pid = saved_siginfo.si_pid;
+    read_the_siginfo.si_uid = saved_siginfo.si_uid;
+    read_the_siginfo.si_value.sival_int = saved_siginfo.si_value.sival_int;
+
+    ucontext_t read_the_ucontext = {};
+    read_the_ucontext.uc_link = saved_ucontext.uc_link;
+    read_the_ucontext.uc_sigmask = saved_ucontext.uc_sigmask;
+    read_the_ucontext.uc_stack.ss_sp = saved_ucontext.uc_stack.ss_sp;
+    read_the_ucontext.uc_stack.ss_size = saved_ucontext.uc_stack.ss_size;
+    read_the_ucontext.uc_stack.ss_flags = saved_ucontext.uc_stack.ss_flags;
+    // read_the_ucontext.uc_mcontext = saved_ucontext.uc_mcontext;
+
+    printf("Handled signal: %d\n", read_the_signal);
+    printf("Stack sorta started as %p\n", stack_ptr);
+    printf("Siginfo was stored at %p:\n", sig_info_addr);
+    printf("\tsi_signo: %d\n", read_the_siginfo.si_signo);
+    printf("\tsi_code, %x\n", read_the_siginfo.si_code);
+    printf("\tsi_pid, %d\n", read_the_siginfo.si_pid);
+    printf("\tsi_uid, %d\n", read_the_siginfo.si_uid);
+    printf("\tsi_status, %x\n", read_the_siginfo.si_status);
+    printf("\tsi_value.sival_int, %x\n", read_the_siginfo.si_value.sival_int);
+    printf("ucontext was stored at %p:\n", ucontext_addr);
+    printf("\tuc_link, %p\n", read_the_ucontext.uc_link);
+    printf("\tuc_sigmask, %d\n", read_the_ucontext.uc_sigmask);
+    printf("\tuc_stack.ss_sp, %p\n", read_the_ucontext.uc_stack.ss_sp);
+    printf("\tuc_stack.ss_size, %zu\n", read_the_ucontext.uc_stack.ss_size);
+    printf("\tuc_stack.ss_flags, %d\n", read_the_ucontext.uc_stack.ss_flags);
+    // printf("\tuc_mcontext, %d\n", read_the_ucontext.uc_mcontext);
+
+    return 0;
+}
+
+int main()
+{
+    struct sigaction action = {};
+    action.sa_flags = SA_SIGINFO;
+    sigemptyset(&action.sa_mask);
+    action.sa_sigaction = signal_handler;
+
+    for (size_t i = 0; i < NSIG; ++i)
+        (void)sigaction(i, &action, nullptr);
+
+    printf("Sleeping for a long time waiting for kill -<N> %d\n", getpid());
+
+    sleep(1000);
+    return print_signal_results();
+}

+ 14 - 2
Toolchain/BuildIt.sh

@@ -350,9 +350,21 @@ pushd "$DIR/Build/$ARCH"
     pushd "$BUILD"
         mkdir -p Root/usr/include/
         SRC_ROOT=$($REALPATH "$DIR"/..)
-        FILES=$(find "$SRC_ROOT"/Kernel/API "$SRC_ROOT"/Userland/Libraries/LibC "$SRC_ROOT"/Userland/Libraries/LibM "$SRC_ROOT"/Userland/Libraries/LibPthread -name '*.h' -print)
+        FILES=$(find \
+            "$SRC_ROOT"/AK \
+            "$SRC_ROOT"/Kernel/API \
+            "$SRC_ROOT"/Kernel/Arch \
+            "$SRC_ROOT"/Userland/Libraries/LibC \
+            "$SRC_ROOT"/Userland/Libraries/LibM \
+            "$SRC_ROOT"/Userland/Libraries/LibPthread \
+            -name '*.h' -print)
         for header in $FILES; do
-            target=$(echo "$header" | sed -e "s@$SRC_ROOT/Userland/Libraries/LibC@@" -e "s@$SRC_ROOT/Userland/Libraries/LibM@@" -e "s@$SRC_ROOT/Userland/Libraries/LibPthread@@" -e "s@$SRC_ROOT/Kernel/@Kernel/@")
+            target=$(echo "$header" | sed \
+                -e "s@$SRC_ROOT/AK/@AK/@" \
+                -e "s@$SRC_ROOT/Userland/Libraries/LibC@@" \
+                -e "s@$SRC_ROOT/Userland/Libraries/LibM@@" \
+                -e "s@$SRC_ROOT/Userland/Libraries/LibPthread@@" \
+                -e "s@$SRC_ROOT/Kernel/@Kernel/@")
             buildstep "system_headers" $INSTALL -D "$header" "Root/usr/include/$target"
         done
         unset SRC_ROOT

+ 1 - 0
Userland/Libraries/LibC/signal.h

@@ -7,6 +7,7 @@
 #pragma once
 
 #include <Kernel/API/POSIX/signal.h>
+#include <Kernel/API/POSIX/ucontext.h>
 #include <bits/sighow.h>
 #include <signal_numbers.h>
 #include <sys/types.h>

+ 21 - 52
Userland/Libraries/LibC/sys/arch/i386/regs.h

@@ -14,80 +14,49 @@
 #    include <sys/types.h>
 #endif
 
-struct [[gnu::packed]] PtraceRegisters {
-#if ARCH(I386)
-    uint32_t eax;
-    uint32_t ecx;
-    uint32_t edx;
-    uint32_t ebx;
-    uint32_t esp;
-    uint32_t ebp;
-    uint32_t esi;
-    uint32_t edi;
-    uint32_t eip;
-    uint32_t eflags;
-#else
-    uint64_t rax;
-    uint64_t rcx;
-    uint64_t rdx;
-    uint64_t rbx;
-    uint64_t rsp;
-    uint64_t rbp;
-    uint64_t rsi;
-    uint64_t rdi;
-    uint64_t rip;
-    uint64_t r8;
-    uint64_t r9;
-    uint64_t r10;
-    uint64_t r11;
-    uint64_t r12;
-    uint64_t r13;
-    uint64_t r14;
-    uint64_t r15;
-    uint64_t rflags;
-#endif
-    uint32_t cs;
-    uint32_t ss;
-    uint32_t ds;
-    uint32_t es;
-    uint32_t fs;
-    uint32_t gs;
+#include <Kernel/Arch/mcontext.h>
 
-#if defined(__cplusplus) && defined(__cpp_concepts)
+#ifdef __cplusplus
+struct [[gnu::packed]] PtraceRegisters : public __mcontext {
+#    if defined(__cplusplus) && defined(__cpp_concepts)
     FlatPtr ip() const
     {
-#    if ARCH(I386)
+#        if ARCH(I386)
         return eip;
-#    else
+#        else
         return rip;
-#    endif
+#        endif
     }
 
     void set_ip(FlatPtr ip)
     {
-#    if ARCH(I386)
+#        if ARCH(I386)
         eip = ip;
-#    else
+#        else
         rip = ip;
-#    endif
+#        endif
     }
 
     FlatPtr bp() const
     {
-#    if ARCH(I386)
+#        if ARCH(I386)
         return ebp;
-#    else
+#        else
         return rbp;
-#    endif
+#        endif
     }
 
     void set_bp(FlatPtr bp)
     {
-#    if ARCH(I386)
+#        if ARCH(I386)
         ebp = bp;
-#    else
+#        else
         rbp = bp;
-#    endif
+#        endif
     }
-#endif
+#    endif
 };
+
+#else
+typedef struct __mcontext PthreadRegisters;
+#endif