summaryrefslogtreecommitdiff
path: root/Userland/DevTools/UserspaceEmulator
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2022-02-28 00:00:47 +0330
committerAndreas Kling <kling@serenityos.org>2022-03-04 20:07:05 +0100
commit1125cbe336ccbaafed45b08f816d92e4a5f45353 (patch)
treef8adb664f707917fd7a5e55a6b94b6b4e0c0301d /Userland/DevTools/UserspaceEmulator
parentbaf70389198847f62d3b3b8f7531abc1a82c897a (diff)
downloadserenity-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.cpp125
-rw-r--r--Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp47
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()