From bdd62011eb8acba7587c0636fc37f20a0a640ae5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Jan 2008 10:08:47 -0700 Subject: [PATCH] fix up access violation handling on windows; refactor posix segv handling to match API change needed for windows --- src/compile.S | 20 -------------------- src/compile.cpp | 49 +++++++++++++++++++++++++++++++++++-------------- src/posix.cpp | 28 +++++++++++++++++++++------- src/system.h | 3 ++- src/windows.cpp | 13 +++++++++---- src/x86.S | 20 ++++++++++++++++++++ src/x86.h | 4 ++++ 7 files changed, 91 insertions(+), 46 deletions(-) diff --git a/src/compile.S b/src/compile.S index 4daccf30fe..3464784fa6 100644 --- a/src/compile.S +++ b/src/compile.S @@ -59,13 +59,6 @@ test: popq %rbp ret -.globl vmJump -vmJump: - movq %rsi,%rbp - movq %rdx,%rsp - movq %rcx,%rbx - jmp *%rdi - #elif defined __i386__ # if defined __APPLE__ || defined __MINGW32__ @@ -135,19 +128,6 @@ exit: movl %ebp,%esp popl %ebp ret - -# if defined __APPLE__ || defined __MINGW32__ -.globl _vmJump -_vmJump: -# else -.globl vmJump -vmJump: -# endif - movl 4(%esp),%eax - movl 8(%esp),%ebp - movl 16(%esp),%ebx - movl 12(%esp),%esp - jmp *%eax #else # error unsupported platform diff --git a/src/compile.cpp b/src/compile.cpp index 9df75d6330..463a6fc861 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -3,6 +3,7 @@ #include "vector.h" #include "process.h" #include "compiler.h" +#include "x86.h" using namespace vm; @@ -13,9 +14,6 @@ vmInvoke(void* thread, void* function, void* stack, unsigned stackSize, extern "C" void vmCall(); -extern "C" void NO_RETURN -vmJump(void* address, void* base, void* stack, void* thread); - namespace { const bool Verbose = false; @@ -996,8 +994,9 @@ class Frame { unsigned sp; }; -void NO_RETURN -unwind(MyThread* t) +void +findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, + void** targetStack) { void* ip = t->ip; void* base = t->base; @@ -1008,7 +1007,8 @@ unwind(MyThread* t) ip = *stack; } - while (true) { + *targetIp = 0; + while (*targetIp == 0) { object node = findTraceNode(t, ip); if (node) { object method = traceNodeMethod(t, node); @@ -1028,7 +1028,9 @@ unwind(MyThread* t) *(--stack) = t->exception; t->exception = 0; - vmJump(compiled + exceptionHandlerIp(handler), base, stack, t); + *targetIp = compiled + exceptionHandlerIp(handler); + *targetBase = base; + *targetStack = stack; } else { if (methodFlags(t, method) & ACC_SYNCHRONIZED) { object lock; @@ -1046,11 +1048,23 @@ unwind(MyThread* t) base = *static_cast(base); } } else { - vmJump(ip, base, stack + 1, 0); + *targetIp = ip; + *targetBase = base; + *targetStack = stack + 1; } } } +void NO_RETURN +unwind(MyThread* t) +{ + void* ip; + void* base; + void* stack; + findUnwindTarget(t, &ip, &base, &stack); + vmJump(ip, base, stack, t); +} + void insertTraceNode(MyThread* t, object method, object target, bool virtualCall, uintptr_t* map, void* address) @@ -3997,15 +4011,22 @@ class SegFaultHandler: public System::SignalHandler { public: SegFaultHandler(): m(0) { } - virtual void handleSignal(void* ip, void* base, void* stack) { + virtual bool handleSignal(void** ip, void** base, void** stack, + void** thread) + { MyThread* t = static_cast(m->localThread->get()); - object node = findTraceNode(t, ip); + object node = findTraceNode(t, *ip); if (node) { - t->ip = ip; - t->base = base; - t->stack = stack; + t->ip = *ip; + t->base = *base; + t->stack = *stack; t->exception = makeNullPointerException(t); - unwind(t); + + findUnwindTarget(t, ip, base, stack); + *thread = t; + return true; + } else { + return false; } } diff --git a/src/posix.cpp b/src/posix.cpp index d4ec599d6b..869634e997 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -9,6 +9,7 @@ #include "unistd.h" #include "pthread.h" #include "signal.h" +#include "ucontext.h" #include "stdint.h" #include "x86.h" @@ -43,10 +44,12 @@ const int InterruptSignal = SIGUSR2; const int IpRegister = REG_RIP; const int BaseRegister = REG_RBP; const int StackRegister = REG_RSP; +const int ThreadRegister = REG_RBX; #elif defined __i386__ const int IpRegister = REG_EIP; const int BaseRegister = REG_EBP; const int StackRegister = REG_ESP; +const int ThreadRegister = REG_EBX; #else # error unsupported architecture #endif @@ -61,15 +64,26 @@ handleSignal(int signal, siginfo_t* info, void* context) sigaddset(&set, SIGSEGV); sigprocmask(SIG_UNBLOCK, &set, 0); - greg_t* registers - = static_cast(context)->uc_mcontext.gregs; + ucontext_t* c = static_cast(context); - segFaultHandler->handleSignal - (reinterpret_cast(registers[IpRegister]), - reinterpret_cast(registers[BaseRegister]), - reinterpret_cast(registers[StackRegister])); + greg_t* registers = c->uc_mcontext.gregs; + bool jump = segFaultHandler->handleSignal + (reinterpret_cast(registers + IpRegister), + reinterpret_cast(registers + BaseRegister), + reinterpret_cast(registers + StackRegister), + reinterpret_cast(registers + ThreadRegister)); - if (oldSegFaultHandler.sa_flags & SA_SIGINFO) { + if (jump) { + // I'd like to use setcontext here (and get rid of the + // sigprocmask call above), but it doesn't work on my system, + // and I can't tell from the documentation if it's even supposed + // to work. + + vmJump(reinterpret_cast(registers[IpRegister]), + reinterpret_cast(registers[BaseRegister]), + reinterpret_cast(registers[StackRegister]), + reinterpret_cast(registers[ThreadRegister])); + } else if (oldSegFaultHandler.sa_flags & SA_SIGINFO) { oldSegFaultHandler.sa_sigaction(signal, info, context); } else if (oldSegFaultHandler.sa_handler) { oldSegFaultHandler.sa_handler(signal); diff --git a/src/system.h b/src/system.h index cf13134b13..9b1fc6541e 100644 --- a/src/system.h +++ b/src/system.h @@ -84,7 +84,8 @@ class System: public Allocator { public: virtual ~SignalHandler() { } - virtual void handleSignal(void* ip, void* base, void* stack) = 0; + virtual bool handleSignal(void** ip, void** base, void** stack, + void** thread) = 0; }; virtual ~System() { } diff --git a/src/windows.cpp b/src/windows.cpp index edafa31d54..a5749d517f 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -20,10 +20,15 @@ LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - segFaultHandler->handleSignal - (reinterpret_cast(e->ContextRecord->Eip), - reinterpret_cast(e->ContextRecord->Ebp), - reinterpret_cast(e->ContextRecord->Esp)); + bool jump = segFaultHandler->handleSignal + (reinterpret_cast(&(e->ContextRecord->Eip)), + reinterpret_cast(&(e->ContextRecord->Ebp)), + reinterpret_cast(&(e->ContextRecord->Esp)), + reinterpret_cast(&(e->ContextRecord->Ebx))); + + if (jump) { + return EXCEPTION_CONTINUE_EXECUTION; + } } return EXCEPTION_CONTINUE_SEARCH; } diff --git a/src/x86.S b/src/x86.S index a1c21ff776..f6d2025303 100644 --- a/src/x86.S +++ b/src/x86.S @@ -106,6 +106,13 @@ exit: popq %rbp ret +.globl vmJump +vmJump: + movq %rsi,%rbp + movq %rdx,%rsp + movq %rcx,%rbx + jmp *%rdi + #elif defined __i386__ # if defined __APPLE__ || defined __MINGW32__ @@ -184,6 +191,19 @@ exit: movl %ebp,%esp popl %ebp ret + +# if defined __APPLE__ || defined __MINGW32__ +.globl _vmJump +_vmJump: +# else +.globl vmJump +vmJump: +# endif + movl 4(%esp),%eax + movl 8(%esp),%ebp + movl 16(%esp),%ebx + movl 12(%esp),%esp + jmp *%eax #else # error unsupported platform diff --git a/src/x86.h b/src/x86.h index a3412c6283..0987ce0993 100644 --- a/src/x86.h +++ b/src/x86.h @@ -3,6 +3,10 @@ #include "types.h" #include "stdint.h" +#include "common.h" + +extern "C" void NO_RETURN +vmJump(void* address, void* base, void* stack, void* thread); #ifdef __i386__