diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2022-02-28 00:00:47 +0330 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-04 20:07:05 +0100 |
commit | 1125cbe336ccbaafed45b08f816d92e4a5f45353 (patch) | |
tree | f8adb664f707917fd7a5e55a6b94b6b4e0c0301d /Userland/DevTools/UserspaceEmulator | |
parent | baf70389198847f62d3b3b8f7531abc1a82c897a (diff) | |
download | serenity-1125cbe336ccbaafed45b08f816d92e4a5f45353.zip |
UserspaceEmulator: Update signal handlers to use the new stack layout
The kernel sets up the stack like this, so set it up the same way.
Diffstat (limited to 'Userland/DevTools/UserspaceEmulator')
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/Emulator.cpp | 125 | ||||
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp | 47 |
2 files changed, 123 insertions, 49 deletions
diff --git a/Userland/DevTools/UserspaceEmulator/Emulator.cpp b/Userland/DevTools/UserspaceEmulator/Emulator.cpp index 4e37afaf16..f9a6a10961 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator.cpp @@ -616,31 +616,81 @@ void Emulator::dispatch_one_pending_signal() reportln("\n=={}== Got signal {} ({}), handler at {:p}", getpid(), signum, strsignal(signum), handler.handler); - auto old_esp = m_cpu->esp(); - - u32 stack_alignment = (m_cpu->esp().value() - 52) % 16; - m_cpu->set_esp(shadow_wrap_as_initialized(m_cpu->esp().value() - stack_alignment)); - - m_cpu->push32(shadow_wrap_as_initialized(m_cpu->eflags())); - m_cpu->push32(shadow_wrap_as_initialized(m_cpu->eip())); - m_cpu->push32(m_cpu->eax()); - m_cpu->push32(m_cpu->ecx()); - m_cpu->push32(m_cpu->edx()); - m_cpu->push32(m_cpu->ebx()); - m_cpu->push32(old_esp); - m_cpu->push32(m_cpu->ebp()); - m_cpu->push32(m_cpu->esi()); - m_cpu->push32(m_cpu->edi()); - - // FIXME: Push old signal mask here. - m_cpu->push32(shadow_wrap_as_initialized(0u)); + auto old_esp = m_cpu->esp().value(); + + ucontext_t ucontext { + .uc_link = nullptr, + .uc_sigmask = m_signal_mask, + .uc_stack = { + .ss_sp = bit_cast<void*>(old_esp), + .ss_flags = 0, + .ss_size = 0, + }, + .uc_mcontext = { + .eax = m_cpu->eax().value(), + .ecx = m_cpu->ecx().value(), + .edx = m_cpu->edx().value(), + .ebx = m_cpu->ebx().value(), + .esp = m_cpu->esp().value(), + .ebp = m_cpu->ebp().value(), + .esi = m_cpu->esi().value(), + .edi = m_cpu->edi().value(), + .eip = m_cpu->eip(), + .eflags = m_cpu->eflags(), + .cs = m_cpu->cs(), + .ss = m_cpu->ss(), + .ds = m_cpu->ds(), + .es = m_cpu->es(), + // ??? + .fs = 0, + .gs = 0, + }, + }; + + // FIXME: Set these fields. + siginfo_t signal_info { + .si_signo = signum, + .si_code = 0, + .si_errno = 0, + .si_pid = 0, + .si_uid = 0, + .si_addr = 0, + .si_status = 0, + .si_band = 0, + .si_value = { + .sival_int = 0, + }, + }; + + // 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_t) + sizeof(siginfo_t); + FlatPtr stack_alignment = (old_esp - 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. + old_esp -= stack_alignment; - m_cpu->push32(shadow_wrap_as_initialized((u32)signum)); - m_cpu->push32(shadow_wrap_as_initialized(handler.handler)); + m_cpu->set_esp(shadow_wrap_with_taint_from(old_esp, m_cpu->esp())); - VERIFY((m_cpu->esp().value() % 16) == 0); + m_cpu->push32(shadow_wrap_as_initialized(0u)); // syscall return value slot + m_cpu->push_buffer(bit_cast<u8 const*>(&ucontext), sizeof(ucontext_t)); + auto pointer_to_ucontext = m_cpu->esp().value(); + + m_cpu->push_buffer(bit_cast<u8 const*>(&signal_info), sizeof(siginfo_t)); + auto pointer_to_signal_info = m_cpu->esp().value(); + + // FPU state, leave a 512-byte gap. FIXME: Fill this in. + m_cpu->set_esp({ m_cpu->esp().value() - 512, m_cpu->esp().shadow() }); + + // Leave one empty slot to align the stack for a handler call. m_cpu->push32(shadow_wrap_as_initialized(0u)); + m_cpu->push32(shadow_wrap_as_initialized(pointer_to_ucontext)); + m_cpu->push32(shadow_wrap_as_initialized(pointer_to_signal_info)); + m_cpu->push32(shadow_wrap_as_initialized(static_cast<u32>(signum))); + + m_cpu->push32(shadow_wrap_as_initialized<u32>(handler.handler)); m_cpu->set_eip(m_signal_trampoline); } @@ -654,21 +704,34 @@ NEVER_INLINE 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) + 512 + 4 * sizeof(FlatPtr); asm( ".intel_syntax noprefix\n" + ".globl asm_signal_trampoline\n" "asm_signal_trampoline:\n" - "push ebp\n" - "mov ebp, esp\n" - "push eax\n" // we have to store eax 'cause it might be the return value from a syscall - "sub esp, 4\n" // align the stack to 16 bytes - "mov eax, [ebp+12]\n" // push the signal code - "push eax\n" - "call [ebp+8]\n" // call the signal handler - "add esp, 8\n" + // stack state: 0, ucontext, signal_info, (alignment = 16), fpu_state (alignment = 16), 0, ucontext*, siginfo*, signal, (alignment = 16), handler + + // 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 + "mov [esp+%P2], 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 ecx\n" + // drop the 4 arguments + "add esp, 16\n" + // Current stack state is just saved_eax, ucontext, signal_info, fpu_state?. + // syscall SC_sigreturn "mov eax, %P0\n" - "int 0x82\n" // sigreturn syscall + "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), + "i"(offset_to_first_register_slot - sizeof(FlatPtr))); } extern "C" void asm_signal_trampoline(void); diff --git a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp index 311459ba30..ea35e75604 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp @@ -1400,32 +1400,43 @@ int Emulator::virt$sigprocmask(int how, FlatPtr set, FlatPtr old_set) int Emulator::virt$sigreturn() { u32 stack_ptr = m_cpu->esp().value(); - auto local_pop = [&]() -> ValueWithShadow<u32> { - auto value = m_cpu->read_memory32({ m_cpu->ss(), stack_ptr }); - stack_ptr += sizeof(u32); + auto local_pop = [&]<typename T>() { + auto value = m_cpu->read_memory<T>({ m_cpu->ss(), stack_ptr }); + stack_ptr += sizeof(T); return value; }; - auto smuggled_eax = local_pop(); + // State from signal trampoline (note that we're assuming i386 here): + // saved_ax, ucontext, signal_info, fpu_state. - stack_ptr += 4 * sizeof(u32); + // Drop the FPU state + // FIXME: Read and restore from this. + stack_ptr += 512; - m_signal_mask = local_pop().value(); + // Drop the signal info + stack_ptr += sizeof(siginfo_t); - m_cpu->set_edi(local_pop()); - m_cpu->set_esi(local_pop()); - m_cpu->set_ebp(local_pop()); - m_cpu->set_esp(local_pop()); - m_cpu->set_ebx(local_pop()); - m_cpu->set_edx(local_pop()); - m_cpu->set_ecx(local_pop()); - m_cpu->set_eax(local_pop()); + auto ucontext = local_pop.operator()<ucontext_t>(); - m_cpu->set_eip(local_pop().value()); - m_cpu->set_eflags(local_pop()); + auto eax = local_pop.operator()<u32>(); - // FIXME: We're losing shadow bits here. - return smuggled_eax.value(); + m_signal_mask = ucontext.value().uc_sigmask; + + auto mcontext_slice = ucontext.slice<&ucontext_t::uc_mcontext>(); + + m_cpu->set_edi(mcontext_slice.slice<&__mcontext::edi>()); + m_cpu->set_esi(mcontext_slice.slice<&__mcontext::esi>()); + m_cpu->set_ebp(mcontext_slice.slice<&__mcontext::ebp>()); + m_cpu->set_esp(mcontext_slice.slice<&__mcontext::esp>()); + m_cpu->set_ebx(mcontext_slice.slice<&__mcontext::ebx>()); + m_cpu->set_edx(mcontext_slice.slice<&__mcontext::edx>()); + m_cpu->set_ecx(mcontext_slice.slice<&__mcontext::ecx>()); + m_cpu->set_eax(mcontext_slice.slice<&__mcontext::eax>()); + m_cpu->set_eip(mcontext_slice.value().eip); + m_cpu->set_eflags(mcontext_slice.slice<&__mcontext::eflags>()); + + // FIXME: We're dropping the shadow bits here. + return eax.value(); } int Emulator::virt$getpgrp() |