diff --git a/vm/vmcore/include/jvmti_break_intf.h b/vm/vmcore/include/jvmti_break_intf.h index 725d899..07e48a0 100755 --- a/vm/vmcore/include/jvmti_break_intf.h +++ b/vm/vmcore/include/jvmti_break_intf.h @@ -1,179 +1,204 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision$ - */ -/** - * @file jvmti_break_intf.h - * @brief JVMTI native breakpoints API - */ -#if !defined(__JVMTI_BREAK_INTF_H__) -#define __JVMTI_BREAK_INTF_H__ - -#include "open/types.h" -#include "jni.h" -#include "lock_manager.h" -#include "jvmti_dasm.h" -#include "environment.h" - - -class VmBrkptIntf; -struct VmBrkpt; -struct VmBrkptRef; - -// Callbacks are called for interfaces according to its priority -#define BREAK_MAX_PRIORITY 0 -#define BREAK_MIN_PRIORITY 1 - -// Pointer to interface callback function -typedef bool (*fn_interface_callback)(VmBrkptIntf* intf, VmBrkptRef* bp_ref); - -class VmBreakpoints -{ -public: - VmBreakpoints(); - ~VmBreakpoints(); - - void lock() {m_lock._lock();} - void unlock() {m_lock._unlock();} - // Is used for LMAutoUnlock - Lock_Manager* get_lock() - {return &this->m_lock;} - - // Returns interface for breakpoint handling - VmBrkptIntf* query_intf(fn_interface_callback callback, bool is_interp); - // Destroys interface and deletes all its breakpoints - void release_intf(VmBrkptIntf* intf); - - // Inserts breakpoint into global list and performs instrumentation - bool insert_breakpoint(VmBrkpt* brpt); - // Removes breakpoint from global list and restores instrumented area - bool remove_breakpoint(VmBrkpt* brpt); - - // Search operations - VmBrkpt* find_breakpoint(jmethodID method, jlocation location); - VmBrkpt* find_breakpoint(NativeCodePtr addr); - VmBrkpt* find_next_breakpoint(VmBrkpt* prev, NativeCodePtr addr); - - // Search breakpoints for given method - bool has_breakpoint(jmethodID method); - VmBrkpt* find_first(jmethodID method); - VmBrkpt* find_next(VmBrkpt* prev, jmethodID method); - - // Checks if given breakpoint is set by other interfaces - VmBrkptRef* find_other(VmBrkptIntf* intf, jmethodID method, jlocation location); - VmBrkptRef* find_other(VmBrkptIntf* intf, NativeCodePtr addr); - VmBrkptRef* find_other(VmBrkptIntf* intf, VmBrkpt* brpt); - - // General callback functions - void process_native_breakpoint(); - jbyte process_interpreter_breakpoint(jmethodID method, jlocation location); - -protected: - void clear_processed_flags(); - VmBrkptIntf* get_intf_to_process(int priority); - -protected: - VmBrkptIntf* m_intf_list; - VmBrkpt* m_brpt_list; - - Lock_Manager m_lock; -}; - -class VmBrkptIntf -{ - friend class VmBreakpoints; - -public: - void lock(); - void unlock(); - Lock_Manager* get_lock(); - - // Default is BREAK_MIN_PRIORITY - bool set_priority(int priority); - int get_priority() const { return m_priority; } - - // Iteration - VmBrkptRef* get_first(); - VmBrkptRef* get_next(VmBrkptRef* prev); - - // Basic operations - - // 'data' must be allocated with JVMTI Allocate (or internal _allocate) - // Users must not deallocate 'data', it will be deallocated by 'remove' - VmBrkptRef* add(jmethodID method, jlocation location, void* data); - // To specify address explicitly - VmBrkptRef* add(jmethodID method, jlocation location, - NativeCodePtr addr, void* data); - VmBrkptRef* add(NativeCodePtr addr, void* data); - bool remove(VmBrkptRef* ref); - VmBrkptRef* find(jmethodID method, jlocation location); - VmBrkptRef* find(NativeCodePtr addr); - VmBrkptRef* find(VmBrkpt* brpt); - void remove_all(); - -protected: - VmBrkptIntf(fn_interface_callback callback, bool is_interp); - VmBrkptIntf(); - ~VmBrkptIntf(); - - void set_processed(bool processed) { m_processed = processed; } - bool is_processed() const { return (m_processed == true); } - -protected: - VmBrkptRef* m_list; - fn_interface_callback m_callback; - bool m_is_interp; - int m_priority; - bool m_processed; - - VmBrkptIntf* m_next; -}; - -struct VmBrkpt -{ - bool is_interp; - NativeCodePtr addr; - jmethodID method; - jlocation location; - jbyte saved_byte; - InstructionDisassembler* disasm; - - VmBrkpt* next; -}; - -// Breakpoint reference -struct VmBrkptRef -{ - VmBrkpt* brpt; - void* data; - - VmBrkptRef* next; -}; - - -// Callback function for native breakpoint processing -bool jvmti_jit_breakpoint_handler(Registers *regs); - -// Callback function for interpreter breakpoint processing -VMEXPORT jbyte -jvmti_process_interpreter_breakpoint_event(jmethodID method, jlocation location); - -// Callback for JIT method compile -void jvmti_set_pending_breakpoints(Method *method); - -#endif // __JVMTI_BREAK_INTF_H__ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision$ + */ +/** + * @file jvmti_break_intf.h + * @brief JVMTI native breakpoints API + */ +#if !defined(__JVMTI_BREAK_INTF_H__) +#define __JVMTI_BREAK_INTF_H__ + +#include "open/types.h" +#include "jni.h" +#include "lock_manager.h" +#include "jvmti_dasm.h" +#include "environment.h" + +// Callbacks are called for interfaces according to its priority +typedef enum { + PRIORITY_SINGLE_STEP_BREAKPOINT = 0, + PRIORITY_SIMPLE_BREAKPOINT, + PRIORITY_NUMBER +} jvmti_BreakPriority; + +class VMBreakInterface; + +struct VMBreakPoint +{ + InstructionDisassembler* disasm; + VMBreakPoint* next; + NativeCodePtr addr; + jlocation location; + jmethodID method; + jbyte saved_byte; + bool is_interp; + bool is_processed; +}; + +// Breakpoint reference +struct VMBreakPointRef +{ + VMBreakPoint* brpt; + void* data; + VMBreakPointRef* next; +}; + +// Pointer to interface callback function +typedef bool (*BPInterfaceCallBack)(VMBreakInterface* intf, VMBreakPointRef* bp_ref); + +class VMBreakPoints +{ +public: + VMBreakPoints() : m_break(NULL) + { + for(unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + m_intf[index] = NULL; + } + } + + ~VMBreakPoints(); + + void lock() {m_lock._lock();} + void unlock() {m_lock._unlock();} + // Is used for LMAutoUnlock + Lock_Manager* get_lock() {return &m_lock;} + + // Returns interface for breakpoint handling + VMBreakInterface* new_intf(BPInterfaceCallBack callback, + unsigned priority, bool is_interp); + // Destroys interface and deletes all its breakpoints + void release_intf(VMBreakInterface* intf); + + // Checks breakpoint before inserting + bool check_insert_breakpoint(VMBreakPoint* bp); + // Inserts breakpoint into global list and performs instrumentation + bool insert_breakpoint(VMBreakPoint* brpt); + // Removes breakpoint from global list and restores instrumented area + bool remove_breakpoint(VMBreakPoint* brpt); + + // Search operations + VMBreakPoint* find_breakpoint(jmethodID method, jlocation location); + VMBreakPoint* find_breakpoint(NativeCodePtr addr); + VMBreakPoint* find_other_breakpoint_with_same_addr(VMBreakPoint* bp); + VMBreakPoint* find_next_breakpoint(VMBreakPoint* prev, NativeCodePtr addr); + + // Search breakpoints for given method + bool has_breakpoint(jmethodID method); + VMBreakPoint* find_first(jmethodID method); + VMBreakPoint* find_next(VMBreakPoint* prev, jmethodID method); + + // Checks if given breakpoint is set by other interfaces + VMBreakPointRef* find_other_reference(VMBreakInterface* intf, + jmethodID method, jlocation location); + VMBreakPointRef* find_other_reference(VMBreakInterface* intf, + NativeCodePtr addr); + VMBreakPointRef* find_other_reference(VMBreakInterface* intf, + VMBreakPoint* brpt); + + // General callback functions + void process_native_breakpoint(); + jbyte process_interpreter_breakpoint(jmethodID method, jlocation location); + +protected: + void clear_breakpoints_processed_flags(); + VMBreakPoint* get_none_processed_breakpoint(NativeCodePtr addr); + void set_breakpoint_processed( VMBreakPoint *bp, bool flag ) + { + bp->is_processed = flag; + } + bool breakpoint_is_processed( VMBreakPoint *bp ) + { + return bp->is_processed == true; + } + + void clear_intfs_processed_flags(); + VMBreakInterface* get_none_processed_intf(unsigned priority); + +private: + VMBreakInterface* m_intf[PRIORITY_NUMBER]; + VMBreakPoint* m_break; + Lock_Manager m_lock; +}; + +class VMBreakInterface +{ + friend class VMBreakPoints; + +public: + void lock() {VM_Global_State::loader_env->TI->vm_brpt->lock();} + void unlock() {VM_Global_State::loader_env->TI->vm_brpt->unlock();} + Lock_Manager* get_lock() + {return VM_Global_State::loader_env->TI->vm_brpt->get_lock();} + + int get_priority() const { return m_priority; } + + // Iteration + VMBreakPointRef* get_first() { return m_list; } + VMBreakPointRef* get_next(VMBreakPointRef* prev) + { + assert(prev); + return prev->next; + } + + // Basic operations + + // 'data' must be allocated with JVMTI Allocate (or internal _allocate) + // Users must not deallocate 'data', it will be deallocated by 'remove' + VMBreakPointRef* add(jmethodID method, jlocation location, void* data); + // To specify address explicitly + VMBreakPointRef* add(jmethodID method, jlocation location, + NativeCodePtr addr, void* data); + VMBreakPointRef* add(NativeCodePtr addr, void* data); + + void remove_all(); + bool remove(VMBreakPointRef* ref); + + VMBreakPointRef* find(jmethodID method, jlocation location); + VMBreakPointRef* find(NativeCodePtr addr); + VMBreakPointRef* find(VMBreakPoint* brpt); + +protected: + VMBreakInterface(BPInterfaceCallBack callback, unsigned priority, bool is_interp) + : m_list(NULL), m_callback(callback), m_priority(priority), + m_next(NULL), m_processed(false), m_is_interp(is_interp) {} + ~VMBreakInterface() { remove_all(); } + + void set_processed(bool processed) { m_processed = processed; } + bool is_processed() const { return (m_processed == true); } + VMBreakInterface* m_next; + +private: + VMBreakPointRef* m_list; + BPInterfaceCallBack m_callback; + bool m_is_interp; + unsigned m_priority; + bool m_processed; +}; + +// Callback function for native breakpoint processing +bool jvmti_jit_breakpoint_handler(Registers *regs); + +// Callback function for interpreter breakpoint processing +VMEXPORT jbyte +jvmti_process_interpreter_breakpoint_event(jmethodID method, jlocation location); + +// Callback for JIT method compile +void jvmti_set_pending_breakpoints(Method *method); + +#endif // __JVMTI_BREAK_INTF_H__ diff --git a/vm/vmcore/include/jvmti_dasm.h b/vm/vmcore/include/jvmti_dasm.h index 15a4aac..a31fcec 100644 --- a/vm/vmcore/include/jvmti_dasm.h +++ b/vm/vmcore/include/jvmti_dasm.h @@ -32,7 +32,7 @@ class InstructionDisassembler { public: enum Type { - OPCODEERROR, + OPCODEERROR = 0, UNKNOWN, OTHER=UNKNOWN, RELATIVE_JUMP, @@ -72,7 +72,8 @@ public: }; - InstructionDisassembler(NativeCodePtr address) + InstructionDisassembler(NativeCodePtr address) : + type(OPCODEERROR), target(0), len(0), cond_jump_type(JUMP_OVERFLOW) { disasm(address, this); } diff --git a/vm/vmcore/include/jvmti_direct.h b/vm/vmcore/include/jvmti_direct.h index f1195dc..b6855f0 100644 --- a/vm/vmcore/include/jvmti_direct.h +++ b/vm/vmcore/include/jvmti_direct.h @@ -32,7 +32,7 @@ struct TIEventThread struct Agent; extern Agent *current_loading_agent; -class VmBrkptIntf; +class VMBreakInterface; /* * Type that describes TI environment created by GetEnv function @@ -46,7 +46,7 @@ struct TIEnv jvmtiEventCallbacks event_table; jvmtiExtensionEvent *extension_event_table; jvmtiCapabilities posessed_capabilities; - VmBrkptIntf *brpt_intf; + VMBreakInterface *brpt_intf; TIEnv* next; bool global_events[JVMTI_MAX_EVENT_TYPE_VAL - JVMTI_MIN_EVENT_TYPE_VAL]; diff --git a/vm/vmcore/include/jvmti_internal.h b/vm/vmcore/include/jvmti_internal.h index c5b1e54..2fe8d5d 100644 --- a/vm/vmcore/include/jvmti_internal.h +++ b/vm/vmcore/include/jvmti_internal.h @@ -91,7 +91,7 @@ struct jvmti_StepLocation struct JVMTISingleStepState { - VmBrkptIntf* predicted_breakpoints; + VMBreakInterface* predicted_breakpoints; }; /* @@ -145,8 +145,8 @@ public: }; typedef struct Class Class; -class VmBreakpoints; -struct VmBrkptRef; +class VMBreakPoints; +struct VMBreakPointRef; /* * JVMTI state of the VM @@ -156,7 +156,7 @@ class DebugUtilsTI { jint agent_counter; Lock_Manager TIenvs_lock; Lock_Manager dcList_lock; - VmBreakpoints* vm_brpt; + VMBreakPoints* vm_brpt; DebugUtilsTI(); @@ -346,8 +346,8 @@ jint load_agentlib(Agent *agent, const c jint load_agentpath(Agent *agent, const char *str, JavaVM_Internal *vm); // Breakpoints internal functions -jvmtiError jvmti_get_next_bytecodes_stack_from_native(VM_thread *thread, - jvmti_StepLocation **next_step, unsigned *count, bool step_up); +jvmtiError jvmti_get_next_bytecodes_from_native(VM_thread *thread, + jvmti_StepLocation **next_step, unsigned *count, bool stack_step_up); void jvmti_set_single_step_breakpoints(DebugUtilsTI *ti, VM_thread *vm_thread, jvmti_StepLocation *locations, unsigned locations_number); @@ -366,6 +366,6 @@ void jvmti_SingleStepLocation(VM_thread* unsigned location, jvmti_StepLocation **next_step, unsigned *count); // Callback function for JVMTI breakpoint processing -bool jvmti_process_breakpoint_event(VmBrkptIntf* intf, VmBrkptRef* bp_ref); +bool jvmti_process_breakpoint_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref); #endif /* _JVMTI_INTERNAL_H_ */ diff --git a/vm/vmcore/src/jvmti/jvmti.cpp b/vm/vmcore/src/jvmti/jvmti.cpp index 87a6c61..803f091 100644 --- a/vm/vmcore/src/jvmti/jvmti.cpp +++ b/vm/vmcore/src/jvmti/jvmti.cpp @@ -266,8 +266,9 @@ jint JNICALL create_jvmti_environment(Ja // Acquire interface for breakpoint handling newenv->brpt_intf = - vm->vm_env->TI->vm_brpt->query_intf(jvmti_process_breakpoint_event, - interpreter_enabled()); + vm->vm_env->TI->vm_brpt->new_intf(jvmti_process_breakpoint_event, + PRIORITY_SIMPLE_BREAKPOINT, + interpreter_enabled()); LMAutoUnlock lock(&vm->vm_env->TI->TIenvs_lock); vm->vm_env->TI->addEnvironment(newenv); @@ -312,7 +313,7 @@ DebugUtilsTI::DebugUtilsTI() : res = _allocate( MAX_NOTIFY_LIST * sizeof(Class**), (unsigned char**)¬ifyPrepareList ); assert(res == JVMTI_ERROR_NONE); - vm_brpt = new VmBreakpoints(); + vm_brpt = new VMBreakPoints(); assert(vm_brpt); return; } diff --git a/vm/vmcore/src/jvmti/jvmti_break.cpp b/vm/vmcore/src/jvmti/jvmti_break.cpp index 0b85636..e69fee0 100644 --- a/vm/vmcore/src/jvmti/jvmti_break.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break.cpp @@ -37,12 +37,16 @@ #include "open/hythread_ext.h" // Callback function for JVMTI breakpoint processing -bool jvmti_process_breakpoint_event(VmBrkptIntf* intf, VmBrkptRef* bp_ref) +bool jvmti_process_breakpoint_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref) { - VmBrkpt* bp = bp_ref->brpt; + VMBreakPoint* bp = bp_ref->brpt; assert(bp); - TRACE2("jvmti.break", "BREAKPOINT occured: location=" << bp->location); + TRACE2("jvmti.break", "Process breakpoint: " + << class_get_name(method_get_class((Method*)bp->method)) << "." + << method_get_name((Method*)bp->method) + << method_get_descriptor((Method*)bp->method) + << " :" << bp->location << " :" << bp->addr); DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE) @@ -135,7 +139,11 @@ jvmtiSetBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) { - TRACE2("jvmti.break", "SetBreakpoint called, method = " << method << " , location = " << location); + TRACE2("jvmti.break", "SetBreakpoint is called for method: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location); SuspendEnabledChecker sec; jvmtiError errorCode; @@ -181,10 +189,10 @@ #endif return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; TIEnv *p_env = (TIEnv *)env; - VmBrkptIntf* brpt_intf = p_env->brpt_intf; + VMBreakInterface* brpt_intf = p_env->brpt_intf; LMAutoUnlock lock(brpt_intf->get_lock()); - VmBrkptRef* bp = brpt_intf->find(method, location); + VMBreakPointRef* bp = brpt_intf->find(method, location); if (NULL != bp) return JVMTI_ERROR_DUPLICATE; @@ -202,7 +210,7 @@ #endif return JVMTI_ERROR_INTERNAL; } - TRACE2("jvmti.break", "SetBreakpoint successfull"); + TRACE2("jvmti.break", "SetBreakpoint is successfull"); return JVMTI_ERROR_NONE; } @@ -219,7 +227,11 @@ jvmtiClearBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) { - TRACE2("jvmti.break", "ClearBreakpoint called, method = " << method << " , location = " << location); + TRACE2("jvmti.break", "ClearBreakpoint is called for method: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location); SuspendEnabledChecker sec; jvmtiError errorCode; @@ -265,10 +277,10 @@ #endif return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; TIEnv *p_env = (TIEnv *)env; - VmBrkptIntf* brpt_intf = p_env->brpt_intf; + VMBreakInterface* brpt_intf = p_env->brpt_intf; LMAutoUnlock lock(brpt_intf->get_lock()); - VmBrkptRef* bp = brpt_intf->find(method, location); + VMBreakPointRef* bp = brpt_intf->find(method, location); if (NULL == bp) return JVMTI_ERROR_NOT_FOUND; @@ -276,6 +288,6 @@ #endif if (!brpt_intf->remove(bp)) return JVMTI_ERROR_INTERNAL; - TRACE2("jvmti.break", "ClearBreakpoint successfull"); + TRACE2("jvmti.break", "ClearBreakpoint is successfull"); return JVMTI_ERROR_NONE; } diff --git a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp index 264d3a3..25ef8a1 100755 --- a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp @@ -38,61 +38,53 @@ #include "jvmti_break_intf.h" // Forvard declarations static ConditionCode get_condition_code(InstructionDisassembler::CondJumpType jump_type); -static bool set_jit_mode_breakpoint(VmBreakpoints* vm_brpt, VmBrkpt* bp); -static bool set_native_breakpoint(VmBrkpt* bp); -static bool clear_native_breakpoint(VmBrkpt* bp); +static bool set_jit_mode_breakpoint(VMBreakPoints* vm_brpt, VMBreakPoint* bp); +static bool set_native_breakpoint(VMBreakPoint* bp); +static bool clear_native_breakpoint(VMBreakPoint* bp); ////////////////////////////////////////////////////////////////////////////// -// VmBreakpoints implementation -VmBreakpoints::VmBreakpoints(): - m_intf_list(NULL), m_brpt_list(NULL) -{} - -VmBreakpoints::~VmBreakpoints() +// VMBreakPoints implementation +VMBreakPoints::~VMBreakPoints() { lock(); - - while (m_intf_list) - { - VmBrkptIntf* next = m_intf_list->m_next; - delete m_intf_list; - m_intf_list = next; + for(unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + while (m_intf[index]) { + VMBreakInterface* intf = m_intf[index]; + m_intf[index] = intf->m_next; + delete intf; + } } - - assert(m_brpt_list == NULL); - + assert(m_break == NULL); unlock(); } - -VmBrkptIntf* VmBreakpoints::query_intf(fn_interface_callback callback, - bool is_interp) +VMBreakInterface* +VMBreakPoints::new_intf(BPInterfaceCallBack callback, + unsigned priority, + bool is_interp) { - if (!callback) - return NULL; - - VmBrkptIntf* intf = - new VmBrkptIntf(callback, is_interp); - - if (!intf) - return NULL; + assert(callback); + assert(priority < PRIORITY_NUMBER); + VMBreakInterface* intf = new VMBreakInterface(callback, priority, is_interp); + assert(intf); lock(); - intf->m_next = m_intf_list; - m_intf_list = intf; + intf->m_next = m_intf[priority]; + m_intf[priority] = intf; unlock(); return intf; } -void VmBreakpoints::release_intf(VmBrkptIntf* intf) +void +VMBreakPoints::release_intf(VMBreakInterface* intf) { assert(intf); - + assert(intf->get_priority() < PRIORITY_NUMBER); LMAutoUnlock lock(get_lock()); - for (VmBrkptIntf** cur_ptr = &m_intf_list; + for (VMBreakInterface** cur_ptr = &m_intf[intf->get_priority()]; *cur_ptr; cur_ptr = &((*cur_ptr)->m_next)) { if (*cur_ptr == intf) @@ -103,14 +95,69 @@ void VmBreakpoints::release_intf(VmBrkpt return; } } + DIE2("jvmti.break", "VMBreakPoints::release_intf: try to release unknown interface"); } -bool VmBreakpoints::insert_breakpoint(VmBrkpt* brpt) +inline bool +VMBreakPoints::check_insert_breakpoint(VMBreakPoint* bp) { - assert(brpt); - assert(!brpt->method || !find_breakpoint(brpt->method, brpt->location)); - assert(brpt->method || (brpt->addr && (!find_breakpoint(brpt->addr) || find_breakpoint(brpt->addr)->method))); +#ifndef NDEBUG + if( !bp ) { + return false; + } else if( bp->method ) { + TRACE2("jvmti.break", "Try to insert breakpoint: " + << class_get_name(method_get_class((Method*)bp->method)) << "." + << method_get_name((Method*)bp->method) + << method_get_descriptor((Method*)bp->method) + << " :" << bp->location << " :" << bp->addr); + + VMBreakPoint* another = find_breakpoint(bp->method, bp->location); + if( !another ) { + return true; + } + TRACE2("jvmti.break", "Before inserting found another breakpoint: " + << (another->method + ? class_get_name(method_get_class((Method*)another->method)): "(nil)") + << "." + << (another->method ? method_get_name((Method*)another->method) : "(nil)") + << (another->method ? method_get_descriptor((Method*)another->method) : "(nil)") + << " :" << another->location << " :" << another->addr); + + if( bp->addr == another->addr) { + return false; + } + } else if( bp->addr ) { + TRACE2("jvmti.break", "Try to insert breakpoint: native address:" + << bp->addr); + + VMBreakPoint* another = find_breakpoint(bp->addr); + if( !another ) { + return true; + } + + TRACE2("jvmti.break", "Before inserting found another breakpoint: " + << (another->method + ? class_get_name(method_get_class((Method*)another->method)) :"(nil)") + << "." + << (another->method ? method_get_name((Method*)another->method) :"(nil)") + << (another->method ? method_get_descriptor((Method*)another->method) :"(nil)") + << " :" << another->location << " :" << another->addr); + + if(another->method) { + return false; + } + } else { + return false; + } +#endif // !NDEBUG + return true; +} + +bool +VMBreakPoints::insert_breakpoint(VMBreakPoint* brpt) +{ + check_insert_breakpoint(brpt); if (brpt->is_interp) { assert(interpreter_enabled()); @@ -131,10 +178,11 @@ bool VmBreakpoints::insert_breakpoint(Vm else { assert(brpt->addr == NULL); - TRACE2("jvmti.break.intf", "Skipping setting breakpoing in method " << - m->get_class()->name->bytes << "." << - m->get_name()->bytes << " " << m->get_descriptor()->bytes << - " because it is not compiled yet"); + TRACE2("jvmti.break.intf", "Skipping setting breakpoing in method " + << class_get_name(method_get_class(m)) << "." + << method_get_name(m) + << method_get_descriptor(m) + << " because it is not compiled yet"); m->insert_pending_breakpoint(); } } @@ -144,20 +192,32 @@ bool VmBreakpoints::insert_breakpoint(Vm return false; } } + TRACE2("jvmti.break.intf", "Insert breakpoint: " + << class_get_name(method_get_class((Method*)brpt->method)) << "." + << method_get_name((Method*)brpt->method) + << method_get_descriptor((Method*)brpt->method) + << " :" << brpt->location << " :" << brpt->addr); - brpt->next = m_brpt_list; - m_brpt_list = brpt; + brpt->next = m_break; + m_break = brpt; return true; } -bool VmBreakpoints::remove_breakpoint(VmBrkpt* brpt) +bool +VMBreakPoints::remove_breakpoint(VMBreakPoint* brpt) { assert(brpt); assert(!brpt->method || find_breakpoint(brpt->method, brpt->location)); assert(brpt->method || find_breakpoint(brpt->addr)); - for (VmBrkpt** cur_ptr = &m_brpt_list; + TRACE2("jvmti.break.intf", "Remove breakpoint: " + << class_get_name(method_get_class((Method*)brpt->method)) << "." + << method_get_name((Method*)brpt->method) + << method_get_descriptor((Method*)brpt->method) + << " :" << brpt->location << " :" << brpt->addr); + + for (VMBreakPoint** cur_ptr = &m_break; *cur_ptr; cur_ptr = &(*cur_ptr)->next) { if (*cur_ptr == brpt) @@ -191,9 +251,10 @@ bool VmBreakpoints::remove_breakpoint(Vm return true; } -VmBrkpt* VmBreakpoints::find_breakpoint(jmethodID method, jlocation location) +VMBreakPoint* +VMBreakPoints::find_breakpoint(jmethodID method, jlocation location) { - for (VmBrkpt* brpt = m_brpt_list; brpt; brpt = brpt->next) + for (VMBreakPoint* brpt = m_break; brpt; brpt = brpt->next) { if (brpt->method == method && brpt->location == location) @@ -203,11 +264,12 @@ VmBrkpt* VmBreakpoints::find_breakpoint( return NULL; } -VmBrkpt* VmBreakpoints::find_breakpoint(NativeCodePtr addr) +VMBreakPoint* +VMBreakPoints::find_breakpoint(NativeCodePtr addr) { assert(addr); - for (VmBrkpt* brpt = m_brpt_list; brpt; brpt = brpt->next) + for (VMBreakPoint* brpt = m_break; brpt; brpt = brpt->next) { if (brpt->addr == addr) return brpt; @@ -216,11 +278,27 @@ VmBrkpt* VmBreakpoints::find_breakpoint( return NULL; } -VmBrkpt* VmBreakpoints::find_next_breakpoint(VmBrkpt* prev, NativeCodePtr addr) + +VMBreakPoint* +VMBreakPoints::find_other_breakpoint_with_same_addr(VMBreakPoint* bp) +{ + assert(bp); + + for (VMBreakPoint* other = m_break; other; other = other->next) + { + if (other != bp && other->addr == bp->addr) + return other; + } + + return NULL; +} + +VMBreakPoint* +VMBreakPoints::find_next_breakpoint(VMBreakPoint* prev, NativeCodePtr addr) { assert(addr && prev); - for (VmBrkpt* brpt = prev->next; brpt; brpt = brpt->next) + for (VMBreakPoint* brpt = prev->next; brpt; brpt = brpt->next) { if (brpt->addr == addr) return brpt; @@ -229,16 +307,18 @@ VmBrkpt* VmBreakpoints::find_next_breakp return NULL; } -bool VmBreakpoints::has_breakpoint(jmethodID method) +bool +VMBreakPoints::has_breakpoint(jmethodID method) { return (find_first(method) != NULL); } -VmBrkpt* VmBreakpoints::find_first(jmethodID method) +VMBreakPoint* +VMBreakPoints::find_first(jmethodID method) { assert(method); - for (VmBrkpt* brpt = m_brpt_list; brpt; brpt = brpt->next) + for (VMBreakPoint* brpt = m_break; brpt; brpt = brpt->next) { if (brpt->method && brpt->method == method) @@ -248,11 +328,12 @@ VmBrkpt* VmBreakpoints::find_first(jmeth return NULL; } -VmBrkpt* VmBreakpoints::find_next(VmBrkpt* prev, jmethodID method) +VMBreakPoint* +VMBreakPoints::find_next(VMBreakPoint* prev, jmethodID method) { assert(prev); - for (VmBrkpt* brpt = prev->next; brpt; brpt = brpt->next) + for (VMBreakPoint* brpt = prev->next; brpt; brpt = brpt->next) { if (brpt->method == method) return brpt; @@ -261,56 +342,65 @@ VmBrkpt* VmBreakpoints::find_next(VmBrkp return NULL; } -VmBrkptRef* VmBreakpoints::find_other(VmBrkptIntf* intf, - jmethodID method, jlocation location) +VMBreakPointRef* +VMBreakPoints::find_other_reference(VMBreakInterface* intf, + jmethodID method, + jlocation location) { assert(intf); - for (VmBrkptIntf* cur = m_intf_list; cur; cur = cur->m_next) - { - if (cur == intf) - continue; + for( unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + for (VMBreakInterface* cur = m_intf[index]; cur; cur = cur->m_next) { + if (cur == intf) + continue; - VmBrkptRef* ref = cur->find(method, location); + VMBreakPointRef* ref = cur->find(method, location); - if (ref) - return ref; + if (ref) + return ref; + } } return NULL; } -VmBrkptRef* VmBreakpoints::find_other(VmBrkptIntf* intf, NativeCodePtr addr) +VMBreakPointRef* +VMBreakPoints::find_other_reference(VMBreakInterface* intf, + NativeCodePtr addr) { assert(intf); - for (VmBrkptIntf* cur = m_intf_list; cur; cur = cur->m_next) - { - if (cur == intf) - continue; + for( unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + for (VMBreakInterface* cur = m_intf[index]; cur; cur = cur->m_next) { + if (cur == intf) + continue; - VmBrkptRef* ref = cur->find(addr); + VMBreakPointRef* ref = cur->find(addr); - if (ref) - return ref; + if (ref) + return ref; + } } return NULL; } -VmBrkptRef* VmBreakpoints::find_other(VmBrkptIntf* intf, VmBrkpt* brpt) +VMBreakPointRef* +VMBreakPoints::find_other_reference(VMBreakInterface* intf, + VMBreakPoint* brpt) { assert(intf); - for (VmBrkptIntf* cur = m_intf_list; cur; cur = cur->m_next) - { - if (cur == intf) - continue; + for( unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + for (VMBreakInterface* cur = m_intf[index]; cur; cur = cur->m_next) { + if (cur == intf) + continue; - VmBrkptRef* ref = cur->find(brpt); + VMBreakPointRef* ref = cur->find(brpt); - if (ref) - return ref; + if (ref) + return ref; + } } return NULL; @@ -322,7 +412,8 @@ #define INSTRUMENTATION_BYTE_CLI 0xfa // #define INSTRUMENTATION_BYTE_INT3 0xcc // INT 3 instruction #define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_INT3 -void VmBreakpoints::process_native_breakpoint() +void +VMBreakPoints::process_native_breakpoint() { // 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 @@ -331,15 +422,13 @@ void VmBreakpoints::process_native_break #if PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 // Int3 exception address points to the instruction after it - NativeCodePtr addr = - (NativeCodePtr)(((POINTER_SIZE_INT)regs.get_ip()) - 1); -#else + regs.eip -= 1; +#endif // PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 NativeCodePtr addr = (NativeCodePtr)regs.get_ip(); -#endif - TRACE2("jvmti.break.intf", "Native breakpoint occured, location = " << addr); + TRACE2("jvmti.break.intf", "Native breakpoint occured: " << addr); - VmBrkpt* bp = this->find_breakpoint(addr); + VMBreakPoint* bp = find_breakpoint(addr); assert(bp); bool push_frame = (vm_identify_eip(addr) == VM_TYPE_JAVA); @@ -365,18 +454,16 @@ #endif // inside of callbacks InstructionDisassembler idisasm(*bp->disasm); - while (bp) + for (unsigned priority = 0; priority < PRIORITY_NUMBER; priority++) { - VmBrkpt* next_bp = this->find_next_breakpoint(bp, addr); + while( bp = get_none_processed_breakpoint(addr) ) { + set_breakpoint_processed(bp, true); - for (int priority = BREAK_MAX_PRIORITY; - priority <= BREAK_MIN_PRIORITY; priority++) - { - VmBrkptIntf* intf; - - while (NULL != (intf = get_intf_to_process(priority))) + VMBreakInterface* intf; + while( intf = get_none_processed_intf(priority) ) { - VmBrkptRef* ref = intf->find(bp); + intf->set_processed(true); + VMBreakPointRef* ref = intf->find(bp); if (ref && bp->addr != addr) break; // It's another breakpoint now... @@ -384,20 +471,21 @@ #endif if (ref && intf->m_callback != NULL) { TRACE2("jvmti.break.intf", - "Calling native breakpoint callback function, location = " << addr); + "Calling native breakpoint callback function: " + << class_get_name(method_get_class((Method*)bp->method)) << "." + << method_get_name((Method*)bp->method) + << method_get_descriptor((Method*)bp->method) + << " :" << bp->location << " :" << bp->addr ); intf->m_callback(intf, ref); TRACE2("jvmti.break.intf", - "Finished native breakpoint callback function, location = " << addr); + "Finished native breakpoint callback function: " << addr ); } - - intf->set_processed(true); } + clear_intfs_processed_flags(); } - - clear_processed_flags(); - bp = next_bp; + clear_breakpoints_processed_flags(); } // Now we need to return back to normal code execution, it is @@ -498,28 +586,29 @@ #endif si_transfer_control(si); } -jbyte VmBreakpoints::process_interpreter_breakpoint(jmethodID method, jlocation location) +jbyte +VMBreakPoints::process_interpreter_breakpoint(jmethodID method, jlocation location) { - TRACE2("jvmti.break.intf", "Interpreter breakpoint occured, method = " << - method << " location = " << location); + TRACE2("jvmti.break.intf", "Interpreter breakpoint occured: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); assert(interpreter_enabled()); - lock(); - - VmBrkpt* bp = find_breakpoint(method, location); + VMBreakPoint* bp = find_breakpoint(method, location); assert(bp); jbyte orig_byte = bp->saved_byte; - - for (int priority = BREAK_MAX_PRIORITY; - priority <= BREAK_MIN_PRIORITY; priority++) + for (unsigned priority = 0; priority < PRIORITY_NUMBER; priority++) { - VmBrkptIntf* intf; + VMBreakInterface* intf; - while (NULL != (intf = get_intf_to_process(priority))) + while (intf = get_none_processed_intf(priority) ) { - VmBrkptRef* ref = intf->find(bp); + intf->set_processed(true); + VMBreakPointRef* ref = intf->find(bp); if (ref && ( bp->method != method || @@ -530,107 +619,98 @@ jbyte VmBreakpoints::process_interpreter { JNIEnv *jni_env = (JNIEnv *)jni_native_intf; TRACE2("jvmti.break.intf", - "Calling interpreter breakpoint callback function, location = " - << location); + "Calling interpreter breakpoint callback function: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); intf->m_callback(intf, ref); TRACE2("jvmti.break.intf", - "Finished interpreter breakpoint callback function, location = " - << location); + "Finished interpreter breakpoint callback function: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); } - - intf->set_processed(true); } } - clear_processed_flags(); - unlock(); + clear_intfs_processed_flags(); return orig_byte; } -void VmBreakpoints::clear_processed_flags() +void +VMBreakPoints::clear_breakpoints_processed_flags() { - // Must be executed under lock - for (VmBrkptIntf* intf = m_intf_list; intf; intf = intf->m_next) - { - intf->set_processed(false); + LMAutoUnlock lock(get_lock()); + + for(VMBreakPoint *bp = m_break; bp; bp = bp->next ) { + set_breakpoint_processed( bp, false ); } } -VmBrkptIntf* VmBreakpoints::get_intf_to_process(int priority) +VMBreakPoint* +VMBreakPoints::get_none_processed_breakpoint(NativeCodePtr addr) { - // Must be executed under lock - for (VmBrkptIntf* intf = m_intf_list; intf; intf = intf->m_next) + LMAutoUnlock lock(get_lock()); + + for(VMBreakPoint *bp = find_breakpoint(addr); + bp; + bp = find_next_breakpoint(bp, addr) ) { - if (!intf->is_processed() && - intf->get_priority() == priority) - return intf; + if(!breakpoint_is_processed(bp)) { + return bp; + } } return NULL; } - -////////////////////////////////////////////////////////////////////////////// -// VmBrkptIntf implementation -VmBrkptIntf::VmBrkptIntf(fn_interface_callback callback, bool is_interp) - : m_list(NULL), m_callback(callback), m_priority(BREAK_MIN_PRIORITY), - m_next(NULL), m_processed(false), m_is_interp(is_interp) -{} - -VmBrkptIntf::~VmBrkptIntf() -{ - remove_all(); -} - -void VmBrkptIntf::lock() +void +VMBreakPoints::clear_intfs_processed_flags() { - VM_Global_State::loader_env->TI->vm_brpt->lock(); -} + LMAutoUnlock lock(get_lock()); -void VmBrkptIntf::unlock() -{ - VM_Global_State::loader_env->TI->vm_brpt->unlock(); + for(unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { + for (VMBreakInterface* intf = m_intf[index]; intf; intf = intf->m_next) { + intf->set_processed(false); + } + } } -Lock_Manager* VmBrkptIntf::get_lock() +VMBreakInterface* +VMBreakPoints::get_none_processed_intf(unsigned priority) { - return VM_Global_State::loader_env->TI->vm_brpt->get_lock(); -} + LMAutoUnlock lock(get_lock()); -bool VmBrkptIntf::set_priority(int priority) -{ - if (priority < BREAK_MAX_PRIORITY || priority > BREAK_MIN_PRIORITY) - return false; + for (VMBreakInterface* intf = m_intf[priority]; intf; intf = intf->m_next) { + if (!intf->is_processed()) { + assert(intf->get_priority() == priority); + return intf; + } + } - m_priority = priority; - return true; + return NULL; } -VmBrkptRef* VmBrkptIntf::get_first() -{ - return m_list; -} -VmBrkptRef* VmBrkptIntf::get_next(VmBrkptRef* prev) -{ - assert(prev); - return prev->next; -} +////////////////////////////////////////////////////////////////////////////// +// VMBreakInterface implementation -VmBrkptRef* VmBrkptIntf::add(jmethodID method, jlocation location, void* data) +VMBreakPointRef* VMBreakInterface::add(jmethodID method, jlocation location, void* data) { assert(method); assert(!this->find(method, location)); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VmBrkpt* brpt = vm_brpt->find_breakpoint(method, location); + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoint* brpt = vm_brpt->find_breakpoint(method, location); if (!brpt) { - brpt = (VmBrkpt*)STD_MALLOC(sizeof(VmBrkpt)); + brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); brpt->is_interp = m_is_interp; @@ -639,6 +719,7 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m brpt->location = location; brpt->saved_byte = 0; brpt->disasm = NULL; + brpt->is_processed = false; // Insert breakpoint, possibly to the same native address if (!vm_brpt->insert_breakpoint(brpt)) @@ -648,8 +729,8 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m } } - VmBrkptRef* brpt_ref = - (VmBrkptRef*)STD_MALLOC(sizeof(VmBrkptRef)); + VMBreakPointRef* brpt_ref = + (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); assert(brpt_ref); brpt_ref->brpt = brpt; @@ -657,22 +738,31 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m brpt_ref->next = m_list; m_list = brpt_ref; + TRACE2("jvmti.break.intf", "Added ref on breakpoint: " + << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." + << method_get_name((Method*)brpt_ref->brpt->method) + << method_get_descriptor((Method*)brpt_ref->brpt->method) + << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); + return brpt_ref; } -VmBrkptRef* VmBrkptIntf::add(jmethodID method, jlocation location, +VMBreakPointRef* VMBreakInterface::add(jmethodID method, jlocation location, NativeCodePtr addr, void* data) { assert(method); assert(!this->find(method, location)); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VmBrkpt* brpt = vm_brpt->find_breakpoint(method, location); - assert(!brpt || !brpt->addr || !addr || brpt->addr == addr); + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoint* brpt = vm_brpt->find_breakpoint(method, location); - if (!brpt) + // If breakpoint with the same method location is not found or + // given native address is differ with obtained breapoint. + // The last case cound be if the same method location points + // to different native address. + if ( !brpt || !brpt->addr || brpt->addr != addr ) { - brpt = (VmBrkpt*)STD_MALLOC(sizeof(VmBrkpt)); + brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); brpt->is_interp = m_is_interp; @@ -681,6 +771,7 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m brpt->location = location; brpt->saved_byte = 0; brpt->disasm = NULL; + brpt->is_processed = false; if (!vm_brpt->insert_breakpoint(brpt)) { @@ -689,8 +780,8 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m } } - VmBrkptRef* brpt_ref = - (VmBrkptRef*)STD_MALLOC(sizeof(VmBrkptRef)); + VMBreakPointRef* brpt_ref = + (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); assert(brpt_ref); brpt_ref->brpt = brpt; @@ -698,25 +789,27 @@ VmBrkptRef* VmBrkptIntf::add(jmethodID m brpt_ref->next = m_list; m_list = brpt_ref; + TRACE2("jvmti.break.intf", "Added ref on breakpoint: " + << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." + << method_get_name((Method*)brpt_ref->brpt->method) + << method_get_descriptor((Method*)brpt_ref->brpt->method) + << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); + return brpt_ref; } -VmBrkptRef* VmBrkptIntf::add(NativeCodePtr addr, void* data) +VMBreakPointRef* VMBreakInterface::add(NativeCodePtr addr, void* data) { assert(addr); assert(!this->m_is_interp); assert(!this->find(addr)); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VmBrkpt* brpt; - // Look for native breakpoint (with method == NULL) - for (brpt = vm_brpt->find_breakpoint(addr); - brpt && brpt->method; - brpt = vm_brpt->find_next_breakpoint(brpt, addr)); + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoint* brpt = vm_brpt->find_breakpoint(addr); if (!brpt) { - brpt = (VmBrkpt*)STD_MALLOC(sizeof(VmBrkpt)); + brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); brpt->is_interp = m_is_interp; // false @@ -725,6 +818,7 @@ VmBrkptRef* VmBrkptIntf::add(NativeCodeP brpt->location = 0; brpt->saved_byte = 0; brpt->disasm = NULL; + brpt->is_processed = false; // Insert breakpoint, possibly duplicating breakpoint with method != NULL if (!vm_brpt->insert_breakpoint(brpt)) @@ -734,8 +828,8 @@ VmBrkptRef* VmBrkptIntf::add(NativeCodeP } } - VmBrkptRef* brpt_ref = - (VmBrkptRef*)STD_MALLOC(sizeof(VmBrkptRef)); + VMBreakPointRef* brpt_ref = + (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); assert(brpt_ref); brpt_ref->brpt = brpt; @@ -743,17 +837,29 @@ VmBrkptRef* VmBrkptIntf::add(NativeCodeP brpt_ref->next = m_list; m_list = brpt_ref; + TRACE2("jvmti.break.intf", "Added ref on breakpoint: " + << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." + << method_get_name((Method*)brpt_ref->brpt->method) + << method_get_descriptor((Method*)brpt_ref->brpt->method) + << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); + return brpt_ref; } -bool VmBrkptIntf::remove(VmBrkptRef* ref) +bool VMBreakInterface::remove(VMBreakPointRef* ref) { assert(ref); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VmBrkptRef* found = NULL; + TRACE2("jvmti.break.intf", "Remove ref on breakpoint: " + << class_get_name(method_get_class((Method*)ref->brpt->method)) << "." + << method_get_name((Method*)ref->brpt->method) + << method_get_descriptor((Method*)ref->brpt->method) + << " :" << ref->brpt->location << " :" << ref->brpt->addr); + + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPointRef* found = NULL; - for (VmBrkptRef** cur_ptr = &m_list; + for (VMBreakPointRef** cur_ptr = &m_list; *cur_ptr; cur_ptr = &(*cur_ptr)->next) { if (*cur_ptr == ref) @@ -766,7 +872,7 @@ bool VmBrkptIntf::remove(VmBrkptRef* ref assert(found); - VmBrkpt* brpt = found->brpt; + VMBreakPoint* brpt = found->brpt; assert(brpt); if (found->data) @@ -774,7 +880,7 @@ bool VmBrkptIntf::remove(VmBrkptRef* ref STD_FREE(found); - if (vm_brpt->find_other(this, brpt)) + if (vm_brpt->find_other_reference(this, brpt)) return true; // There are some other references to the same breakpoint if (!vm_brpt->remove_breakpoint(brpt)) @@ -784,11 +890,11 @@ bool VmBrkptIntf::remove(VmBrkptRef* ref return true; } -VmBrkptRef* VmBrkptIntf::find(jmethodID method, jlocation location) +VMBreakPointRef* VMBreakInterface::find(jmethodID method, jlocation location) { assert(method); - for (VmBrkptRef* ref = m_list; ref; ref = ref->next) + for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { if (ref->brpt->method && ref->brpt->method == method && @@ -801,11 +907,11 @@ VmBrkptRef* VmBrkptIntf::find(jmethodID return NULL; } -VmBrkptRef* VmBrkptIntf::find(NativeCodePtr addr) +VMBreakPointRef* VMBreakInterface::find(NativeCodePtr addr) { assert(addr); - for (VmBrkptRef* ref = m_list; ref; ref = ref->next) + for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { if (ref->brpt->addr == addr) { @@ -816,11 +922,11 @@ VmBrkptRef* VmBrkptIntf::find(NativeCode return NULL; } -VmBrkptRef* VmBrkptIntf::find(VmBrkpt* brpt) +VMBreakPointRef* VMBreakInterface::find(VMBreakPoint* brpt) { assert(brpt); - for (VmBrkptRef* ref = m_list; ref; ref = ref->next) + for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { if (ref->brpt == brpt) { @@ -831,7 +937,7 @@ VmBrkptRef* VmBrkptIntf::find(VmBrkpt* b return NULL; } -void VmBrkptIntf::remove_all() +void VMBreakInterface::remove_all() { while (m_list) remove(m_list); @@ -848,7 +954,7 @@ get_condition_code(InstructionDisassembl return (ConditionCode)jump_type; } -static bool set_jit_mode_breakpoint(VmBreakpoints* vm_brpt, VmBrkpt* bp) +static bool set_jit_mode_breakpoint(VMBreakPoints* vm_brpt, VMBreakPoint* bp) { assert(bp); @@ -875,57 +981,68 @@ static bool set_jit_mode_breakpoint(VmBr bp->addr = np; } - TRACE2("jvmti.break.intf", "Instrumenting JIT location " << np << - " in method " << m->get_name()->bytes << - " location " << bp->location); - + TRACE2("jvmti.break.intf", "Set JIT breakpoint: " + << class_get_name(method_get_class((Method*)bp->method)) << "." + << method_get_name((Method*)bp->method) + << method_get_descriptor((Method*)bp->method) + << " :" << bp->location << " :" << bp->addr); return set_native_breakpoint(bp); } -static bool set_native_breakpoint(VmBrkpt* bp) +static bool set_native_breakpoint(VMBreakPoint* bp) { assert(bp); assert(bp->addr); - TRACE2("jvmti.break.intf", "Instrumenting native location " << - bp->addr); + TRACE2("jvmti.break.intf", "Instrumenting native: " + << (bp->method ? class_get_name(method_get_class((Method*)bp->method)) : "" ) + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "" ) + << (bp->method ? method_get_descriptor((Method*)bp->method) : "" ) + << " :" << bp->location << " :" << bp->addr); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; // Look for breakpoint with identical addr - VmBrkpt* same_brpt; - for (same_brpt = vm_brpt->find_breakpoint(bp->addr); same_brpt; - same_brpt = vm_brpt->find_next_breakpoint(same_brpt, bp->addr)); - - if (same_brpt) + VMBreakPoint* other_bp = vm_brpt->find_other_breakpoint_with_same_addr(bp); + if (other_bp) { - bp->disasm = new InstructionDisassembler(*same_brpt->disasm); - bp->saved_byte = same_brpt->saved_byte; - return true; + assert(other_bp->disasm); + bp->disasm = new InstructionDisassembler(*other_bp->disasm); + assert(bp->disasm); + bp->saved_byte = other_bp->saved_byte; } + else + { + bp->disasm = new InstructionDisassembler(bp->addr); + assert(bp->disasm); - bp->disasm = new InstructionDisassembler(bp->addr); - assert(bp->disasm); - - jbyte* target_instruction = (jbyte*)bp->addr; - bp->saved_byte = *target_instruction; - *target_instruction = (jbyte)INSTRUMENTATION_BYTE; + // instrumening code + jbyte* target_instruction = (jbyte*)bp->addr; + bp->saved_byte = *target_instruction; + *target_instruction = (jbyte)INSTRUMENTATION_BYTE; + } return true; } -static bool clear_native_breakpoint(VmBrkpt* bp) +static bool clear_native_breakpoint(VMBreakPoint* bp) { assert(bp); assert(bp->addr); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - // Look for breakpoint with same addr + // Looking for another breakpoint with the same address, + // currect breakpoint is already removed from breakpoint list. if (!vm_brpt->find_breakpoint(bp->addr)) { - TRACE2("jvmti.break.intf", "Deinstrumenting native location " << bp->addr); - + TRACE2("jvmti.break.intf", "Deinstrumenting native: " + << (bp->method ? class_get_name(method_get_class((Method*)bp->method)) : "" ) + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "" ) + << (bp->method ? method_get_descriptor((Method*)bp->method) : "" ) + << " :" << bp->location << " :" << bp->addr); jbyte* target_instruction = (jbyte*)bp->addr; *target_instruction = bp->saved_byte; } @@ -960,9 +1077,9 @@ #endif if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE) return false; - VmBreakpoints* vm_brpt = ti->vm_brpt; + VMBreakPoints* vm_brpt = ti->vm_brpt; vm_brpt->lock(); - VmBrkpt* bp = vm_brpt->find_breakpoint(native_location); + VMBreakPoint* bp = vm_brpt->find_breakpoint(native_location); if (NULL == bp) { vm_brpt->unlock(); @@ -995,14 +1112,16 @@ void jvmti_set_pending_breakpoints(Metho if (!ti->isEnabled()) return; - VmBreakpoints* vm_brpt = ti->vm_brpt; - - assert(method->get_pending_breakpoints() > 0); + if( !method->get_pending_breakpoints() ) + return; + VMBreakPoints* vm_brpt = ti->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); - jmethodID mid = (jmethodID)method; - VmBrkpt* bp = vm_brpt->find_first(mid); + if( !method->get_pending_breakpoints() ) + return; + + VMBreakPoint* bp = vm_brpt->find_first((jmethodID)method); assert(bp); jlocation *locations = (jlocation *)STD_MALLOC(sizeof(jlocation) * @@ -1022,12 +1141,13 @@ void jvmti_set_pending_breakpoints(Metho locations[location_count++] = bp->location; method->remove_pending_breakpoint(); - bp = vm_brpt->find_next(bp, mid); + bp = vm_brpt->find_next(bp, (jmethodID)method); } while (NULL != bp); assert(method->get_pending_breakpoints() == 0); STD_FREE(locations); + return; } ////////////////////////////////////////////////////////////////////////////// diff --git a/vm/vmcore/src/jvmti/jvmti_event.cpp b/vm/vmcore/src/jvmti/jvmti_event.cpp index 4f4ed36..24ca6da 100644 --- a/vm/vmcore/src/jvmti/jvmti_event.cpp +++ b/vm/vmcore/src/jvmti/jvmti_event.cpp @@ -325,7 +325,6 @@ jvmtiSetEventNotificationMode(jvmtiEnv* else if (JVMTI_DISABLE == mode && ti->is_single_step_enabled()) { // Check that no environment has SingleStep enabled - TRACE2("jvmti.break.ss", "SingleStep event is disabled"); LMAutoUnlock lock(&ti->TIenvs_lock); bool disable = true; @@ -344,6 +343,7 @@ jvmtiSetEventNotificationMode(jvmtiEnv* if (disable) { + TRACE2("jvmti.break.ss", "SingleStep event is disabled"); jvmtiError errorCode = ti->jvmti_single_step_stop(); if (JVMTI_ERROR_NONE != errorCode) diff --git a/vm/vmcore/src/jvmti/jvmti_method.cpp b/vm/vmcore/src/jvmti/jvmti_method.cpp index 4b2d78e..1e3fb4a 100644 --- a/vm/vmcore/src/jvmti/jvmti_method.cpp +++ b/vm/vmcore/src/jvmti/jvmti_method.cpp @@ -530,14 +530,14 @@ jvmtiGetBytecodes(jvmtiEnv* env, if (interpreter_enabled()) { TIEnv *p_env = (TIEnv *)env; - VmBreakpoints* vm_brpt = p_env->vm->vm_env->TI->vm_brpt; + VMBreakPoints* vm_brpt = p_env->vm->vm_env->TI->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); if (!vm_brpt->has_breakpoint(method)) return JVMTI_ERROR_NONE; - for (VmBrkpt* bpt = vm_brpt->find_first(method); bpt; + for (VMBreakPoint* bpt = vm_brpt->find_first(method); bpt; bpt = vm_brpt->find_next(bpt, method)) { (*bytecodes_ptr)[bpt->location] = diff --git a/vm/vmcore/src/jvmti/jvmti_step.cpp b/vm/vmcore/src/jvmti/jvmti_step.cpp index d967194..2b71b97 100644 --- a/vm/vmcore/src/jvmti/jvmti_step.cpp +++ b/vm/vmcore/src/jvmti/jvmti_step.cpp @@ -31,8 +31,6 @@ #include "open/bytecodes.h" #include "open/jthread.h" #include "jvmti_break_intf.h" -static JNIEnv * jvmti_test_jenv = jni_native_intf; - static inline short jvmti_GetHalfWordValue( const unsigned char *bytecode, unsigned location) @@ -258,7 +256,7 @@ jvmti_SingleStepLocation( VM_thread* thr case OPCODE_RETURN: /* 0xb1 */ assert( !is_wide ); { - error = jvmti_get_next_bytecodes_stack_from_native( + error = jvmti_get_next_bytecodes_from_native( thread, next_step, count, true ); assert( error == JVMTI_ERROR_NONE ); } @@ -382,7 +380,7 @@ jvmti_SingleStepLocation( VM_thread* thr } // jvmti_SingleStepLocation static void -jvmti_setup_jit_single_step(DebugUtilsTI *ti, VmBrkptIntf* intf, +jvmti_setup_jit_single_step(DebugUtilsTI *ti, VMBreakInterface* intf, Method* m, jlocation location) { VM_thread* vm_thread = p_TLS_vmthread; @@ -398,12 +396,16 @@ jvmti_setup_jit_single_step(DebugUtilsTI } // Callback function for JVMTI single step processing -static bool jvmti_process_jit_single_step_event(VmBrkptIntf* intf, VmBrkptRef* bp_ref) +static bool jvmti_process_jit_single_step_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref) { - VmBrkpt* bp = bp_ref->brpt; + VMBreakPoint* bp = bp_ref->brpt; assert(bp); - TRACE2("jvmti.break.ss", "Single Step occured: location=" << bp->location); + TRACE2("jvmti.break.ss", "SingleStep occured: " + << class_get_name(method_get_class((Method*)bp->method)) << "." + << method_get_name((Method*)bp->method) + << method_get_descriptor((Method*)bp->method) + << " :" << bp->location << " :" << bp->addr); DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE) @@ -516,23 +518,17 @@ void jvmti_set_single_step_breakpoints(D JVMTISingleStepState *ss_state = vm_thread->ss_state; if (NULL == ss_state->predicted_breakpoints) - { // Create SS breakpoints list + { + // Create SS breakpoints list + // Single Step must be processed earlier then Breakpoints ss_state->predicted_breakpoints = - ti->vm_brpt->query_intf(jvmti_process_jit_single_step_event, false); + ti->vm_brpt->new_intf(jvmti_process_jit_single_step_event, + PRIORITY_SINGLE_STEP_BREAKPOINT, false); assert(ss_state->predicted_breakpoints); - // Single Step must be processed earlier then Breakpoints - assert(BREAK_MIN_PRIORITY > BREAK_MAX_PRIORITY); - ss_state->predicted_breakpoints->set_priority(BREAK_MIN_PRIORITY - 1); } for (unsigned iii = 0; iii < locations_number; iii++) { - VmBrkptRef* ref = - ss_state->predicted_breakpoints->add((jmethodID)locations[iii].method, - locations[iii].location, - locations[iii].native_location, - NULL); - TRACE2("jvmti.break.ss", "Set single step breakpoint: " << class_get_name(method_get_class(locations[iii].method)) << "." << method_get_name(locations[iii].method) @@ -540,6 +536,11 @@ void jvmti_set_single_step_breakpoints(D << " :" << locations[iii].location << " :" << locations[iii].native_location); + VMBreakPointRef* ref = + ss_state->predicted_breakpoints->add((jmethodID)locations[iii].method, + locations[iii].location, + locations[iii].native_location, + NULL); assert(ref); } } @@ -549,14 +550,16 @@ void jvmti_remove_single_step_breakpoint // Function is always executed under global TI breakpoints lock JVMTISingleStepState *ss_state = vm_thread->ss_state; + TRACE2("jvmti.break.ss", "Remove single step breakpoints"); + if (ss_state && ss_state->predicted_breakpoints) ss_state->predicted_breakpoints->remove_all(); } -jvmtiError jvmti_get_next_bytecodes_stack_from_native(VM_thread *thread, +jvmtiError jvmti_get_next_bytecodes_from_native(VM_thread *thread, jvmti_StepLocation **next_step, unsigned *count, - bool step_up) + bool stack_step_up) { ASSERT_NO_INTERPRETER; @@ -575,7 +578,7 @@ jvmtiError jvmti_get_next_bytecodes_stac } assert(!si_is_native(si)); - if( step_up ) { + if( stack_step_up ) { // get previous stack frame si_goto_previous(si); } @@ -607,13 +610,13 @@ jvmtiError jvmti_get_next_bytecodes_stac } si_free(si); return JVMTI_ERROR_NONE; -} // jvmti_get_next_bytecodes_stack_from_native +} // jvmti_get_next_bytecodes_from_native jvmtiError DebugUtilsTI::jvmti_single_step_start(void) { assert(hythread_is_suspend_enabled()); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); hythread_iterator_t threads_iterator; @@ -651,7 +654,7 @@ jvmtiError DebugUtilsTI::jvmti_single_st jvmti_StepLocation *locations; unsigned locations_number; - errorCode = jvmti_get_next_bytecodes_stack_from_native( + errorCode = jvmti_get_next_bytecodes_from_native( vm_thread, &locations, &locations_number, false); if (JVMTI_ERROR_NONE != errorCode) @@ -676,7 +679,7 @@ jvmtiError DebugUtilsTI::jvmti_single_st { assert(hythread_is_suspend_enabled()); - VmBreakpoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); hythread_iterator_t threads_iterator;