blob: 7bce34df013923e6db08e9bfbbc5f4386729cdc5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/*
* JVMTI API for working with breakpoints
*/
#define LOG_DOMAIN "jvmti.break"
#include "cxxlog.h"
#include "open/hythread_ext.h"
#include "open/vm_method_access.h"
#include "jvmti_direct.h"
#include "jvmti_utils.h"
#include "jvmti_internal.h"
#include "environment.h"
#include "Class.h"
#include "vm_log.h"
#include "cci.h"
#include "suspend_checker.h"
#include "interpreter_exports.h"
#include "jvmti_break_intf.h"
#include "jthread.h"
// Callback function for JVMTI breakpoint processing
bool jvmti_process_breakpoint_event(TIEnv *env, const VMBreakPoint* bp, const POINTER_SIZE_INT UNREF data)
{
assert(bp);
TRACE("Process breakpoint: "
<< bp->method << " :" << bp->location << " :" << bp->addr );
DebugUtilsTI *ti = VM_Global_State::loader_env->TI;
if (ti->getPhase() != JVMTI_PHASE_LIVE)
return false;
jlocation location = bp->location;
jmethodID method = bp->method;
NativeCodePtr addr = bp->addr;
hythread_t h_thread = hythread_self();
jthread j_thread = jthread_get_java_thread(h_thread);
ObjectHandle hThread = oh_allocate_local_handle();
hThread->object = (Java_java_lang_Thread *)j_thread->object;
tmn_suspend_enable();
JNIEnv *jni_env = p_TLS_vmthread->jni_env;
jvmtiEventBreakpoint func =
(jvmtiEventBreakpoint)env->get_event_callback(JVMTI_EVENT_BREAKPOINT);
if (NULL != func)
{
if (env->global_events[JVMTI_EVENT_BREAKPOINT - JVMTI_MIN_EVENT_TYPE_VAL])
{
TRACE("Calling global breakpoint callback: "
<< method << " :" << location << " :" << addr);
func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location);
TRACE("Finished global breakpoint callback: "
<< method << " :" << location << " :" << addr);
}
else
{
TIEventThread *next_et;
TIEventThread *first_et =
env->event_threads[JVMTI_EVENT_BREAKPOINT - JVMTI_MIN_EVENT_TYPE_VAL];
for (TIEventThread *et = first_et; NULL != et; et = next_et)
{
next_et = et->next;
if (et->thread == hythread_self())
{
TRACE("Calling local breakpoint callback: "
<< method << " :" << location << " :" << addr);
func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location);
TRACE("Finished local breakpoint callback: "
<< method << " :" << location << " :" << addr);
}
}
}
}
oh_discard_local_handle(hThread);
hythread_exception_safe_point();
tmn_suspend_disable();
return true;
}
/*
* Set Breakpoint
*
* Set a breakpoint at the instruction indicated by method and
* location. An instruction can only have one breakpoint.
*
* OPTIONAL Functionality
*/
jvmtiError JNICALL
jvmtiSetBreakpoint(jvmtiEnv* env,
jmethodID method,
jlocation location)
{
TRACE("SetBreakpoint is called for method: " << method
<< " :" << location);
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (method == NULL)
return JVMTI_ERROR_INVALID_METHODID;
Method *m = (Method*) method;
TRACE("SetBreakpoint: " << method << " :" << location);
#if defined (__INTEL_COMPILER)
#pragma warning( push )
#pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type
#endif
if (location < 0 || unsigned(location) >= m->get_byte_code_size())
return JVMTI_ERROR_INVALID_LOCATION;
#if defined (__INTEL_COMPILER)
#pragma warning( pop )
#endif
/*
* JVMTI_ERROR_MUST_POSSESS_CAPABILITY
*/
jvmtiCapabilities capptr;
errorCode = jvmtiGetCapabilities(env, &capptr);
if (errorCode != JVMTI_ERROR_NONE)
return errorCode;
if (capptr.can_generate_breakpoint_events == 0)
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
TIEnv *p_env = (TIEnv *)env;
VMBreakInterface* brpt_intf = p_env->brpt_intf;
VMBreakPoints *vm_breaks = VM_Global_State::loader_env->TI->vm_brpt;
LMAutoUnlock lock(vm_breaks->get_lock());
VMBreakPointRef* bp = brpt_intf->find_reference(method, location);
if (NULL != bp)
return JVMTI_ERROR_DUPLICATE;
if (!brpt_intf->add_reference(method, location, (POINTER_SIZE_INT)false))
return JVMTI_ERROR_INTERNAL;
TRACE("SetBreakpoint is successful");
return JVMTI_ERROR_NONE;
}
/*
* Clear Breakpoint
*
* Clear the breakpoint at the bytecode indicated by method and
* location.
*
* OPTIONAL Functionality
*/
jvmtiError JNICALL
jvmtiClearBreakpoint(jvmtiEnv* env,
jmethodID method,
jlocation location)
{
TRACE("ClearBreakpoint is called for method: " << method
<< " :" << location);
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (method == NULL)
return JVMTI_ERROR_INVALID_METHODID;
Method *m = (Method*) method;
TRACE("ClearBreakpoint: " << method << " :" << location);
#if defined (__INTEL_COMPILER)
#pragma warning( push )
#pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type
#endif
if (location < 0 || unsigned(location) >= m->get_byte_code_size())
return JVMTI_ERROR_INVALID_LOCATION;
#if defined (__INTEL_COMPILER)
#pragma warning( pop )
#endif
/*
* JVMTI_ERROR_MUST_POSSESS_CAPABILITY
*/
jvmtiCapabilities capptr;
errorCode = jvmtiGetCapabilities(env, &capptr);
if (errorCode != JVMTI_ERROR_NONE)
return errorCode;
if (capptr.can_generate_breakpoint_events == 0)
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
TIEnv *p_env = (TIEnv *)env;
VMBreakInterface* brpt_intf = p_env->brpt_intf;
VMBreakPoints *vm_breaks = VM_Global_State::loader_env->TI->vm_brpt;
LMAutoUnlock lock(vm_breaks->get_lock());
VMBreakPointRef* bp_ref = brpt_intf->find_reference(method, location);
if (NULL == bp_ref)
return JVMTI_ERROR_NOT_FOUND;
if (!brpt_intf->remove_reference(bp_ref))
return JVMTI_ERROR_INTERNAL;
TRACE("ClearBreakpoint is successful");
return JVMTI_ERROR_NONE;
}