diff --git a/Kernel/API/POSIX/ucontext.h b/Kernel/API/POSIX/ucontext.h new file mode 100644 index 0000000000..306c41cac4 --- /dev/null +++ b/Kernel/API/POSIX/ucontext.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022, Ali Mohammad Pur + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +#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 diff --git a/Kernel/Arch/mcontext.h b/Kernel/Arch/mcontext.h new file mode 100644 index 0000000000..ee62f487bd --- /dev/null +++ b/Kernel/Arch/mcontext.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#if ARCH(X86_64) || ARCH(I386) +# include +#elif ARCH(AARCH64) +# error "Unknown architecture" +#endif diff --git a/Kernel/Arch/x86/mcontext.h b/Kernel/Arch/x86/mcontext.h new file mode 100644 index 0000000000..a01376ef98 --- /dev/null +++ b/Kernel/Arch/x86/mcontext.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +#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 diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 6703d83d89..d1b4946748 100644 --- a/Kernel/Process.cpp +++ b/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 } diff --git a/Kernel/Syscalls/sigaction.cpp b/Kernel/Syscalls/sigaction.cpp index f061501b93..b11d3c7a72 100644 --- a/Kernel/Syscalls/sigaction.cpp +++ b/Kernel/Syscalls/sigaction.cpp @@ -68,8 +68,6 @@ ErrorOr Process::sys$sigaction(int signum, Userspace } 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(act.sa_sigaction) }; @@ -83,63 +81,36 @@ ErrorOr 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(registers.userspace_esp); - FlatPtr smuggled_eax = *stack_ptr; + auto stack_ptr = registers.userspace_sp(); - // 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(®isters.edi, stack_ptr, 8 * sizeof(FlatPtr)); - stack_ptr += 8; - - registers.eip = *stack_ptr; - stack_ptr++; - - 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 + // saved_ax, ucontext, signal_info. + stack_ptr += sizeof(siginfo); // We don't need this here. - // 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; + auto ucontext = TRY(copy_typed_from_user<__ucontext>(stack_ptr)); + stack_ptr += sizeof(__ucontext); - // pop the stored rax, rbp, return address, handler and signal code - stack_ptr += 5; + auto saved_ax = TRY(copy_typed_from_user(stack_ptr)); - Thread::current()->m_signal_mask = *stack_ptr; - stack_ptr++; - - // pop rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, r8, r9, r10, r11, r12, r13, r14 and r15 - memcpy(®isters.rdi, stack_ptr, 16 * sizeof(FlatPtr)); - stack_ptr += 16; - - registers.rip = *stack_ptr; - stack_ptr++; - - registers.rflags = (registers.rflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask); - stack_ptr++; - - registers.userspace_rsp = registers.rsp; - return smuggled_rax; + Thread::current()->m_signal_mask = ucontext.uc_sigmask; +#if ARCH(X86_64) + auto sp = registers.rsp; +#elif ARCH(I386) + auto sp = registers.esp; #endif + + copy_ptrace_registers_into_kernel_registers(registers, static_cast(ucontext.uc_mcontext)); + +#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 Process::remap_range_as_stack(FlatPtr address, size_t size) diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index ccc8ff6a33..837741fc50 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -938,6 +938,13 @@ static ErrorOr push_value_on_user_stack(FlatPtr& stack, FlatPtr data) return copy_to_user((FlatPtr*)stack, &data); } +template +static ErrorOr copy_value_on_user_stack(FlatPtr& stack, T const& data) +{ + stack -= sizeof(data); + return copy_to_user((RemoveCVReference*)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 { - 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(); - 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}", state.ip(), state.userspace_sp()); - dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to IP {:p}, SP {:p}", ret_ip, old_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(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 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 - // 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)); +# error Unknown architecture in dispatch_signal #endif - // PUSH old_signal_mask - TRY(push_value_on_user_stack(stack, old_signal_mask)); + // 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_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; - TRY(push_value_on_user_stack(stack, signal)); - TRY(push_value_on_user_stack(stack, handler_vaddr.get())); + TRY(push_value_on_user_stack(stack, 0)); // syscall return value slot + + 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); - TRY(push_value_on_user_stack(stack, 0)); // push fake return address +#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, 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. diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 586b3ae0c8..05b33873a8 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -31,4 +31,5 @@ #include #include #include +#include #include diff --git a/Tests/Kernel/CMakeLists.txt b/Tests/Kernel/CMakeLists.txt index 5744a74cc6..61d51e68a8 100644 --- a/Tests/Kernel/CMakeLists.txt +++ b/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 diff --git a/Tests/Kernel/siginfo-example.cpp b/Tests/Kernel/siginfo-example.cpp new file mode 100644 index 0000000000..75cf4745f9 --- /dev/null +++ b/Tests/Kernel/siginfo-example.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020-2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +// 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 - %d\n", getpid()); + + sleep(1000); + return print_signal_results(); +} diff --git a/Toolchain/BuildIt.sh b/Toolchain/BuildIt.sh index d4f7f39ae7..395357f928 100755 --- a/Toolchain/BuildIt.sh +++ b/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 diff --git a/Userland/Libraries/LibC/signal.h b/Userland/Libraries/LibC/signal.h index ee1593a113..3ed14348a0 100644 --- a/Userland/Libraries/LibC/signal.h +++ b/Userland/Libraries/LibC/signal.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include diff --git a/Userland/Libraries/LibC/sys/arch/i386/regs.h b/Userland/Libraries/LibC/sys/arch/i386/regs.h index 098feb99dc..478923ba78 100644 --- a/Userland/Libraries/LibC/sys/arch/i386/regs.h +++ b/Userland/Libraries/LibC/sys/arch/i386/regs.h @@ -14,80 +14,49 @@ # include #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 -#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