break out signal handling from System

This commit is contained in:
Joshua Warner
2014-02-21 17:06:17 -07:00
committed by Joshua Warner
parent 5ffdfecdc2
commit 730dade53e
17 changed files with 649 additions and 370 deletions

View File

@ -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

View File

@ -98,12 +98,6 @@ class System : public avian::util::Aborter {
virtual void disposeAll() = 0; virtual void disposeAll() = 0;
}; };
class SignalHandler {
public:
virtual bool handleSignal(void** ip, void** frame, void** stack,
void** thread) = 0;
};
class MonitorResource { class MonitorResource {
public: public:
MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) { 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(Mutex**) = 0;
virtual Status make(Monitor**) = 0; virtual Status make(Monitor**) = 0;
virtual Status make(Local**) = 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, virtual Status visit(Thread* thread, Thread* target,
ThreadVisitor* visitor) = 0; ThreadVisitor* visitor) = 0;
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
@ -193,7 +186,7 @@ sysAbort(System* s)
// #endif // not NDEBUG // #endif // not NDEBUG
AVIAN_EXPORT System* AVIAN_EXPORT System*
makeSystem(const char* crashDumpDirectory); makeSystem();
} // namespace vm } // namespace vm

View File

@ -1109,6 +1109,7 @@ vm-depends := $(generated-code) \
vm-sources = \ vm-sources = \
$(src)/system/$(system).cpp \ $(src)/system/$(system).cpp \
$(src)/system/$(system)/signal.cpp \
$(src)/finder.cpp \ $(src)/finder.cpp \
$(src)/machine.cpp \ $(src)/machine.cpp \
$(src)/util.cpp \ $(src)/util.cpp \
@ -1240,6 +1241,7 @@ generator-depends := $(wildcard $(src)/*.h)
generator-sources = \ generator-sources = \
$(src)/tools/type-generator/main.cpp \ $(src)/tools/type-generator/main.cpp \
$(src)/system/$(build-system).cpp \ $(src)/system/$(build-system).cpp \
$(src)/system/$(build-system)/signal.cpp \
$(src)/finder.cpp $(src)/finder.cpp
ifneq ($(lzma),) ifneq ($(lzma),)

View File

@ -14,6 +14,7 @@
#include "avian/common.h" #include "avian/common.h"
#include "java-common.h" #include "java-common.h"
#include <avian/system/system.h> #include <avian/system/system.h>
#include <avian/system/signal.h>
#include <avian/heap/heap.h> #include <avian/heap/heap.h>
#include "avian/finder.h" #include "avian/finder.h"
#include "avian/processor.h" #include "avian/processor.h"

View File

@ -208,8 +208,10 @@ class Processor {
} }
}; };
Processor* Processor* makeProcessor(System* system,
makeProcessor(System* system, Allocator* allocator, bool useNativeFeatures); Allocator* allocator,
const char* crashDumpDirectory,
bool useNativeFeatures);
} // namespace vm } // namespace vm

View File

@ -43,6 +43,7 @@ vmJumpAndInvoke(void* thread, void* function, void* stack,
unsigned frameSize); unsigned frameSize);
using namespace avian::codegen; using namespace avian::codegen;
using namespace avian::system;
namespace { namespace {
@ -8366,7 +8367,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
return r; return r;
} }
class SignalHandler: public System::SignalHandler { class SignalHandler: public SignalRegistrar::Handler {
public: public:
SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize):
m(0), type(type), root(root), fixedSize(fixedSize) { } m(0), type(type), root(root), fixedSize(fixedSize) { }
@ -8501,24 +8502,27 @@ class MyProcessor: public Processor {
Thunk table; Thunk table;
}; };
MyProcessor(System* s, Allocator* allocator, bool useNativeFeatures): MyProcessor(System* s,
s(s), Allocator* allocator,
allocator(allocator), const char* crashDumpDirectory,
roots(0), bool useNativeFeatures)
bootImage(0), : s(s),
heapImage(0), allocator(allocator),
codeImage(0), roots(0),
codeImageSize(0), bootImage(0),
segFaultHandler(Machine::NullPointerExceptionType, heapImage(0),
Machine::NullPointerException, codeImage(0),
FixedSizeOfNullPointerException), codeImageSize(0),
divideByZeroHandler(Machine::ArithmeticExceptionType, segFaultHandler(Machine::NullPointerExceptionType,
Machine::ArithmeticException, Machine::NullPointerException,
FixedSizeOfArithmeticException), FixedSizeOfNullPointerException),
codeAllocator(s, 0, 0), divideByZeroHandler(Machine::ArithmeticExceptionType,
callTableSize(0), Machine::ArithmeticException,
useNativeFeatures(useNativeFeatures), FixedSizeOfArithmeticException),
compilationHandlers(0) codeAllocator(s, 0, 0),
callTableSize(0),
useNativeFeatures(useNativeFeatures),
compilationHandlers(0)
{ {
thunkTable[compileMethodIndex] = voidPointer(local::compileMethod); thunkTable[compileMethodIndex] = voidPointer(local::compileMethod);
thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod); thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod);
@ -8540,6 +8544,8 @@ class MyProcessor: public Processor {
// table. // table.
thunkTable[dummyIndex] = reinterpret_cast<void*> thunkTable[dummyIndex] = reinterpret_cast<void*>
(static_cast<uintptr_t>(UINT64_C(0x5555555555555555))); (static_cast<uintptr_t>(UINT64_C(0x5555555555555555)));
signals.setCrashDumpDirectory(crashDumpDirectory);
} }
virtual Thread* virtual Thread*
@ -8924,7 +8930,9 @@ class MyProcessor: public Processor {
compilationHandlers->dispose(allocator); compilationHandlers->dispose(allocator);
s->handleSegFault(0); signals.handleSegFault(0);
signals.handleDivideByZero(0);
signals.setCrashDumpDirectory(0);
allocator->free(this, sizeof(*this)); allocator->free(this, sizeof(*this));
} }
@ -9116,12 +9124,10 @@ class MyProcessor: public Processor {
#endif #endif
segFaultHandler.m = t->m; segFaultHandler.m = t->m;
expect(t, t->m->system->success expect(t, signals.handleSegFault(&segFaultHandler));
(t->m->system->handleSegFault(&segFaultHandler)));
divideByZeroHandler.m = t->m; divideByZeroHandler.m = t->m;
expect(t, t->m->system->success expect(t, signals.handleDivideByZero(&divideByZeroHandler));
(t->m->system->handleDivideByZero(&divideByZeroHandler)));
} }
virtual void callWithCurrentContinuation(Thread* t, object receiver) { virtual void callWithCurrentContinuation(Thread* t, object receiver) {
@ -9173,6 +9179,7 @@ class MyProcessor: public Processor {
} }
System* s; System* s;
SignalRegistrar signals;
Allocator* allocator; Allocator* allocator;
object roots; object roots;
BootImage* bootImage; BootImage* bootImage;
@ -10285,11 +10292,13 @@ codeAllocator(MyThread* t)
namespace vm { namespace vm {
Processor* Processor* makeProcessor(System* system,
makeProcessor(System* system, Allocator* allocator, bool useNativeFeatures) Allocator* allocator,
const char* crashDumpDirectory,
bool useNativeFeatures)
{ {
return new (allocator->allocate(sizeof(local::MyProcessor))) return new (allocator->allocate(sizeof(local::MyProcessor)))
local::MyProcessor(system, allocator, useNativeFeatures); local::MyProcessor(system, allocator, crashDumpDirectory, useNativeFeatures);
} }
} // namespace vm } // namespace vm

View File

@ -10,6 +10,7 @@
#include "avian/common.h" #include "avian/common.h"
#include <avian/system/system.h> #include <avian/system/system.h>
#include <avian/system/signal.h>
#include "avian/constants.h" #include "avian/constants.h"
#include "avian/machine.h" #include "avian/machine.h"
#include "avian/processor.h" #include "avian/processor.h"
@ -20,6 +21,7 @@
#include <avian/util/list.h> #include <avian/util/list.h>
using namespace vm; using namespace vm;
using namespace avian::system;
namespace local { namespace local {
@ -2959,9 +2961,11 @@ invoke(Thread* t, object method)
class MyProcessor: public Processor { class MyProcessor: public Processor {
public: public:
MyProcessor(System* s, Allocator* allocator): MyProcessor(System* s, Allocator* allocator, const char* crashDumpDirectory)
s(s), allocator(allocator) : s(s), allocator(allocator)
{ } {
signals.setCrashDumpDirectory(crashDumpDirectory);
}
virtual vm::Thread* virtual vm::Thread*
makeThread(Machine* m, object javaThread, vm::Thread* parent) makeThread(Machine* m, object javaThread, vm::Thread* parent)
@ -3260,21 +3264,25 @@ class MyProcessor: public Processor {
virtual void dispose() { virtual void dispose() {
allocator->free(this, sizeof(*this)); allocator->free(this, sizeof(*this));
signals.setCrashDumpDirectory(0);
} }
System* s; System* s;
Allocator* allocator; Allocator* allocator;
SignalRegistrar signals;
}; };
} // namespace } // namespace
namespace vm { namespace vm {
Processor* Processor* makeProcessor(System* system,
makeProcessor(System* system, Allocator* allocator, bool) Allocator* allocator,
const char* crashDumpDirectory,
bool)
{ {
return new (allocator->allocate(sizeof(local::MyProcessor))) return new (allocator->allocate(sizeof(local::MyProcessor)))
local::MyProcessor(system, allocator); local::MyProcessor(system, allocator, crashDumpDirectory);
} }
} // namespace vm } // namespace vm

View File

@ -3878,7 +3878,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
if (classpath == 0) classpath = "."; if (classpath == 0) classpath = ".";
System* s = makeSystem(crashDumpDirectory); System* s = makeSystem();
Heap* h = makeHeap(s, heapLimit); Heap* h = makeHeap(s, heapLimit);
Classpath* c = makeClasspath(s, h, javaHome, embedPrefix); 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); Finder* af = makeFinder(s, h, classpath, bootLibrary);
if(bootLibrary) if(bootLibrary)
free(bootLibrary); free(bootLibrary);
Processor* p = makeProcessor(s, h, true); Processor* p = makeProcessor(s, h, crashDumpDirectory, true);
const char** properties = static_cast<const char**> const char** properties = static_cast<const char**>
(h->allocate(sizeof(const char*) * propertyCount)); (h->allocate(sizeof(const char*) * propertyCount));

View File

@ -59,7 +59,7 @@ mainClass(const char* jar)
{ {
using namespace vm; using namespace vm;
System* system = makeSystem(0); System* system = makeSystem();
class MyAllocator: public Allocator { class MyAllocator: public Allocator {
public: public:

View File

@ -78,29 +78,14 @@ class MutexResource {
const int InvalidSignal = -1; const int InvalidSignal = -1;
const int VisitSignal = SIGUSR1; const int VisitSignal = SIGUSR1;
const unsigned VisitSignalIndex = 0; const unsigned VisitSignalIndex = 0;
const int SegFaultSignal = SIGSEGV;
const unsigned SegFaultSignalIndex = 1;
const int InterruptSignal = SIGUSR2; const int InterruptSignal = SIGUSR2;
const unsigned InterruptSignalIndex = 2; const unsigned InterruptSignalIndex = 1;
#ifdef __APPLE__
const int AltSegFaultSignal = SIGBUS;
#else
const int AltSegFaultSignal = InvalidSignal;
#endif
const unsigned AltSegFaultSignalIndex = 3;
const int PipeSignal = SIGPIPE; const int PipeSignal = SIGPIPE;
const unsigned PipeSignalIndex = 4; const unsigned PipeSignalIndex = 2;
const int DivideByZeroSignal = SIGFPE;
const unsigned DivideByZeroSignalIndex = 5;
const int signals[] = { VisitSignal, const int signals[] = {VisitSignal, InterruptSignal, PipeSignal};
SegFaultSignal,
InterruptSignal,
AltSegFaultSignal,
PipeSignal,
DivideByZeroSignal };
const unsigned SignalCount = 6; const unsigned SignalCount = 3;
class MySystem; class MySystem;
MySystem* system; MySystem* system;
@ -123,7 +108,7 @@ pathOfExecutable(System* s, const char** retBuf, unsigned* size)
CFURLRef url = CFBundleCopyExecutableURL(bundle); CFURLRef url = CFBundleCopyExecutableURL(bundle);
CFStringRef path = CFURLCopyPath(url); CFStringRef path = CFURLCopyPath(url);
path = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault,
path, CFSTR("")); path, CFSTR(""));
CFIndex pathSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path); CFIndex pathSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path);
char* buffer = reinterpret_cast<char*>(allocate(s, pathSize)); char* buffer = reinterpret_cast<char*>(allocate(s, pathSize));
if (CFStringGetFileSystemRepresentation(path, buffer, pathSize)) { if (CFStringGetFileSystemRepresentation(path, buffer, pathSize)) {
@ -606,32 +591,27 @@ class MySystem: public System {
expect(this, system == 0); expect(this, system == 0);
system = this; system = this;
memset(handlers, 0, sizeof(handlers)); expect(this, registerHandler(InterruptSignalIndex));
expect(this, registerHandler(VisitSignalIndex));
registerHandler(&nullHandler, InterruptSignalIndex); expect(this, registerHandler(PipeSignalIndex));
registerHandler(&nullHandler, PipeSignalIndex);
registerHandler(&nullHandler, VisitSignalIndex);
expect(this, make(&visitLock) == 0); expect(this, make(&visitLock) == 0);
} }
int registerHandler(System::SignalHandler* handler, int index) { // Returns true on success, false on failure
if (handler) { bool unregisterHandler(int index) {
handlers[index] = handler; return sigaction(signals[index], oldHandlers + index, 0) == 0;
}
struct sigaction sa; // Returns true on success, false on failure
memset(&sa, 0, sizeof(struct sigaction)); bool registerHandler(int index) {
sigemptyset(&(sa.sa_mask)); struct sigaction sa;
sa.sa_flags = SA_SIGINFO; memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = handleSignal; sigemptyset(&(sa.sa_mask));
sa.sa_flags = SA_SIGINFO;
return sigaction(signals[index], &sa, oldHandlers + index); sa.sa_sigaction = handleSignal;
} else if (handlers[index]) {
handlers[index] = 0; return sigaction(signals[index], &sa, oldHandlers + index) == 0;
return sigaction(signals[index], oldHandlers + index, 0);
} else {
return 1;
}
} }
virtual void* tryAllocate(unsigned sizeInBytes) { virtual void* tryAllocate(unsigned sizeInBytes) {
@ -701,18 +681,6 @@ class MySystem: public System {
return 0; 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, virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget,
ThreadVisitor* visitor) ThreadVisitor* visitor)
{ {
@ -937,19 +905,14 @@ class MySystem: public System {
virtual void dispose() { virtual void dispose() {
visitLock->dispose(); visitLock->dispose();
registerHandler(0, InterruptSignalIndex); expect(this, unregisterHandler(InterruptSignalIndex));
registerHandler(0, VisitSignalIndex); expect(this, unregisterHandler(VisitSignalIndex));
registerHandler(0, PipeSignalIndex); expect(this, unregisterHandler(PipeSignalIndex));
system = 0; system = 0;
::free(this); ::free(this);
} }
class NullSignalHandler: public SignalHandler {
virtual bool handleSignal(void**, void**, void**, void**) { return false; }
} nullHandler;
SignalHandler* handlers[SignalCount];
struct sigaction oldHandlers[SignalCount]; struct sigaction oldHandlers[SignalCount];
ThreadVisitor* threadVisitor; ThreadVisitor* threadVisitor;
@ -957,27 +920,16 @@ class MySystem: public System {
System::Monitor* visitLock; System::Monitor* visitLock;
}; };
void void handleSignal(int signal, siginfo_t*, void* context)
handleSignal(int signal, siginfo_t*, void* context)
{ {
ucontext_t* c = static_cast<ucontext_t*>(context); ucontext_t* c = static_cast<ucontext_t*>(context);
void* ip = reinterpret_cast<void*>(IP_REGISTER(c)); void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c)); void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
void* link = reinterpret_cast<void*>(LINK_REGISTER(c)); void* link = reinterpret_cast<void*>(LINK_REGISTER(c));
#ifdef FRAME_REGISTER
void* frame = reinterpret_cast<void*>(FRAME_REGISTER(c));
#else
void* frame = 0;
#endif
unsigned index;
switch (signal) { switch (signal) {
case VisitSignal: { case VisitSignal: {
index = VisitSignalIndex;
system->threadVisitor->visit(ip, stack, link); system->threadVisitor->visit(ip, stack, link);
System::Thread* t = system->visitTarget; System::Thread* t = system->visitTarget;
@ -987,57 +939,6 @@ handleSignal(int signal, siginfo_t*, void* context)
system->visitLock->notifyAll(t); system->visitLock->notifyAll(t);
} break; } 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 InterruptSignal:
case PipeSignal: case PipeSignal:
break; break;
@ -1052,7 +953,7 @@ handleSignal(int signal, siginfo_t*, void* context)
namespace vm { namespace vm {
AVIAN_EXPORT System* AVIAN_EXPORT System*
makeSystem(const char*) makeSystem()
{ {
return new (malloc(sizeof(MySystem))) MySystem(); return new (malloc(sizeof(MySystem))) MySystem();
} }

207
src/system/posix/signal.cpp Normal file
View File

@ -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 <asm/sigcontext.h> /* for sigcontext */
#include <asm/signal.h> /* 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 <avian/system/system.h>
#include <avian/system/signal.h>
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<ucontext_t*>(context);
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
#ifdef FRAME_REGISTER
void* frame = reinterpret_cast<void*>(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

View File

@ -10,7 +10,6 @@
#include "sys/stat.h" #include "sys/stat.h"
#include "windows.h" #include "windows.h"
#include "sys/timeb.h"
#ifdef _MSC_VER #ifdef _MSC_VER
# define S_ISREG(x) ((x) & _S_IFREG) # define S_ISREG(x) ((x) & _S_IFREG)
@ -115,11 +114,6 @@ class MutexResource {
HANDLE m; HANDLE m;
}; };
const unsigned SegFaultIndex = 0;
const unsigned DivideByZeroIndex = 1;
const unsigned HandlerCount = 2;
class MySystem; class MySystem;
MySystem* system; MySystem* system;
@ -626,68 +620,15 @@ class MySystem: public System {
System::Library* next_; System::Library* next_;
}; };
MySystem(const char* crashDumpDirectory): MySystem()
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
oldHandler(0),
#endif
crashDumpDirectory(crashDumpDirectory)
{ {
expect(this, system == 0); expect(this, system == 0);
system = this; system = this;
memset(handlers, 0, sizeof(handlers));
mutex = CreateMutex(0, false, 0); mutex = CreateMutex(0, false, 0);
assert(this, mutex); 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<LPTOP_LEVEL_EXCEPTION_FILTER>(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) { virtual void* tryAllocate(unsigned sizeInBytes) {
return malloc(sizeInBytes); return malloc(sizeInBytes);
} }
@ -746,14 +687,6 @@ class MySystem: public System {
return 0; 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, virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget,
ThreadVisitor* visitor) ThreadVisitor* visitor)
{ {
@ -1020,139 +953,16 @@ class MySystem: public System {
} }
HANDLE mutex; 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
<MiniDumpWriteDumpType>(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<int64_t>(tb.time) * 1000)
+ static_cast<int64_t>(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<void*>(e->ContextRecord->Eip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Ebx);
#elif defined ARCH_x86_64
void* ip = reinterpret_cast<void*>(e->ContextRecord->Rip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Rbp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Rsp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Rbx);
#endif
bool jump = handler->handleSignal(&ip, &base, &stack, &thread);
#ifdef ARCH_x86_32
e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread);
#elif defined ARCH_x86_64
e->ContextRecord->Rip = reinterpret_cast<DWORD64>(ip);
e->ContextRecord->Rbp = reinterpret_cast<DWORD64>(base);
e->ContextRecord->Rsp = reinterpret_cast<DWORD64>(stack);
e->ContextRecord->Rbx = reinterpret_cast<DWORD64>(thread);
#endif
if (jump) {
return EXCEPTION_CONTINUE_EXECUTION;
} else if (system->crashDumpDirectory) {
dump(e, system->crashDumpDirectory);
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
} // namespace } // namespace
namespace vm { namespace vm {
AVIAN_EXPORT System* AVIAN_EXPORT System*
makeSystem(const char* crashDumpDirectory) makeSystem()
{ {
return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory); return new (malloc(sizeof(MySystem))) MySystem();
} }
} // namespace vm } // namespace vm

View File

@ -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 <avian/system/signal.h>
#include <avian/common.h>
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
<MiniDumpWriteDumpType>(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<int64_t>(tb.time) * 1000) + static_cast
<int64_t>(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<void*>(e->ContextRecord->Eip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Ebx);
#elif defined ARCH_x86_64
void* ip = reinterpret_cast<void*>(e->ContextRecord->Rip);
void* base = reinterpret_cast<void*>(e->ContextRecord->Rbp);
void* stack = reinterpret_cast<void*>(e->ContextRecord->Rsp);
void* thread = reinterpret_cast<void*>(e->ContextRecord->Rbx);
#endif
bool jump = handler->handleSignal(&ip, &base, &stack, &thread);
#ifdef ARCH_x86_32
e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread);
#elif defined ARCH_x86_64
e->ContextRecord->Rip = reinterpret_cast<DWORD64>(ip);
e->ContextRecord->Rbp = reinterpret_cast<DWORD64>(base);
e->ContextRecord->Rsp = reinterpret_cast<DWORD64>(stack);
e->ContextRecord->Rbx = reinterpret_cast<DWORD64>(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<LPTOP_LEVEL_EXCEPTION_FILTER>(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

View File

@ -34,7 +34,7 @@ public:
Architecture* arch; Architecture* arch;
BasicEnv(): BasicEnv():
s(makeSystem(0)), s(makeSystem()),
heap(makeHeap(s, 32 * 1024)), heap(makeHeap(s, 32 * 1024)),
arch(makeArchitectureNative(s, true)) arch(makeArchitectureNative(s, true))
{ {

View File

@ -1899,11 +1899,11 @@ main(int ac, const char** av)
Arguments args(ac, av); Arguments args(ac, av);
// args.dump(); // args.dump();
System* s = makeSystem(0); System* s = makeSystem();
Heap* h = makeHeap(s, HeapCapacity * 2); Heap* h = makeHeap(s, HeapCapacity * 2);
Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX);
Finder* f = makeFinder(s, h, args.classpath, 0); 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 // todo: currently, the compiler cannot compile code with jumps or
// calls spanning more than the maximum size of an immediate value // calls spanning more than the maximum size of an immediate value

View File

@ -1941,7 +1941,7 @@ main(int ac, char** av)
local::usageAndExit(av[0]); local::usageAndExit(av[0]);
} }
System* system = makeSystem(0); System* system = makeSystem();
class MyAllocator: public Allocator { class MyAllocator: public Allocator {
public: public:

View File

@ -33,7 +33,7 @@ public:
Architecture* arch; Architecture* arch;
BasicEnv(): BasicEnv():
s(makeSystem(0)), s(makeSystem()),
heap(makeHeap(s, 32 * 1024)), heap(makeHeap(s, 32 * 1024)),
arch(makeArchitectureNative(s, true)) arch(makeArchitectureNative(s, true))
{ {