use dbghelp.dll to generate crash dump file on Windows XP and later

The dump is written to the directory specified via the avian.crash.dir
system property if that property is set and is not written otherwise.
This commit is contained in:
Joel Dice 2008-10-27 15:13:27 -06:00
parent 003afdc918
commit 4d613f404f
7 changed files with 135 additions and 45 deletions

View File

@ -543,8 +543,9 @@ Java_java_lang_Runtime_load(Thread* t, jclass, jstring name, jboolean mapName)
char n[length + 1]; char n[length + 1];
stringChars(t, *name, n); stringChars(t, *name, n);
if (mapName and t->m->builtins) { const char* builtins = findProperty(t, "avian.builtins");
const char* s = t->m->builtins; if (mapName and builtins) {
const char* s = builtins;
while (*s) { while (*s) {
if (strncmp(s, n, length) == 0 if (strncmp(s, n, length) == 0
and (s[length] == ',' or s[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); ENTER(t, Thread::ActiveState);
abort(t);
unsigned length = stringLength(t, *outputFile); unsigned length = stringLength(t, *outputFile);
char n[length + 1]; char n[length + 1];
stringChars(t, *outputFile, n); stringChars(t, *outputFile, n);

View File

@ -2046,12 +2046,13 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable)
} // namespace vm } // namespace vm
#define BUILTINS_PROPERTY "avian.builtins"
#define BOOTSTRAP_PROPERTY "avian.bootstrap" #define BOOTSTRAP_PROPERTY "avian.bootstrap"
#define CRASHDIR_PROPERTY "avian.crash.dir"
#define CLASSPATH_PROPERTY "java.class.path" #define CLASSPATH_PROPERTY "java.class.path"
#define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p"
#define BOOTCLASSPATH_OPTION "bootclasspath" #define BOOTCLASSPATH_OPTION "bootclasspath"
#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a"
#define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a"
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
JNI_GetDefaultJavaVMInitArgs(void*) JNI_GetDefaultJavaVMInitArgs(void*)
@ -2065,12 +2066,12 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
JavaVMInitArgs* a = static_cast<JavaVMInitArgs*>(args); JavaVMInitArgs* a = static_cast<JavaVMInitArgs*>(args);
unsigned heapLimit = 0; unsigned heapLimit = 0;
const char* builtins = 0;
const char* bootLibrary = 0; const char* bootLibrary = 0;
const char* classpath = 0; const char* classpath = 0;
const char* bootClasspathPrepend = ""; const char* bootClasspathPrepend = "";
const char* bootClasspath = ""; const char* bootClasspath = "";
const char* bootClasspathAppend = ""; const char* bootClasspathAppend = "";
const char* crashDumpDirectory = 0;
unsigned propertyCount = 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) { } else if (strncmp(a->options[i].optionString, "-D", 2) == 0) {
const char* p = a->options[i].optionString + 2; const char* p = a->options[i].optionString + 2;
if (strncmp(p, BUILTINS_PROPERTY "=", if (strncmp(p, BOOTSTRAP_PROPERTY "=",
sizeof(BUILTINS_PROPERTY)) == 0) sizeof(BOOTSTRAP_PROPERTY)) == 0)
{
builtins = p + sizeof(BUILTINS_PROPERTY);
} else if (strncmp(p, BOOTSTRAP_PROPERTY "=",
sizeof(BOOTSTRAP_PROPERTY)) == 0)
{ {
bootLibrary = p + sizeof(BOOTSTRAP_PROPERTY); 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 "=", } else if (strncmp(p, CLASSPATH_PROPERTY "=",
sizeof(CLASSPATH_PROPERTY)) == 0) sizeof(CLASSPATH_PROPERTY)) == 0)
{ {
@ -2130,7 +2131,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR); append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR);
append(&classpathPointer, classpath, cpl, 0); append(&classpathPointer, classpath, cpl, 0);
System* s = makeSystem(); System* s = makeSystem(crashDumpDirectory);
Heap* h = makeHeap(s, heapLimit); Heap* h = makeHeap(s, heapLimit);
Finder* f = makeFinder(s, classpathBuffer, bootLibrary); Finder* f = makeFinder(s, classpathBuffer, bootLibrary);
Processor* p = makeProcessor(s, h); Processor* p = makeProcessor(s, h);
@ -2145,7 +2146,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
} }
*m = new (h->allocate(sizeof(Machine))) *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); *t = p->makeThread(*m, 0, 0);

View File

@ -1630,8 +1630,7 @@ class HeapClient: public Heap::Client {
namespace vm { namespace vm {
Machine::Machine(System* system, Heap* heap, Finder* finder, Machine::Machine(System* system, Heap* heap, Finder* finder,
Processor* processor, const char* bootLibrary, Processor* processor, const char** properties,
const char* builtins, const char** properties,
unsigned propertyCount): unsigned propertyCount):
vtable(&javaVMVTable), vtable(&javaVMVTable),
system(system), system(system),
@ -1643,7 +1642,6 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
rootThread(0), rootThread(0),
exclusive(0), exclusive(0),
jniReferences(0), jniReferences(0),
builtins(builtins),
properties(properties), properties(properties),
propertyCount(propertyCount), propertyCount(propertyCount),
activeCount(0), 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(&heapLock)) or
not system->success(system->make(&classLock)) or not system->success(system->make(&classLock)) or
not system->success(system->make(&referenceLock)) 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(); system->abort();
} }

View File

@ -1122,7 +1122,6 @@ class Machine {
}; };
Machine(System* system, Heap* heap, Finder* finder, Processor* processor, Machine(System* system, Heap* heap, Finder* finder, Processor* processor,
const char* bootLibrary, const char* builtins,
const char** properties, unsigned propertyCount); const char** properties, unsigned propertyCount);
~Machine() { ~Machine() {
@ -1144,7 +1143,6 @@ class Machine {
Thread* rootThread; Thread* rootThread;
Thread* exclusive; Thread* exclusive;
Reference* jniReferences; Reference* jniReferences;
const char* builtins;
const char** properties; const char** properties;
unsigned propertyCount; unsigned propertyCount;
unsigned activeCount; unsigned activeCount;
@ -1514,10 +1512,10 @@ setObjectClass(Thread*, object o, object value)
} }
inline const char* inline const char*
findProperty(Thread* t, const char* name) findProperty(Machine* m, const char* name)
{ {
for (unsigned i = 0; i < t->m->propertyCount; ++i) { for (unsigned i = 0; i < m->propertyCount; ++i) {
const char* p = t->m->properties[i]; const char* p = m->properties[i];
const char* n = name; const char* n = name;
while (*p and *p != '=' and *n and *p == *n) { while (*p and *p != '=' and *n and *p == *n) {
++ p; ++ p;
@ -1530,6 +1528,12 @@ findProperty(Thread* t, const char* name)
return 0; return 0;
} }
inline const char*
findProperty(Thread* t, const char* name)
{
return findProperty(t->m, name);
}
object& object&
arrayBodyUnsafe(Thread*, object, unsigned); arrayBodyUnsafe(Thread*, object, unsigned);

View File

@ -856,7 +856,7 @@ handleSignal(int signal, siginfo_t* info, void* context)
namespace vm { namespace vm {
System* System*
makeSystem() makeSystem(const char*)
{ {
return new (malloc(sizeof(MySystem))) MySystem(); return new (malloc(sizeof(MySystem))) MySystem();
} }

View File

@ -185,7 +185,7 @@ assert(System* s, bool v)
#endif // not NDEBUG #endif // not NDEBUG
System* System*
makeSystem(); makeSystem(const char* crashDumpDirectory);
} // namespace vm } // namespace vm

View File

@ -10,6 +10,7 @@
#include "sys/stat.h" #include "sys/stat.h"
#include "windows.h" #include "windows.h"
#include "sys/timeb.h"
#undef max #undef max
#undef min #undef min
@ -40,25 +41,11 @@ class MutexResource {
HANDLE m; HANDLE m;
}; };
System::SignalHandler* segFaultHandler = 0; class MySystem;
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0; MySystem* system;
LONG CALLBACK LONG CALLBACK
handleException(LPEXCEPTION_POINTERS e) handleException(LPEXCEPTION_POINTERS e);
{
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
bool jump = segFaultHandler->handleSignal
(reinterpret_cast<void**>(&(e->ContextRecord->Eip)),
reinterpret_cast<void**>(&(e->ContextRecord->Ebp)),
reinterpret_cast<void**>(&(e->ContextRecord->Esp)),
reinterpret_cast<void**>(&(e->ContextRecord->Ebx)));
if (jump) {
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
DWORD WINAPI DWORD WINAPI
run(void* r) run(void* r)
@ -495,7 +482,14 @@ class MySystem: public System {
System::Library* next_; 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); mutex = CreateMutex(0, false, 0);
assert(this, mutex); assert(this, mutex);
} }
@ -721,8 +715,9 @@ class MySystem: public System {
} }
virtual void abort() { virtual void abort() {
asm("int3"); // trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and
::abort(); // generate a debug dump for
*static_cast<int*>(0) = 0;
} }
virtual void dispose() { virtual void dispose() {
@ -731,16 +726,104 @@ class MySystem: public System {
} }
HANDLE mutex; 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
<MiniDumpWriteDumpType>(GetProcAddress(dbghelp, "MiniDumpWriteDump"));
if (MiniDumpWriteDump) {
char name[MAX_PATH];
_timeb tb;
_ftime(&tb);
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,
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<void**>(&(e->ContextRecord->Eip)),
reinterpret_cast<void**>(&(e->ContextRecord->Ebp)),
reinterpret_cast<void**>(&(e->ContextRecord->Esp)),
reinterpret_cast<void**>(&(e->ContextRecord->Ebx)));
if (jump) {
return EXCEPTION_CONTINUE_EXECUTION;
}
}
if (system->crashDumpDirectory) {
dump(e, system->crashDumpDirectory);
}
return EXCEPTION_CONTINUE_SEARCH;
}
} // namespace } // namespace
namespace vm { namespace vm {
System* System*
makeSystem() makeSystem(const char* crashDumpDirectory)
{ {
return new (malloc(sizeof(MySystem))) MySystem(); return new (malloc(sizeof(MySystem))) MySystem(crashDumpDirectory);
} }
} // namespace vm } // namespace vm