mirror of
https://github.com/corda/corda.git
synced 2025-02-03 09:41:10 +00:00
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:
parent
003afdc918
commit
4d613f404f
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
127
src/windows.cpp
127
src/windows.cpp
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user