You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2006/09/23 15:07:45 UTC
svn commit: r449228 - in /incubator/harmony/enhanced/drlvm/trunk/vm/vmcore:
include/jvmti_direct.h include/vm_threads.h src/jvmti/jvmti_break.cpp
src/util/linux/signals_ia32.cpp src/util/win/ia32/nt_exception_filter.cpp
Author: geirm
Date: Sat Sep 23 06:07:44 2006
New Revision: 449228
URL: http://svn.apache.org/viewvc?view=rev&rev=449228
Log:
HARMONY-1541
The current implementation of JVMTI breakpoints invokes agent from inside of exception (on Windows) or signal (on
Linux) handler. This usually works but may cause problems if for example agent decides to stop the thread with
breakpoint for some long time. On Windows exception handler cannot be invoked by another thread until other exception
handler is running. This may cause dead locks with any exception happening in other threads, e.g. C++ exceptions on
windows are done through the same mechanism. On Linux calling arbitrary functions from inside of signal handler may
not work as well.
The solution for this problem is if JVMTI sees that happened breakpoint is actually set by JVMTI, for processing it
it should exit the handler. In order to start breakpoint processing the handler exit IP is changed from the IP
pointing to the interrupted location to the JVMTI processing handler. Then exception/signal handler exits and makes
the kernel happy while execution is transferred to JVMTI breakpoints handler. This also is done while holding
breakpoints list lock so that no intermittent modification, like removing the breakpoin which caused exception is
possible.
Ubuntu 6 - smoke, c-unit, kernel
Modified:
incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/jvmti_direct.h
incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_threads.h
incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_break.cpp
incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/linux/signals_ia32.cpp
incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
Modified: incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/jvmti_direct.h
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/jvmti_direct.h?view=diff&rev=449228&r1=449227&r2=449228
==============================================================================
--- incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/jvmti_direct.h (original)
+++ incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/jvmti_direct.h Sat Sep 23 06:07:44 2006
@@ -110,7 +110,7 @@
void jvmti_send_class_prepare_event(Class* clss);
VMEXPORT void jvmti_send_thread_start_end_event(int is_start);
void jvmti_send_vm_death_event();
-bool jvmti_send_jit_breakpoint_event(Registers *regs);
+bool jvmti_jit_breakpoint_handler(Registers *regs);
#ifdef __cplusplus
}
Modified: incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_threads.h
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_threads.h?view=diff&rev=449228&r1=449227&r2=449228
==============================================================================
--- incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_threads.h (original)
+++ incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/include/vm_threads.h Sat Sep 23 06:07:44 2006
@@ -103,6 +103,7 @@
jbyte jvmti_jit_breakpoints_handling_buffer[50];
jvmti_frame_pop_listener *frame_pop_listener;
JVMTISingleStepState *ss_state;
+ Registers jvmti_saved_exception_registers;
// CPU registers.
Registers regs;
Modified: incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_break.cpp
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_break.cpp?view=diff&rev=449228&r1=449227&r2=449228
==============================================================================
--- incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_break.cpp (original)
+++ incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_break.cpp Sat Sep 23 06:07:44 2006
@@ -35,6 +35,7 @@
#include "encoder.h"
#include "m2n.h"
#include "exceptions.h"
+#include "stack_iterator.h"
#define INSTRUMENTATION_BYTE_HLT 0xf4 // HLT instruction
@@ -175,35 +176,29 @@
return ss_breakpoint;
} // jvmti_check_and_get_single_step_breakpoint
-bool jvmti_send_jit_breakpoint_event(Registers *regs)
+static void jvmti_send_jit_breakpoint_event(void)
{
+ // When we get here we know already that breakpoint occurred in JITted code,
+ // JVMTI handles it, and registers context is saved for us in TLS
+ VM_thread *vm_thread = p_TLS_vmthread;
+ Registers regs = vm_thread->jvmti_saved_exception_registers;
+
#if PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3
// Int3 exception address points to the instruction after it
- NativeCodePtr native_location = (NativeCodePtr)(((POINTER_SIZE_INT)regs->get_ip()) - 1);
+ NativeCodePtr native_location = (NativeCodePtr)(((POINTER_SIZE_INT)regs.get_ip()) - 1);
#else
- NativeCodePtr native_location = (NativeCodePtr)regs->get_ip();
+ NativeCodePtr native_location = (NativeCodePtr)regs.get_ip();
#endif
- TRACE2("jvmti.break", "BREAKPOINT occured: " << native_location);
-
DebugUtilsTI *ti = VM_Global_State::loader_env->TI;
- if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE)
- return false;
-
- ti->brkpntlst_lock._lock();
BreakPoint *bp = ti->find_first_bpt(native_location);
- if (NULL == bp)
- {
- ti->brkpntlst_lock._unlock();
- return false;
- }
-
+ assert(bp);
assert(ti->isEnabled());
assert(!interpreter_enabled());
+ assert(ti->getPhase() == JVMTI_PHASE_LIVE);
- Registers orig_regs = *regs;
-
- M2nFrame *m2nf = m2n_push_suspended_frame(&orig_regs);
+ M2nFrame *m2nf = m2n_push_suspended_frame(®s);
+ jbyte *instruction_buffer;
BEGIN_RAISE_AREA;
// need to be able to pop the frame
@@ -224,7 +219,6 @@
InstructionDisassembler idisasm(*bp->disasm);
JNIEnv *jni_env = (JNIEnv *)jni_native_intf;
- VM_thread *vm_thread = p_TLS_vmthread;
BreakPoint *ss_breakpoint = jvmti_check_and_get_single_step_breakpoint( ti,
vm_thread, native_location );
// Check if there are Single Step type breakpoints in TLS
@@ -387,7 +381,7 @@
// special handling.
InstructionDisassembler::Type type = idisasm.get_type();
- jbyte *instruction_buffer = vm_thread->jvmti_jit_breakpoints_handling_buffer;
+ instruction_buffer = vm_thread->jvmti_jit_breakpoints_handling_buffer;
jbyte *interrupted_instruction = (jbyte *)native_location;
jint instruction_length = idisasm.get_length_with_prefix();
@@ -456,13 +450,6 @@
}
}
- // Set exception or signal return address to the instruction buffer
-#ifndef _EM64T_
- regs->eip = (POINTER_SIZE_INT)instruction_buffer;
-#else
- regs->rip = (POINTER_SIZE_INT)instruction_buffer;
-#endif
-
// Set breakpoints on bytecodes after the current one
ss_breakpoint = jvmti_check_and_get_single_step_breakpoint( ti,
vm_thread, native_location );
@@ -487,9 +474,60 @@
oh_discard_local_handle(hThread);
END_RAISE_AREA;
+
+ // This function does not return. It restores register context and
+ // transfers execution control to the instruction buffer to
+ // execute the original instruction with the registers which it
+ // had before breakpoint happened
+ StackIterator *si = si_create_from_registers(®s, false, m2n_get_previous_frame(m2nf));
+
m2n_set_last_frame(m2n_get_previous_frame(m2nf));
STD_FREE(m2nf);
+ si_set_ip(si, instruction_buffer, false);
+ si_transfer_control(si);
+}
+
+bool jvmti_jit_breakpoint_handler(Registers *regs)
+{
+#if PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3
+ // Int3 exception address points to the instruction after it
+ NativeCodePtr native_location = (NativeCodePtr)(((POINTER_SIZE_INT)regs->get_ip()) - 1);
+#else
+ NativeCodePtr native_location = (NativeCodePtr)regs->get_ip();
+#endif
+
+ TRACE2("jvmti.break", "BREAKPOINT occured: " << native_location);
+
+ DebugUtilsTI *ti = VM_Global_State::loader_env->TI;
+ if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE)
+ return false;
+
+ ti->brkpntlst_lock._lock();
+ BreakPoint *bp = ti->find_first_bpt(native_location);
+ if (NULL == bp)
+ {
+ ti->brkpntlst_lock._unlock();
+ return false;
+ }
+
+ assert(ti->isEnabled());
+ assert(!interpreter_enabled());
+
+ // Now it is necessary to set up a transition to
+ // jvmti_send_jit_breakpoint_event from the exception/signal
+ // handler
+ VM_thread *vm_thread = p_TLS_vmthread;
+ // Copy original registers to TLS
+ vm_thread->jvmti_saved_exception_registers = *regs;
+#ifndef _EM64T_
+ regs->eip = (POINTER_SIZE_INT)jvmti_send_jit_breakpoint_event;
+#else
+ regs->rip = (POINTER_SIZE_INT)jvmti_send_jit_breakpoint_event;
+#endif
+
+ // Breakpoints list lock is not released until it is unlocked
+ // inside of jvmti_send_jit_breakpoint_event
return true;
}
Modified: incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/linux/signals_ia32.cpp
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/linux/signals_ia32.cpp?view=diff&rev=449228&r1=449227&r2=449228
==============================================================================
--- incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/linux/signals_ia32.cpp (original)
+++ incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/linux/signals_ia32.cpp Sat Sep 23 06:07:44 2006
@@ -494,7 +494,7 @@
(void *)regs.eip);
assert(!interpreter_enabled());
- bool handled = jvmti_send_jit_breakpoint_event(®s);
+ bool handled = jvmti_jit_breakpoint_handler(®s);
if (handled)
{
linux_regs_to_ucontext(uc, ®s);
Modified: incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp?view=diff&rev=449228&r1=449227&r2=449228
==============================================================================
--- incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp (original)
+++ incubator/harmony/enhanced/drlvm/trunk/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp Sat Sep 23 06:07:44 2006
@@ -418,7 +418,7 @@
nt_to_vm_context(context, ®s);
TRACE2("signals", "JVMTI breakpoint detected at " <<
(void *)regs.eip);
- bool handled = jvmti_send_jit_breakpoint_event(®s);
+ bool handled = jvmti_jit_breakpoint_handler(®s);
if (handled)
{
vm_to_nt_context(®s, context);