From 730dade53eebc4bc00723598bff2a53389f139eb Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 21 Feb 2014 17:06:17 -0700 Subject: [PATCH] break out signal handling from System --- include/avian/system/signal.h | 67 ++++++ include/avian/system/system.h | 11 +- makefile | 2 + src/avian/machine.h | 1 + src/avian/processor.h | 6 +- src/compile.cpp | 63 +++--- src/interpret.cpp | 20 +- src/jnienv.cpp | 4 +- src/main.cpp | 2 +- src/system/posix.cpp | 151 +++---------- src/system/posix/signal.cpp | 207 ++++++++++++++++++ src/system/windows.cpp | 196 +---------------- src/system/windows/signal.cpp | 279 +++++++++++++++++++++++++ src/tools/audit-codegen/main.cpp | 2 +- src/tools/bootimage-generator/main.cpp | 4 +- src/tools/type-generator/main.cpp | 2 +- unittest/codegen/assembler-test.cpp | 2 +- 17 files changed, 649 insertions(+), 370 deletions(-) create mode 100644 include/avian/system/signal.h create mode 100644 src/system/posix/signal.cpp create mode 100644 src/system/windows/signal.cpp diff --git a/include/avian/system/signal.h b/include/avian/system/signal.h new file mode 100644 index 0000000000..d9314415be --- /dev/null +++ b/include/avian/system/signal.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#ifndef AVIAN_SYSTEM_SIGNAL_H +#define AVIAN_SYSTEM_SIGNAL_H + +namespace avian { +namespace system { + +// Registrar for unix-like "signals" (implemented with structured exceptions on windows). +// TODO: remove dependence on generated code having a well-known "thread" +// register. Use a thread-local variable instead. +class SignalRegistrar { + public: + class Handler { + public: + // This function receives state information about the paused thread. + // Returns whether to resume execution after the failure point. + virtual bool handleSignal(void** ip, + void** frame, + void** stack, + void** thread) = 0; + }; + + SignalRegistrar(); + ~SignalRegistrar(); + + // Register a handler for segfault signals. + // After this method call, any segfault exceptions (mostly null pointer + // dereference, but generally access to any non-mapped memory) will be handled + // by the given handler. Pass null (0) to unregister a handler. + // Returns true upon success, false upon failure + bool handleSegFault(Handler* handler); + + // Register a handler for divide-by-zero signals. + // After this method call, any divide-by-zero exceptions will be handled by + // the given handler. Pass null (0) to unregister a handler. + // Returns true upon success, false upon failure + bool handleDivideByZero(Handler* handler); + + // Set the directory that a crash dump will be written to should an unhandled + // exception be thrown. + // Note: this only currently does anything on windows. + // TODO: move this out of this class, into a separate "CrashDumper" class or + // somesuch. + void setCrashDumpDirectory(const char* crashDumpDirectory); + + // This is internal, implementation-specific data. It's declared in the + // specific implementation. + struct Data; + + private: + + Data* data; +}; + +} // namespace system +} // namespace avian + +#endif diff --git a/include/avian/system/system.h b/include/avian/system/system.h index 014b288a60..2427fd1f57 100644 --- a/include/avian/system/system.h +++ b/include/avian/system/system.h @@ -98,12 +98,6 @@ class System : public avian::util::Aborter { virtual void disposeAll() = 0; }; - class SignalHandler { - public: - virtual bool handleSignal(void** ip, void** frame, void** stack, - void** thread) = 0; - }; - class MonitorResource { public: MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) { @@ -131,8 +125,7 @@ class System : public avian::util::Aborter { virtual Status make(Mutex**) = 0; virtual Status make(Monitor**) = 0; virtual Status make(Local**) = 0; - virtual Status handleSegFault(SignalHandler* handler) = 0; - virtual Status handleDivideByZero(SignalHandler* handler) = 0; + virtual Status visit(Thread* thread, Thread* target, ThreadVisitor* visitor) = 0; virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, @@ -193,7 +186,7 @@ sysAbort(System* s) // #endif // not NDEBUG AVIAN_EXPORT System* -makeSystem(const char* crashDumpDirectory); +makeSystem(); } // namespace vm diff --git a/makefile b/makefile index 0781e3b0b4..269bdc03d9 100755 --- a/makefile +++ b/makefile @@ -1109,6 +1109,7 @@ vm-depends := $(generated-code) \ vm-sources = \ $(src)/system/$(system).cpp \ + $(src)/system/$(system)/signal.cpp \ $(src)/finder.cpp \ $(src)/machine.cpp \ $(src)/util.cpp \ @@ -1240,6 +1241,7 @@ generator-depends := $(wildcard $(src)/*.h) generator-sources = \ $(src)/tools/type-generator/main.cpp \ $(src)/system/$(build-system).cpp \ + $(src)/system/$(build-system)/signal.cpp \ $(src)/finder.cpp ifneq ($(lzma),) diff --git a/src/avian/machine.h b/src/avian/machine.h index f466979216..e1cca45ad2 100644 --- a/src/avian/machine.h +++ b/src/avian/machine.h @@ -14,6 +14,7 @@ #include "avian/common.h" #include "java-common.h" #include +#include #include #include "avian/finder.h" #include "avian/processor.h" diff --git a/src/avian/processor.h b/src/avian/processor.h index 40e02f43aa..94ad8b7d0e 100644 --- a/src/avian/processor.h +++ b/src/avian/processor.h @@ -208,8 +208,10 @@ class Processor { } }; -Processor* -makeProcessor(System* system, Allocator* allocator, bool useNativeFeatures); +Processor* makeProcessor(System* system, + Allocator* allocator, + const char* crashDumpDirectory, + bool useNativeFeatures); } // namespace vm diff --git a/src/compile.cpp b/src/compile.cpp index 87a303f96f..f716fe4e1f 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -43,6 +43,7 @@ vmJumpAndInvoke(void* thread, void* function, void* stack, unsigned frameSize); using namespace avian::codegen; +using namespace avian::system; namespace { @@ -8366,7 +8367,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) return r; } -class SignalHandler: public System::SignalHandler { +class SignalHandler: public SignalRegistrar::Handler { public: SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): m(0), type(type), root(root), fixedSize(fixedSize) { } @@ -8501,24 +8502,27 @@ class MyProcessor: public Processor { Thunk table; }; - MyProcessor(System* s, Allocator* allocator, bool useNativeFeatures): - s(s), - allocator(allocator), - roots(0), - bootImage(0), - heapImage(0), - codeImage(0), - codeImageSize(0), - segFaultHandler(Machine::NullPointerExceptionType, - Machine::NullPointerException, - FixedSizeOfNullPointerException), - divideByZeroHandler(Machine::ArithmeticExceptionType, - Machine::ArithmeticException, - FixedSizeOfArithmeticException), - codeAllocator(s, 0, 0), - callTableSize(0), - useNativeFeatures(useNativeFeatures), - compilationHandlers(0) + MyProcessor(System* s, + Allocator* allocator, + const char* crashDumpDirectory, + bool useNativeFeatures) + : s(s), + allocator(allocator), + roots(0), + bootImage(0), + heapImage(0), + codeImage(0), + codeImageSize(0), + segFaultHandler(Machine::NullPointerExceptionType, + Machine::NullPointerException, + FixedSizeOfNullPointerException), + divideByZeroHandler(Machine::ArithmeticExceptionType, + Machine::ArithmeticException, + FixedSizeOfArithmeticException), + codeAllocator(s, 0, 0), + callTableSize(0), + useNativeFeatures(useNativeFeatures), + compilationHandlers(0) { thunkTable[compileMethodIndex] = voidPointer(local::compileMethod); thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod); @@ -8540,6 +8544,8 @@ class MyProcessor: public Processor { // table. thunkTable[dummyIndex] = reinterpret_cast (static_cast(UINT64_C(0x5555555555555555))); + + signals.setCrashDumpDirectory(crashDumpDirectory); } virtual Thread* @@ -8924,7 +8930,9 @@ class MyProcessor: public Processor { compilationHandlers->dispose(allocator); - s->handleSegFault(0); + signals.handleSegFault(0); + signals.handleDivideByZero(0); + signals.setCrashDumpDirectory(0); allocator->free(this, sizeof(*this)); } @@ -9116,12 +9124,10 @@ class MyProcessor: public Processor { #endif segFaultHandler.m = t->m; - expect(t, t->m->system->success - (t->m->system->handleSegFault(&segFaultHandler))); + expect(t, signals.handleSegFault(&segFaultHandler)); divideByZeroHandler.m = t->m; - expect(t, t->m->system->success - (t->m->system->handleDivideByZero(÷ByZeroHandler))); + expect(t, signals.handleDivideByZero(÷ByZeroHandler)); } virtual void callWithCurrentContinuation(Thread* t, object receiver) { @@ -9173,6 +9179,7 @@ class MyProcessor: public Processor { } System* s; + SignalRegistrar signals; Allocator* allocator; object roots; BootImage* bootImage; @@ -10285,11 +10292,13 @@ codeAllocator(MyThread* t) namespace vm { -Processor* -makeProcessor(System* system, Allocator* allocator, bool useNativeFeatures) +Processor* makeProcessor(System* system, + Allocator* allocator, + const char* crashDumpDirectory, + bool useNativeFeatures) { return new (allocator->allocate(sizeof(local::MyProcessor))) - local::MyProcessor(system, allocator, useNativeFeatures); + local::MyProcessor(system, allocator, crashDumpDirectory, useNativeFeatures); } } // namespace vm diff --git a/src/interpret.cpp b/src/interpret.cpp index 91627ab2ab..7ab3ce98a7 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -10,6 +10,7 @@ #include "avian/common.h" #include +#include #include "avian/constants.h" #include "avian/machine.h" #include "avian/processor.h" @@ -20,6 +21,7 @@ #include using namespace vm; +using namespace avian::system; namespace local { @@ -2959,9 +2961,11 @@ invoke(Thread* t, object method) class MyProcessor: public Processor { public: - MyProcessor(System* s, Allocator* allocator): - s(s), allocator(allocator) - { } + MyProcessor(System* s, Allocator* allocator, const char* crashDumpDirectory) + : s(s), allocator(allocator) + { + signals.setCrashDumpDirectory(crashDumpDirectory); + } virtual vm::Thread* makeThread(Machine* m, object javaThread, vm::Thread* parent) @@ -3260,21 +3264,25 @@ class MyProcessor: public Processor { virtual void dispose() { allocator->free(this, sizeof(*this)); + signals.setCrashDumpDirectory(0); } System* s; Allocator* allocator; + SignalRegistrar signals; }; } // namespace namespace vm { -Processor* -makeProcessor(System* system, Allocator* allocator, bool) +Processor* makeProcessor(System* system, + Allocator* allocator, + const char* crashDumpDirectory, + bool) { return new (allocator->allocate(sizeof(local::MyProcessor))) - local::MyProcessor(system, allocator); + local::MyProcessor(system, allocator, crashDumpDirectory); } } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 66f2f2ef5c..1dcd9e6769 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3878,7 +3878,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) if (classpath == 0) classpath = "."; - System* s = makeSystem(crashDumpDirectory); + System* s = makeSystem(); Heap* h = makeHeap(s, heapLimit); Classpath* c = makeClasspath(s, h, javaHome, embedPrefix); @@ -3913,7 +3913,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) Finder* af = makeFinder(s, h, classpath, bootLibrary); if(bootLibrary) free(bootLibrary); - Processor* p = makeProcessor(s, h, true); + Processor* p = makeProcessor(s, h, crashDumpDirectory, true); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); diff --git a/src/main.cpp b/src/main.cpp index 20d4685fce..b1a1be458d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,7 +59,7 @@ mainClass(const char* jar) { using namespace vm; - System* system = makeSystem(0); + System* system = makeSystem(); class MyAllocator: public Allocator { public: diff --git a/src/system/posix.cpp b/src/system/posix.cpp index 9167fb8124..2d3825325b 100644 --- a/src/system/posix.cpp +++ b/src/system/posix.cpp @@ -78,29 +78,14 @@ class MutexResource { const int InvalidSignal = -1; const int VisitSignal = SIGUSR1; const unsigned VisitSignalIndex = 0; -const int SegFaultSignal = SIGSEGV; -const unsigned SegFaultSignalIndex = 1; const int InterruptSignal = SIGUSR2; -const unsigned InterruptSignalIndex = 2; -#ifdef __APPLE__ -const int AltSegFaultSignal = SIGBUS; -#else -const int AltSegFaultSignal = InvalidSignal; -#endif -const unsigned AltSegFaultSignalIndex = 3; +const unsigned InterruptSignalIndex = 1; const int PipeSignal = SIGPIPE; -const unsigned PipeSignalIndex = 4; -const int DivideByZeroSignal = SIGFPE; -const unsigned DivideByZeroSignalIndex = 5; +const unsigned PipeSignalIndex = 2; -const int signals[] = { VisitSignal, - SegFaultSignal, - InterruptSignal, - AltSegFaultSignal, - PipeSignal, - DivideByZeroSignal }; +const int signals[] = {VisitSignal, InterruptSignal, PipeSignal}; -const unsigned SignalCount = 6; +const unsigned SignalCount = 3; class MySystem; MySystem* system; @@ -123,7 +108,7 @@ pathOfExecutable(System* s, const char** retBuf, unsigned* size) CFURLRef url = CFBundleCopyExecutableURL(bundle); CFStringRef path = CFURLCopyPath(url); path = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, - path, CFSTR("")); + path, CFSTR("")); CFIndex pathSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path); char* buffer = reinterpret_cast(allocate(s, pathSize)); if (CFStringGetFileSystemRepresentation(path, buffer, pathSize)) { @@ -606,32 +591,27 @@ class MySystem: public System { expect(this, system == 0); system = this; - memset(handlers, 0, sizeof(handlers)); - - registerHandler(&nullHandler, InterruptSignalIndex); - registerHandler(&nullHandler, PipeSignalIndex); - registerHandler(&nullHandler, VisitSignalIndex); + expect(this, registerHandler(InterruptSignalIndex)); + expect(this, registerHandler(VisitSignalIndex)); + expect(this, registerHandler(PipeSignalIndex)); expect(this, make(&visitLock) == 0); } - int registerHandler(System::SignalHandler* handler, int index) { - if (handler) { - handlers[index] = handler; + // Returns true on success, false on failure + bool unregisterHandler(int index) { + return sigaction(signals[index], oldHandlers + index, 0) == 0; + } - struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = handleSignal; - - return sigaction(signals[index], &sa, oldHandlers + index); - } else if (handlers[index]) { - handlers[index] = 0; - return sigaction(signals[index], oldHandlers + index, 0); - } else { - return 1; - } + // Returns true on success, false on failure + bool registerHandler(int index) { + struct sigaction sa; + memset(&sa, 0, sizeof(struct sigaction)); + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handleSignal; + + return sigaction(signals[index], &sa, oldHandlers + index) == 0; } virtual void* tryAllocate(unsigned sizeInBytes) { @@ -701,18 +681,6 @@ class MySystem: public System { return 0; } - virtual Status handleSegFault(SignalHandler* handler) { - Status s = registerHandler(handler, SegFaultSignalIndex); - if (s == 0 and AltSegFaultSignal != InvalidSignal) { - return registerHandler(handler, AltSegFaultSignalIndex); - } - return s; - } - - virtual Status handleDivideByZero(SignalHandler* handler) { - return registerHandler(handler, DivideByZeroSignalIndex); - } - virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { @@ -937,19 +905,14 @@ class MySystem: public System { virtual void dispose() { visitLock->dispose(); - registerHandler(0, InterruptSignalIndex); - registerHandler(0, VisitSignalIndex); - registerHandler(0, PipeSignalIndex); + expect(this, unregisterHandler(InterruptSignalIndex)); + expect(this, unregisterHandler(VisitSignalIndex)); + expect(this, unregisterHandler(PipeSignalIndex)); system = 0; ::free(this); } - class NullSignalHandler: public SignalHandler { - virtual bool handleSignal(void**, void**, void**, void**) { return false; } - } nullHandler; - - SignalHandler* handlers[SignalCount]; struct sigaction oldHandlers[SignalCount]; ThreadVisitor* threadVisitor; @@ -957,27 +920,16 @@ class MySystem: public System { System::Monitor* visitLock; }; -void -handleSignal(int signal, siginfo_t*, void* context) +void handleSignal(int signal, siginfo_t*, void* context) { ucontext_t* c = static_cast(context); void* ip = reinterpret_cast(IP_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); - void* thread = reinterpret_cast(THREAD_REGISTER(c)); void* link = reinterpret_cast(LINK_REGISTER(c)); -#ifdef FRAME_REGISTER - void* frame = reinterpret_cast(FRAME_REGISTER(c)); -#else - void* frame = 0; -#endif - - unsigned index; switch (signal) { case VisitSignal: { - index = VisitSignalIndex; - system->threadVisitor->visit(ip, stack, link); System::Thread* t = system->visitTarget; @@ -987,57 +939,6 @@ handleSignal(int signal, siginfo_t*, void* context) system->visitLock->notifyAll(t); } break; - case SegFaultSignal: - case AltSegFaultSignal: - case DivideByZeroSignal: { - switch (signal) { - case SegFaultSignal: - index = SegFaultSignalIndex; - break; - - case AltSegFaultSignal: - index = AltSegFaultSignalIndex; - break; - - case DivideByZeroSignal: - index = DivideByZeroSignalIndex; - break; - - default: - abort(); - } - - bool jump = system->handlers[index]->handleSignal - (&ip, &frame, &stack, &thread); - - if (jump) { - // I'd like to use setcontext here (and get rid of the - // sigprocmask call), but it doesn't work on my Linux x86_64 - // system, and I can't tell from the documentation if it's even - // supposed to work. - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, signal); - pthread_sigmask(SIG_UNBLOCK, &set, 0); - - vmJump(ip, frame, stack, thread, 0, 0); - } - } break; - - case InterruptSignal: { - index = InterruptSignalIndex; - } break; - - case PipeSignal: { - index = PipeSignalIndex; - } break; - - default: abort(); - } - - switch (signal) { - case VisitSignal: case InterruptSignal: case PipeSignal: break; @@ -1052,7 +953,7 @@ handleSignal(int signal, siginfo_t*, void* context) namespace vm { AVIAN_EXPORT System* -makeSystem(const char*) +makeSystem() { return new (malloc(sizeof(MySystem))) MySystem(); } diff --git a/src/system/posix/signal.cpp b/src/system/posix/signal.cpp new file mode 100644 index 0000000000..54e117e365 --- /dev/null +++ b/src/system/posix/signal.cpp @@ -0,0 +1,207 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include "signal.h" +#include "sys/types.h" +#ifdef __APPLE__ +#include "CoreFoundation/CoreFoundation.h" +#include "sys/ucontext.h" +#undef assert +#elif defined(__ANDROID__) +#include /* for sigcontext */ +#include /* for stack_t */ +typedef struct ucontext { + unsigned long uc_flags; + struct ucontext* uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + unsigned long uc_sigmask; +} ucontext_t; +#else +#if defined __FreeBSD__ +#include "limits.h" +#endif +#include "ucontext.h" +#endif + +#include "avian/arch.h" +#include +#include + +namespace avian { +namespace system { + +namespace posix { + + +const int InvalidSignal = -1; +const int SegFaultSignal = SIGSEGV; +const unsigned SegFaultSignalIndex = 0; +#ifdef __APPLE__ +const int AltSegFaultSignal = SIGBUS; +#else +const int AltSegFaultSignal = InvalidSignal; +#endif +const unsigned AltSegFaultSignalIndex = 1; +const int DivideByZeroSignal = SIGFPE; +const unsigned DivideByZeroSignalIndex = 2; + +const int signals[] + = {SegFaultSignal, AltSegFaultSignal, DivideByZeroSignal}; + +const unsigned SignalCount = 3; + +} + +struct SignalRegistrar::Data { + Handler* handlers[posix::SignalCount]; + struct sigaction oldHandlers[posix::SignalCount]; + + bool registerHandler(Handler* handler, int index); + + Data() + { + if(instance) { + abort(); + } + + instance = this; + } + + ~Data() + { + instance = 0; + } + + static SignalRegistrar::Data* instance; +}; + +SignalRegistrar::Data* SignalRegistrar::Data::instance = 0; + +namespace posix { + +using namespace vm; + +void handleSignal(int signal, siginfo_t*, void* context) +{ + ucontext_t* c = static_cast(context); + + void* ip = reinterpret_cast(IP_REGISTER(c)); + void* stack = reinterpret_cast(STACK_REGISTER(c)); + void* thread = reinterpret_cast(THREAD_REGISTER(c)); +#ifdef FRAME_REGISTER + void* frame = reinterpret_cast(FRAME_REGISTER(c)); +#else + void* frame = 0; +#endif + + unsigned index; + + switch (signal) { + case SegFaultSignal: + case AltSegFaultSignal: + case DivideByZeroSignal: { + switch (signal) { + case SegFaultSignal: + index = SegFaultSignalIndex; + break; + + case AltSegFaultSignal: + index = AltSegFaultSignalIndex; + break; + + case DivideByZeroSignal: + index = DivideByZeroSignalIndex; + break; + + default: + abort(); + } + + bool jump + = SignalRegistrar::Data::instance->handlers[index]->handleSignal(&ip, &frame, &stack, &thread); + + if (jump) { + // I'd like to use setcontext here (and get rid of the + // sigprocmask call), but it doesn't work on my Linux x86_64 + // system, and I can't tell from the documentation if it's even + // supposed to work. + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signal); + pthread_sigmask(SIG_UNBLOCK, &set, 0); + + vmJump(ip, frame, stack, thread, 0, 0); + } + } break; + + default: + abort(); + } +} + +} // namespace posix + +SignalRegistrar::SignalRegistrar() +{ + data = new (malloc(sizeof(Data))) Data(); +} + +SignalRegistrar::~SignalRegistrar() +{ + data->~Data(); + free(data); +} + +bool SignalRegistrar::Data::registerHandler(Handler* handler, int index) +{ + if (handler) { + handlers[index] = handler; + + struct sigaction sa; + memset(&sa, 0, sizeof(struct sigaction)); + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = posix::handleSignal; + + return sigaction(posix::signals[index], &sa, oldHandlers + index) == 0; + } else if (handlers[index]) { + handlers[index] = 0; + return sigaction(posix::signals[index], oldHandlers + index, 0) == 0; + } else { + return false; + } +} + +bool SignalRegistrar::handleSegFault(Handler* handler) +{ + if(!data->registerHandler(handler, posix::SegFaultSignalIndex)) { + return false; + } + if (posix::AltSegFaultSignal != posix::InvalidSignal) { + return data->registerHandler(handler, posix::AltSegFaultSignalIndex); + } else { + return true; + } +} + +bool SignalRegistrar::handleDivideByZero(Handler* handler) +{ + return data->registerHandler(handler, posix::DivideByZeroSignalIndex); +} + +void SignalRegistrar::setCrashDumpDirectory(const char*) +{ + // Do nothing, not currently supported on posix +} + +} // namespace system +} // namespace avian diff --git a/src/system/windows.cpp b/src/system/windows.cpp index 3f3c94e934..53280049c9 100644 --- a/src/system/windows.cpp +++ b/src/system/windows.cpp @@ -10,7 +10,6 @@ #include "sys/stat.h" #include "windows.h" -#include "sys/timeb.h" #ifdef _MSC_VER # define S_ISREG(x) ((x) & _S_IFREG) @@ -115,11 +114,6 @@ class MutexResource { HANDLE m; }; -const unsigned SegFaultIndex = 0; -const unsigned DivideByZeroIndex = 1; - -const unsigned HandlerCount = 2; - class MySystem; MySystem* system; @@ -626,68 +620,15 @@ class MySystem: public System { System::Library* next_; }; - MySystem(const char* crashDumpDirectory): -#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - oldHandler(0), -#endif - crashDumpDirectory(crashDumpDirectory) + MySystem() { expect(this, system == 0); system = this; - memset(handlers, 0, sizeof(handlers)); - mutex = CreateMutex(0, false, 0); assert(this, mutex); } - bool findHandler() { - for (unsigned i = 0; i < HandlerCount; ++i) { - if (handlers[i]) return true; - } - return false; - } - - int registerHandler(System::SignalHandler* handler, int index) { - if (handler) { - handlers[index] = handler; - -#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - if (oldHandler == 0) { -# ifdef ARCH_x86_32 - oldHandler = SetUnhandledExceptionFilter(handleException); -# elif defined ARCH_x86_64 - AddVectoredExceptionHandler(1, handleException); - oldHandler = reinterpret_cast(1); -# endif - } -#else - #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") -#endif - - return 0; - } else if (handlers[index]) { - handlers[index] = 0; - - if (not findHandler()) { -#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -# ifdef ARCH_x86_32 - SetUnhandledExceptionFilter(oldHandler); - oldHandler = 0; -# elif defined ARCH_x86_64 - // do nothing, handlers are never "unregistered" anyway -# endif -#else - #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") -#endif - } - - return 0; - } else { - return 1; - } - } - virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } @@ -746,14 +687,6 @@ class MySystem: public System { return 0; } - virtual Status handleSegFault(SignalHandler* handler) { - return registerHandler(handler, SegFaultIndex); - } - - virtual Status handleDivideByZero(SignalHandler* handler) { - return registerHandler(handler, DivideByZeroIndex); - } - virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { @@ -1020,139 +953,16 @@ class MySystem: public System { } HANDLE mutex; - SignalHandler* handlers[HandlerCount]; -#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; -#endif - const char* crashDumpDirectory; }; -#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - -#pragma pack(push,4) -struct MINIDUMP_EXCEPTION_INFORMATION { - DWORD thread; - LPEXCEPTION_POINTERS exception; - BOOL exceptionInCurrentAddressSpace; -}; -#pragma pack(pop) - -struct MINIDUMP_USER_STREAM_INFORMATION; -struct MINIDUMP_CALLBACK_INFORMATION; - -enum MINIDUMP_TYPE { - MiniDumpNormal = 0, - MiniDumpWithFullMemory = 2 -}; - -typedef BOOL (*MiniDumpWriteDumpType) -(HANDLE processHandle, - DWORD processId, - HANDLE file, - MINIDUMP_TYPE type, - const MINIDUMP_EXCEPTION_INFORMATION* exception, - const MINIDUMP_USER_STREAM_INFORMATION* userStream, - const MINIDUMP_CALLBACK_INFORMATION* callback); - -void -dump(LPEXCEPTION_POINTERS e, const char* directory) -{ - HINSTANCE dbghelp = LoadLibrary("dbghelp.dll"); - - if (dbghelp) { - MiniDumpWriteDumpType MiniDumpWriteDump = reinterpret_cast - (GetProcAddress(dbghelp, "MiniDumpWriteDump")); - - if (MiniDumpWriteDump) { - char name[MAX_PATH]; - _timeb tb; - FTIME(&tb); - vm::snprintf(name, MAX_PATH, "%s\\crash-%" LLD ".mdmp", directory, - (static_cast(tb.time) * 1000) - + static_cast(tb.millitm)); - - HANDLE file = CreateFile - (name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0); - - if (file != INVALID_HANDLE_VALUE) { - MINIDUMP_EXCEPTION_INFORMATION exception - = { GetCurrentThreadId(), e, true }; - - MiniDumpWriteDump - (GetCurrentProcess(), - GetCurrentProcessId(), - file, - MiniDumpWithFullMemory, - &exception, - 0, - 0); - - CloseHandle(file); - } - } - - FreeLibrary(dbghelp); - } -} - -LONG CALLBACK -handleException(LPEXCEPTION_POINTERS e) -{ - System::SignalHandler* handler = 0; - if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - handler = system->handlers[SegFaultIndex]; - } else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) - { - handler = system->handlers[DivideByZeroIndex]; - } - - if (handler) { -#ifdef ARCH_x86_32 - void* ip = reinterpret_cast(e->ContextRecord->Eip); - void* base = reinterpret_cast(e->ContextRecord->Ebp); - void* stack = reinterpret_cast(e->ContextRecord->Esp); - void* thread = reinterpret_cast(e->ContextRecord->Ebx); -#elif defined ARCH_x86_64 - void* ip = reinterpret_cast(e->ContextRecord->Rip); - void* base = reinterpret_cast(e->ContextRecord->Rbp); - void* stack = reinterpret_cast(e->ContextRecord->Rsp); - void* thread = reinterpret_cast(e->ContextRecord->Rbx); -#endif - - bool jump = handler->handleSignal(&ip, &base, &stack, &thread); - -#ifdef ARCH_x86_32 - e->ContextRecord->Eip = reinterpret_cast(ip); - e->ContextRecord->Ebp = reinterpret_cast(base); - e->ContextRecord->Esp = reinterpret_cast(stack); - e->ContextRecord->Ebx = reinterpret_cast(thread); -#elif defined ARCH_x86_64 - e->ContextRecord->Rip = reinterpret_cast(ip); - e->ContextRecord->Rbp = reinterpret_cast(base); - e->ContextRecord->Rsp = reinterpret_cast(stack); - e->ContextRecord->Rbx = reinterpret_cast(thread); -#endif - - if (jump) { - return EXCEPTION_CONTINUE_EXECUTION; - } else if (system->crashDumpDirectory) { - dump(e, system->crashDumpDirectory); - } - } - - return EXCEPTION_CONTINUE_SEARCH; -} - -#endif - } // namespace namespace vm { AVIAN_EXPORT System* -makeSystem(const char* crashDumpDirectory) +makeSystem() { - return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory); + return new (malloc(sizeof(MySystem))) MySystem(); } } // namespace vm diff --git a/src/system/windows/signal.cpp b/src/system/windows/signal.cpp new file mode 100644 index 0000000000..343788f371 --- /dev/null +++ b/src/system/windows/signal.cpp @@ -0,0 +1,279 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include "windows.h" +#include "sys/timeb.h" + +#ifdef _MSC_VER +#define FTIME _ftime_s +#else +#define FTIME _ftime +#endif + +#ifndef WINAPI_FAMILY + +#ifndef WINAPI_PARTITION_DESKTOP +#define WINAPI_PARTITION_DESKTOP 1 +#endif + +#ifndef WINAPI_FAMILY_PARTITION +#define WINAPI_FAMILY_PARTITION(x) (x) +#endif + +#endif + +#include +#include + +namespace avian { +namespace system { + +namespace windows { +const unsigned SegFaultIndex = 0; +const unsigned DivideByZeroIndex = 1; + +const unsigned HandlerCount = 2; + +} // namespace windows + +struct SignalRegistrar::Data { + Handler* handlers[windows::HandlerCount]; + const char* crashDumpDirectory; + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; +#endif + + Data() : crashDumpDirectory(0), +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + oldHandler(0) +#endif + { + if (instance) { + abort(); + } + instance = this; + memset(handlers, 0, sizeof(handlers)); + } + + ~Data() + { + instance = 0; + } + + bool registerHandler(Handler* handler, int index); + + bool findHandler() { + for (unsigned i = 0; i < windows::HandlerCount; ++i) { + if (handlers[i]) return true; + } + return false; + } + + static SignalRegistrar::Data* instance; +}; + +SignalRegistrar::Data* SignalRegistrar::Data::instance = 0; + +namespace windows { + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + +#pragma pack(push, 4) +struct MINIDUMP_EXCEPTION_INFORMATION { + DWORD thread; + LPEXCEPTION_POINTERS exception; + BOOL exceptionInCurrentAddressSpace; +}; +#pragma pack(pop) + +struct MINIDUMP_USER_STREAM_INFORMATION; +struct MINIDUMP_CALLBACK_INFORMATION; + +enum MINIDUMP_TYPE { + MiniDumpNormal = 0, + MiniDumpWithFullMemory = 2 +}; + +typedef BOOL (*MiniDumpWriteDumpType)(HANDLE processHandle, + DWORD processId, + HANDLE file, + MINIDUMP_TYPE type, + const MINIDUMP_EXCEPTION_INFORMATION + * exception, + const MINIDUMP_USER_STREAM_INFORMATION + * userStream, + const MINIDUMP_CALLBACK_INFORMATION + * callback); + +#endif + +void dump(LPEXCEPTION_POINTERS e, const char* directory) +{ + HINSTANCE dbghelp = LoadLibrary("dbghelp.dll"); + + if (dbghelp) { + MiniDumpWriteDumpType MiniDumpWriteDump = reinterpret_cast + (GetProcAddress(dbghelp, "MiniDumpWriteDump")); + + if (MiniDumpWriteDump) { + char name[MAX_PATH]; + _timeb tb; + FTIME(&tb); + vm::snprintf(name, + MAX_PATH, + "%s\\crash-%" LLD ".mdmp", + directory, + (static_cast(tb.time) * 1000) + static_cast + (tb.millitm)); + + HANDLE file + = CreateFile(name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0); + + if (file != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION exception + = {GetCurrentThreadId(), e, true}; + + MiniDumpWriteDump(GetCurrentProcess(), + GetCurrentProcessId(), + file, + MiniDumpWithFullMemory, + &exception, + 0, + 0); + + CloseHandle(file); + } + } + + FreeLibrary(dbghelp); + } +} + +LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) +{ + SignalRegistrar::Handler* handler = 0; + if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + handler = SignalRegistrar::Data::instance->handlers[SegFaultIndex]; + } else if (e->ExceptionRecord->ExceptionCode + == EXCEPTION_INT_DIVIDE_BY_ZERO) { + handler = SignalRegistrar::Data::instance->handlers[DivideByZeroIndex]; + } + + if (handler) { +#ifdef ARCH_x86_32 + void* ip = reinterpret_cast(e->ContextRecord->Eip); + void* base = reinterpret_cast(e->ContextRecord->Ebp); + void* stack = reinterpret_cast(e->ContextRecord->Esp); + void* thread = reinterpret_cast(e->ContextRecord->Ebx); +#elif defined ARCH_x86_64 + void* ip = reinterpret_cast(e->ContextRecord->Rip); + void* base = reinterpret_cast(e->ContextRecord->Rbp); + void* stack = reinterpret_cast(e->ContextRecord->Rsp); + void* thread = reinterpret_cast(e->ContextRecord->Rbx); +#endif + + bool jump = handler->handleSignal(&ip, &base, &stack, &thread); + +#ifdef ARCH_x86_32 + e->ContextRecord->Eip = reinterpret_cast(ip); + e->ContextRecord->Ebp = reinterpret_cast(base); + e->ContextRecord->Esp = reinterpret_cast(stack); + e->ContextRecord->Ebx = reinterpret_cast(thread); +#elif defined ARCH_x86_64 + e->ContextRecord->Rip = reinterpret_cast(ip); + e->ContextRecord->Rbp = reinterpret_cast(base); + e->ContextRecord->Rsp = reinterpret_cast(stack); + e->ContextRecord->Rbx = reinterpret_cast(thread); +#endif + + if (jump) { + return EXCEPTION_CONTINUE_EXECUTION; + } else if (SignalRegistrar::Data::instance->crashDumpDirectory) { + dump(e, SignalRegistrar::Data::instance->crashDumpDirectory); + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +} // namespace windows + +SignalRegistrar::SignalRegistrar() +{ + data = new (malloc(sizeof(Data))) Data(); +} + +SignalRegistrar::~SignalRegistrar() +{ + data->~Data(); + free(data); +} + +bool SignalRegistrar::Data::registerHandler(Handler* handler, int index) +{ + if (handler) { + handlers[index] = handler; + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + if (oldHandler == 0) { +#ifdef ARCH_x86_32 + oldHandler = SetUnhandledExceptionFilter(windows::handleException); +#elif defined ARCH_x86_64 + AddVectoredExceptionHandler(1, windows::handleException); + oldHandler = reinterpret_cast(1); +#endif + } +#else +#pragma message( \ + "TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") +#endif + + return true; + } else if (handlers[index]) { + handlers[index] = 0; + + if (not findHandler()) { +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#ifdef ARCH_x86_32 + SetUnhandledExceptionFilter(oldHandler); + oldHandler = 0; +#elif defined ARCH_x86_64 +// do nothing, handlers are never "unregistered" anyway +#endif +#else +#pragma message( \ + "TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") +#endif + } + + return true; + } else { + return false; + } +} + +bool SignalRegistrar::handleSegFault(Handler* handler) +{ + return data->registerHandler(handler, windows::SegFaultIndex); +} + +bool SignalRegistrar::handleDivideByZero(Handler* handler) +{ + return data->registerHandler(handler, windows::DivideByZeroIndex); +} + +void SignalRegistrar::setCrashDumpDirectory(const char* crashDumpDirectory) +{ + data->crashDumpDirectory = crashDumpDirectory; +} + +} // namespace system +} // namespace avian diff --git a/src/tools/audit-codegen/main.cpp b/src/tools/audit-codegen/main.cpp index 12c05ede3b..270d0c6348 100644 --- a/src/tools/audit-codegen/main.cpp +++ b/src/tools/audit-codegen/main.cpp @@ -34,7 +34,7 @@ public: Architecture* arch; BasicEnv(): - s(makeSystem(0)), + s(makeSystem()), heap(makeHeap(s, 32 * 1024)), arch(makeArchitectureNative(s, true)) { diff --git a/src/tools/bootimage-generator/main.cpp b/src/tools/bootimage-generator/main.cpp index 3442877626..3d7cf47788 100644 --- a/src/tools/bootimage-generator/main.cpp +++ b/src/tools/bootimage-generator/main.cpp @@ -1899,11 +1899,11 @@ main(int ac, const char** av) Arguments args(ac, av); // args.dump(); - System* s = makeSystem(0); + System* s = makeSystem(); Heap* h = makeHeap(s, HeapCapacity * 2); Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); Finder* f = makeFinder(s, h, args.classpath, 0); - Processor* p = makeProcessor(s, h, false); + Processor* p = makeProcessor(s, h, 0, false); // todo: currently, the compiler cannot compile code with jumps or // calls spanning more than the maximum size of an immediate value diff --git a/src/tools/type-generator/main.cpp b/src/tools/type-generator/main.cpp index 8171bd560b..a08a5be3ff 100644 --- a/src/tools/type-generator/main.cpp +++ b/src/tools/type-generator/main.cpp @@ -1941,7 +1941,7 @@ main(int ac, char** av) local::usageAndExit(av[0]); } - System* system = makeSystem(0); + System* system = makeSystem(); class MyAllocator: public Allocator { public: diff --git a/unittest/codegen/assembler-test.cpp b/unittest/codegen/assembler-test.cpp index f5176b7388..8908fb3a67 100644 --- a/unittest/codegen/assembler-test.cpp +++ b/unittest/codegen/assembler-test.cpp @@ -33,7 +33,7 @@ public: Architecture* arch; BasicEnv(): - s(makeSystem(0)), + s(makeSystem()), heap(makeHeap(s, 32 * 1024)), arch(makeArchitectureNative(s, true)) {