Salikh Zakirov wrote:
> I recently found out the reason why smoke test gc.LOS hangs DRLVM on Windows
> XP, and it turned out to be related to the hardware exception handling.
>
> Since the fix will involve significant modifications to the file
> vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp,
> I can do this modification too.
I'm sending my current state of the patch (well, series of 3 patches)
for interested parties to review.
However, these patches somewhat regress in functionality:
I still haven't figured out how to piggy-back on exception throw
to call JVMTI callback and to restore stack guard page.
(the commented out block at the end of nt_exception_filter.cpp was doing it
before fix).
Any ideas appreciated.
>From a8f9838563950b4eaed54582f053c841d55759f7 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 16:14:27 +0300
Subject: [PATCH] changed logging in nt_exception_filter.c from cxx-style to
c-style
---
.../src/util/win/ia32/nt_exception_filter.cpp | 26 ++++++++++----------
1 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 65cd721..061d33b 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -19,7 +19,7 @@
* @version $Revision: 1.1.2.1.4.4 $
*/
-#include "cxxlog.h"
+#include "clog.h"
#include "method_lookup.h"
#include "Environment.h"
#include "exceptions.h"
@@ -301,9 +301,9 @@ static LONG NTAPI vectored_exception_han
bool run_default_handler = true;
PCONTEXT context = nt_exception->ContextRecord;
- TRACE2("signals", "VEH received an exception: code = 0x" <<
- ((void*)nt_exception->ExceptionRecord->ExceptionCode) <<
- " location IP = 0x" << ((void*)context->Eip));
+ TRACE2("signals", ("VEH received an exception: code = %x, eip = %p",
+ nt_exception->ExceptionRecord->ExceptionCode,
+ ((void*)context->Eip)));
// this filter catches _all_ hardware exceptions including those caused by
// VM internal code. To elimate confusion over what caused the
@@ -360,9 +360,9 @@ static LONG NTAPI vectored_exception_han
case STATUS_STACK_OVERFLOW:
// stack overflow exception -- see ...\vc\include\winnt.h
{
- TRACE2("signals", "StackOverflowError detected at "
- << (void *) context->Eip << " on the stack at "
- << (void *) context->Esp);
+ TRACE2("signals",
+ ("StackOverflowError detected at eip = %p, esp = %p",
+ context->Eip,context->Esp));
// Lazy exception object creation
exc_clss = env->java_lang_StackOverflowError_Class;
p_TLS_vmthread->restore_guard_page = true;
@@ -371,8 +371,8 @@ static LONG NTAPI vectored_exception_han
case STATUS_ACCESS_VIOLATION:
// null pointer exception -- see ...\vc\include\winnt.h
{
- TRACE2("signals", "NullPointerException detected at "
- << (void *) context->Eip);
+ TRACE2("signals",
+ ("NullPointerException detected at eip = %p", context->Eip));
// Lazy exception object creation
exc_clss = env->java_lang_NullPointerException_Class;
}
@@ -381,8 +381,8 @@ static LONG NTAPI vectored_exception_han
case STATUS_INTEGER_DIVIDE_BY_ZERO:
// divide by zero exception -- see ...\vc\include\winnt.h
{
- TRACE2("signals", "ArithmeticException detected at "
- << (void *) context->Eip);
+ TRACE2("signals",
+ ("ArithmeticException detected at eip = %p", context->Eip));
// Lazy exception object creation
exc_clss = env->java_lang_ArithmeticException_Class;
}
@@ -392,8 +392,8 @@ static LONG NTAPI vectored_exception_han
{
Registers regs;
nt_to_vm_context(context, ®s);
- TRACE2("signals", "JVMTI breakpoint detected at " <<
- (void *)regs.eip);
+ TRACE2("signals",
+ ("JVMTI breakpoint detected at eip = %p", regs.eip));
bool handled = jvmti_jit_breakpoint_handler(®s);
if (handled)
{
--
1.4.4.1.g2d57
>From c3e6321984a02e5b9bdcf36cc36adfc7176d9239 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 17:09:15 +0300
Subject: [PATCH] fixed exception handler to throw exception outside of NT
hardware exception handler
---
.../src/util/win/ia32/nt_exception_filter.cpp | 135 ++++++++++++++++----
1 files changed, 111 insertions(+), 24 deletions(-)
diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 061d33b..8f5644d 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -27,10 +27,13 @@
#include "interpreter_exports.h"
#include "stack_dump.h"
#include "jvmti_break_intf.h"
+#include "vm_threads.h"
+#include "m2n.h"
// Windows specific
#include <string>
#include <excpt.h>
+#include <stddef.h> // for offsetof
#if INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3
#define JVMTI_EXCEPTION_STATUS STATUS_BREAKPOINT
@@ -276,6 +279,61 @@ void __declspec(naked) asm_jvmti_excepti
}
}
+static void __cdecl c_exception_handler(Class*);
+
+// the control is transferred to this handler
+// after NT exception handler returned
+static void __declspec(naked) asm_exception_handler_push_m2n() {
+ // input parameters:
+ // EAX = exception eip
+ // EDX = exn_class
+ static const int last_m2n_frame_offset =
+ offsetof(VM_thread, last_m2n_frame);
+ __asm {
+ // construct M2nFrame on a stack
+ push eax // M2n: EIP
+ push ebp // M2n: EBP
+ mov ebp, esp
+ push ebx // M2n: EBX
+ push esi // M2n: ESI
+ push edi // M2n: EDI
+
+ push 0 // M2n: pop_regs = NULL
+ push 0 // M2n: frame type
+ push 0 // M2n: method = NULL
+ push 0 // M2n: object handles = NULL
+
+ // get thread ptr to eax
+ push ecx
+ push edx
+ call get_thread_ptr
+ pop edx
+ pop ecx
+
+ // get &p_TLS_vmthread->last_m2n_frame
+ add eax, last_m2n_frame_offset
+ push eax // M2n: p_lm2nf
+ push [eax] // M2n: prev_m2nf
+ mov [eax], esp // store M2n pointer to VM_thread
+
+ // push parameter exn_class
+ push edx
+ call c_exception_handler
+ }
+ assert(!"internal error on throwing exception");
+}
+
+static void __declspec(naked) asm_exception_handler_no_m2n() {
+ // input parameters:
+ // EDX = exn_class
+ __asm {
+ // push parameter exn_class
+ push edx
+ call c_exception_handler
+ }
+ assert(!"internal error on throwing exception");
+}
+
static LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS
nt_exception);
LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS
nt_exception)
@@ -297,24 +355,33 @@ LONG __declspec(naked) NTAPI vectored_ex
static LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS
nt_exception)
{
DWORD code = nt_exception->ExceptionRecord->ExceptionCode;
-
- bool run_default_handler = true;
PCONTEXT context = nt_exception->ContextRecord;
-
+
TRACE2("signals", ("VEH received an exception: code = %x, eip = %p",
nt_exception->ExceptionRecord->ExceptionCode,
((void*)context->Eip)));
-
- // this filter catches _all_ hardware exceptions including those caused by
- // VM internal code. To elimate confusion over what caused the
- // exception, we first make sure the exception was thrown inside a Java
- // method else crash handler or default handler is executed, this means
that
- // it was thrown by VM C/C++ code.
- if (((code == STATUS_ACCESS_VIOLATION ||
- code == STATUS_INTEGER_DIVIDE_BY_ZERO ||
- code == STATUS_STACK_OVERFLOW) &&
- vm_identify_eip((void *)context->Eip) == VM_TYPE_JAVA) ||
- code == JVMTI_EXCEPTION_STATUS) {
+
+ // the possible reasons for hardware exception are
+ // - segfault in java code
+ // => NullPointerException
+ //
+ // - stack overflow, either in java or in native
+ // => StackOverflowError
+ //
+ // - breakpoint in java code
+ // => send jvmti breakpoint event
+ //
+ // - other (likely internal VM error)
+ // => delegate to default handler
+
+ void* eip = (void*)context->Eip;
+ bool run_default_handler = true;
+ bool in_java = (vm_identify_eip(eip) == VM_TYPE_JAVA);
+
+ if ((in_java && (code == STATUS_ACCESS_VIOLATION
+ || code == STATUS_INTEGER_DIVIDE_BY_ZERO
+ || code == STATUS_STACK_OVERFLOW))
+ || code == JVMTI_EXCEPTION_STATUS) {
run_default_handler = false;
} else if (code == STATUS_STACK_OVERFLOW) {
if (is_unwindable()) {
@@ -406,18 +473,39 @@ static LONG NTAPI vectored_exception_han
default: assert(false);
}
- Registers regs;
+ // we must not call potentially blocking or suspendable
+ // code (e.g. java code) from exception handler, because
+ // this handler may holds a system-wide lock, and thus
+ // may lead to a deadlock.
+
+ // it was reported that exception handler grabs a system
+ // lock on Windows XPsp2 and 2003sp0, but not on a 2003sp1
+
+ // exit NT exception handler and transfer
+ // control to VM exception handler,
+ // passing parameters on the registers
+ context->Eax = context->Eip;
+ context->Edx = (uint32)exc_clss;
+ if (in_java)
+ context->Eip = (uint32)asm_exception_handler_push_m2n;
+ else
+ context->Eip = (uint32)asm_exception_handler_no_m2n;
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
- nt_to_vm_context(context, ®s);
- uint32 exception_esp = regs.esp;
+static void __cdecl c_exception_handler(Class *exn_class)
+{
DebugUtilsTI* ti = VM_Global_State::loader_env->TI;
- // TODO: We already checked that above. Is it possible to reuse the result?
- bool java_code = (vm_identify_eip((void *)regs.eip) == VM_TYPE_JAVA);
- exn_athrow_regs(®s, exc_clss, java_code);
+ void *eip = m2n_get_ip(p_TLS_vmthread->last_m2n_frame);
- assert(exception_esp <= regs.esp);
+ TRACE2("signals", ("should throw exception at EIP: %p", eip));
+ TRACE2("signals", ("last m2n: %p",
+ p_TLS_vmthread->last_m2n_frame));
+ exn_athrow(NULL, exn_class, NULL, NULL);
+
+ /*
if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT))
{
regs.esp = regs.esp - 4;
*((uint32*) regs.esp) = regs.eip;
@@ -429,6 +517,5 @@ static LONG NTAPI vectored_exception_han
}
vm_to_nt_context(®s, context);
-
- return EXCEPTION_CONTINUE_EXECUTION;
-} //vectored_exception_handler
+ */
+}
--
1.4.4.1.g2d57
>From f29c05e52cb9c61d958239f1307d01f4b5279794 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 18:13:03 +0300
Subject: [PATCH] cleaned up NT exception handler
---
.../src/util/win/ia32/nt_exception_filter.cpp | 101 ++++++++------------
1 files changed, 40 insertions(+), 61 deletions(-)
diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 8f5644d..02804c0 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -281,8 +281,7 @@ void __declspec(naked) asm_jvmti_excepti
static void __cdecl c_exception_handler(Class*);
-// the control is transferred to this handler
-// after NT exception handler returned
+// pushes M2nFrame and calls c_exception_handler()
static void __declspec(naked) asm_exception_handler_push_m2n() {
// input parameters:
// EAX = exception eip
@@ -323,6 +322,7 @@ static void __declspec(naked) asm_except
assert(!"internal error on throwing exception");
}
+// calls c_exception_handler() without pushing M2nFrame
static void __declspec(naked) asm_exception_handler_no_m2n() {
// input parameters:
// EDX = exn_class
@@ -362,95 +362,72 @@ static LONG NTAPI vectored_exception_han
((void*)context->Eip)));
// the possible reasons for hardware exception are
- // - segfault in java code
- // => NullPointerException
+ // - segfault or division by zero in java code
+ // => NullPointerException or ArithmeticException
+ //
+ // - breakpoint or privileged instruction in java code
+ // => send jvmti breakpoint event
//
// - stack overflow, either in java or in native
// => StackOverflowError
//
- // - breakpoint in java code
- // => send jvmti breakpoint event
- //
- // - other (likely internal VM error)
+ // - other (internal VM error or debugger breakpoint)
// => delegate to default handler
- void* eip = (void*)context->Eip;
- bool run_default_handler = true;
- bool in_java = (vm_identify_eip(eip) == VM_TYPE_JAVA);
-
- if ((in_java && (code == STATUS_ACCESS_VIOLATION
- || code == STATUS_INTEGER_DIVIDE_BY_ZERO
- || code == STATUS_STACK_OVERFLOW))
- || code == JVMTI_EXCEPTION_STATUS) {
- run_default_handler = false;
- } else if (code == STATUS_STACK_OVERFLOW) {
- if (is_unwindable()) {
- if (hythread_is_suspend_enabled()) {
- tmn_suspend_disable();
- }
- run_default_handler = false;
- } else {
- Global_Env *env = VM_Global_State::loader_env;
- exn_raise_by_class(env->java_lang_StackOverflowError_Class);
- p_TLS_vmthread->restore_guard_page = true;
- return EXCEPTION_CONTINUE_EXECUTION;
- }
- }
+ bool in_java = (vm_identify_eip((void*)context->Eip) == VM_TYPE_JAVA);
- if (run_default_handler) {
-#ifndef NDEBUG
- if (vm_get_boolean_property_value_with_default("vm.assert_dialog")) {
-
- if (IS_ERROR(code)) {
- if (UnhandledExceptionFilter(nt_exception) ==
EXCEPTION_CONTINUE_SEARCH)
- DebugBreak();
- }
- }
-#endif
+ // delegate "other" cases to default handler
+ if (!in_java && code != STATUS_STACK_OVERFLOW)
return EXCEPTION_CONTINUE_SEARCH;
- }
- // since we are now sure HWE occured in java code, gc should also have
been disabled
+ // if HWE occured in java code, suspension should also have been disabled
+ assert(!in_java || !hythread_is_suspend_enabled());
- // gregory - this is not true since for debugging we may use int3
- // in VM code which produces BREAKPOINT exception. JVMTI has
- // assertions for breakpoints which it has set in Java inside of
- // breakpoint handling function. Otherwise this assert should not
- // fail in case _CrtDbgBreak() was added somewhere in VM.
- assert(!hythread_is_suspend_enabled() || code == JVMTI_EXCEPTION_STATUS);
-
Global_Env *env = VM_Global_State::loader_env;
+ // the actual exception object will be created lazily,
+ // we determine only exception class here
Class *exc_clss = 0;
switch(nt_exception->ExceptionRecord->ExceptionCode)
{
case STATUS_STACK_OVERFLOW:
- // stack overflow exception -- see ...\vc\include\winnt.h
{
TRACE2("signals",
("StackOverflowError detected at eip = %p, esp = %p",
context->Eip,context->Esp));
- // Lazy exception object creation
- exc_clss = env->java_lang_StackOverflowError_Class;
+
p_TLS_vmthread->restore_guard_page = true;
+ exc_clss = env->java_lang_StackOverflowError_Class;
+ if (in_java) {
+ // stack overflow occured in java code:
+ // nothing special to do
+ } else if (is_unwindable()) {
+ // stack overflow occured in native code that can be unwound
+ // safely.
+ // Throwing exception requires suspend disabled status
+ if (hythread_is_suspend_enabled())
+ hythread_suspend_disable();
+ } else {
+ // stack overflow occured in native code that
+ // cannot be unwound.
+ // Mark raised exception in TLS and resume execution
+ exn_raise_by_class(env->java_lang_StackOverflowError_Class);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
}
break;
case STATUS_ACCESS_VIOLATION:
- // null pointer exception -- see ...\vc\include\winnt.h
{
TRACE2("signals",
("NullPointerException detected at eip = %p", context->Eip));
- // Lazy exception object creation
exc_clss = env->java_lang_NullPointerException_Class;
}
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
- // divide by zero exception -- see ...\vc\include\winnt.h
{
TRACE2("signals",
("ArithmeticException detected at eip = %p", context->Eip));
- // Lazy exception object creation
exc_clss = env->java_lang_ArithmeticException_Class;
}
break;
@@ -470,13 +447,15 @@ static LONG NTAPI vectored_exception_han
else
return EXCEPTION_CONTINUE_SEARCH;
}
- default: assert(false);
+ default:
+ // unexpected hardware exception occured in java code
+ return EXCEPTION_CONTINUE_SEARCH;
}
- // we must not call potentially blocking or suspendable
- // code (e.g. java code) from exception handler, because
- // this handler may holds a system-wide lock, and thus
- // may lead to a deadlock.
+ // we must not call potentially blocking or suspendable code
+ // (i.e. java code of exception constructor) from exception
+ // handler, because this handler may holds a system-wide lock,
+ // and thus may lead to a deadlock.
// it was reported that exception handler grabs a system
// lock on Windows XPsp2 and 2003sp0, but not on a 2003sp1
--
1.4.4.1.g2d57