diff --git a/src/builtin.cpp b/src/builtin.cpp index dd2e95ec29..f3da5aceeb 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -543,8 +543,9 @@ Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName) char n[length + 1]; stringChars(t, *name, n); - if (mapName and t->m->builtins) { - const char* s = t->m->builtins; + const char* builtins = findProperty(t, "avian.builtins"); + if (mapName and builtins) { + const char* s = builtins; while (*s) { if (strncmp(s, n, length) == 0 and (s[length] == ',' or s[length] == 0)) @@ -592,6 +593,8 @@ Java_java_lang_Runtime_dumpHeap(Thread* t, jclass, jstring outputFile) { ENTER(t, Thread::ActiveState); + abort(t); + unsigned length = stringLength(t, *outputFile); char n[length + 1]; stringChars(t, *outputFile, n); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index ce7107dbbc..8ffb581151 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2046,12 +2046,13 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) } // namespace vm -#define BUILTINS_PROPERTY "avian.builtins" #define BOOTSTRAP_PROPERTY "avian.bootstrap" +#define CRASHDIR_PROPERTY "avian.crash.dir" #define CLASSPATH_PROPERTY "java.class.path" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_OPTION "bootclasspath" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" +#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" extern "C" JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void*) @@ -2065,12 +2066,12 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) JavaVMInitArgs* a = static_cast(args); unsigned heapLimit = 0; - const char* builtins = 0; const char* bootLibrary = 0; const char* classpath = 0; const char* bootClasspathPrepend = ""; const char* bootClasspath = ""; const char* bootClasspathAppend = ""; + const char* crashDumpDirectory = 0; unsigned propertyCount = 0; @@ -2094,14 +2095,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } } else if (strncmp(a->options[i].optionString, "-D", 2) == 0) { const char* p = a->options[i].optionString + 2; - if (strncmp(p, BUILTINS_PROPERTY "=", - sizeof(BUILTINS_PROPERTY)) == 0) - { - builtins = p + sizeof(BUILTINS_PROPERTY); - } else if (strncmp(p, BOOTSTRAP_PROPERTY "=", - sizeof(BOOTSTRAP_PROPERTY)) == 0) + if (strncmp(p, BOOTSTRAP_PROPERTY "=", + sizeof(BOOTSTRAP_PROPERTY)) == 0) { bootLibrary = p + sizeof(BOOTSTRAP_PROPERTY); + } else if (strncmp(p, CRASHDIR_PROPERTY "=", + sizeof(CRASHDIR_PROPERTY)) == 0) + { + crashDumpDirectory = p + sizeof(CRASHDIR_PROPERTY); } else if (strncmp(p, CLASSPATH_PROPERTY "=", sizeof(CLASSPATH_PROPERTY)) == 0) { @@ -2130,7 +2131,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR); append(&classpathPointer, classpath, cpl, 0); - System* s = makeSystem(); + System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); Finder* f = makeFinder(s, classpathBuffer, bootLibrary); Processor* p = makeProcessor(s, h); @@ -2145,7 +2146,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } *m = new (h->allocate(sizeof(Machine))) - Machine(s, h, f, p, bootLibrary, builtins, properties, propertyCount); + Machine(s, h, f, p, properties, propertyCount); *t = p->makeThread(*m, 0, 0); diff --git a/src/machine.cpp b/src/machine.cpp index 20ecead92d..713e4ac0e7 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1630,8 +1630,7 @@ class HeapClient: public Heap::Client { namespace vm { Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor, const char* bootLibrary, - const char* builtins, const char** properties, + Processor* processor, const char** properties, unsigned propertyCount): vtable(&javaVMVTable), system(system), @@ -1643,7 +1642,6 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, rootThread(0), exclusive(0), jniReferences(0), - builtins(builtins), properties(properties), propertyCount(propertyCount), activeCount(0), @@ -1678,7 +1676,8 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or not system->success(system->make(&referenceLock)) or - not system->success(system->load(&libraries, bootLibrary, false))) + not system->success + (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) { system->abort(); } diff --git a/src/machine.h b/src/machine.h index c2c4eed50d..c27e394c5b 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1122,7 +1122,6 @@ class Machine { }; Machine(System* system, Heap* heap, Finder* finder, Processor* processor, - const char* bootLibrary, const char* builtins, const char** properties, unsigned propertyCount); ~Machine() { @@ -1144,7 +1143,6 @@ class Machine { Thread* rootThread; Thread* exclusive; Reference* jniReferences; - const char* builtins; const char** properties; unsigned propertyCount; unsigned activeCount; @@ -1514,10 +1512,10 @@ setObjectClass(Thread*, object o, object value) } inline const char* -findProperty(Thread* t, const char* name) +findProperty(Machine* m, const char* name) { - for (unsigned i = 0; i < t->m->propertyCount; ++i) { - const char* p = t->m->properties[i]; + for (unsigned i = 0; i < m->propertyCount; ++i) { + const char* p = m->properties[i]; const char* n = name; while (*p and *p != '=' and *n and *p == *n) { ++ p; @@ -1530,6 +1528,12 @@ findProperty(Thread* t, const char* name) return 0; } +inline const char* +findProperty(Thread* t, const char* name) +{ + return findProperty(t->m, name); +} + object& arrayBodyUnsafe(Thread*, object, unsigned); diff --git a/src/posix.cpp b/src/posix.cpp index 768e5a8106..8f480aee26 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -856,7 +856,7 @@ handleSignal(int signal, siginfo_t* info, void* context) namespace vm { System* -makeSystem() +makeSystem(const char*) { return new (malloc(sizeof(MySystem))) MySystem(); } diff --git a/src/system.h b/src/system.h index 3771010606..69d42a25e1 100644 --- a/src/system.h +++ b/src/system.h @@ -185,7 +185,7 @@ assert(System* s, bool v) #endif // not NDEBUG System* -makeSystem(); +makeSystem(const char* crashDumpDirectory); } // namespace vm diff --git a/src/windows.cpp b/src/windows.cpp index 9d2cb6b58c..5c57384429 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -10,6 +10,7 @@ #include "sys/stat.h" #include "windows.h" +#include "sys/timeb.h" #undef max #undef min @@ -40,25 +41,11 @@ class MutexResource { HANDLE m; }; -System::SignalHandler* segFaultHandler = 0; -LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0; +class MySystem; +MySystem* system; LONG CALLBACK -handleException(LPEXCEPTION_POINTERS e) -{ - if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - 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; -} +handleException(LPEXCEPTION_POINTERS e); DWORD WINAPI run(void* r) @@ -495,7 +482,14 @@ class MySystem: public System { System::Library* next_; }; - MySystem() { + MySystem(const char* crashDumpDirectory): + segFaultHandler(0), + oldSegFaultHandler(0), + crashDumpDirectory(crashDumpDirectory) + { + expect(this, system == 0); + system = this; + mutex = CreateMutex(0, false, 0); assert(this, mutex); } @@ -721,8 +715,9 @@ class MySystem: public System { } virtual void abort() { - asm("int3"); - ::abort(); + // trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and + // generate a debug dump for + *static_cast(0) = 0; } virtual void dispose() { @@ -731,16 +726,104 @@ class MySystem: public System { } HANDLE mutex; + System::SignalHandler* segFaultHandler; + LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler; + const char* crashDumpDirectory; }; +struct MINIDUMP_EXCEPTION_INFORMATION { + DWORD thread; + LPEXCEPTION_POINTERS exception; + BOOL exceptionInCurrentAddressSpace; +}; + +struct MINIDUMP_USER_STREAM_INFORMATION; +struct MINIDUMP_CALLBACK_INFORMATION; + +enum MINIDUMP_TYPE { + MiniDumpNormal = 0 +}; + +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); + 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, + MiniDumpNormal, + &exception, + 0, + 0); + + CloseHandle(file); + } + } + + FreeLibrary(dbghelp); + } +} + +LONG CALLBACK +handleException(LPEXCEPTION_POINTERS e) +{ + if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + bool jump = system->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; + } + } + + if (system->crashDumpDirectory) { + dump(e, system->crashDumpDirectory); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + } // namespace namespace vm { System* -makeSystem() +makeSystem(const char* crashDumpDirectory) { - return new (malloc(sizeof(MySystem))) MySystem(); + return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory); } } // namespace vm