blob: a785582cd3f4cc4c31e9082f83a36c02ad2635ad [file] [log] [blame]
/**
* @author Ilya Berezhniuk
*/
//#include <memory.h>
//#include <string.h>
//#include <stdio.h>
#define LOG_DOMAIN "ncai.break"
#include "cxxlog.h"
#include "suspend_checker.h"
#include "jvmti_break_intf.h"
#include "ncai_utils.h"
#include "ncai_direct.h"
#include "ncai_internal.h"
// Callback function for NCAI breakpoint processing
bool ncai_process_breakpoint_event(TIEnv *env, const VMBreakPoint* bp,
const POINTER_SIZE_INT data)
{
TRACE2("ncai.break", "BREAKPOINT occured, location = " << bp->addr);
VM_thread* vm_thread = p_TLS_vmthread;
if (!vm_thread)
return false;
jvmti_thread_t jvmti_thread = &vm_thread->jvmti_thread;
// This check works for current thread only
if (jvmti_thread->flag_ncai_handler) // Recursion
return true;
jvmti_thread->flag_ncai_handler = true;
NCAIEnv* ncai_env = env->ncai_env;
void* addr = (void*)bp->addr;
bool suspend_enabled = hythread_is_suspend_enabled();
if (!suspend_enabled)
hythread_suspend_enable();
hythread_t hythread = hythread_self();
ncaiThread thread = reinterpret_cast<ncaiThread>(hythread);
ncaiBreakpoint func =
(ncaiBreakpoint)ncai_env->get_event_callback(NCAI_EVENT_BREAKPOINT);
if (NULL != func)
{
if (ncai_env->global_events[NCAI_EVENT_BREAKPOINT - NCAI_MIN_EVENT_TYPE_VAL])
{
TRACE2("ncai.break", "Calling global breakpoint callback, address = " << addr);
func((ncaiEnv*)ncai_env, thread, addr);
TRACE2("ncai.break", "Finished global breakpoint callback, address = " << addr);
}
else
{
ncaiEventThread* next_et;
ncaiEventThread* first_et =
ncai_env->event_threads[NCAI_EVENT_BREAKPOINT - NCAI_MIN_EVENT_TYPE_VAL];
for (ncaiEventThread* et = first_et; NULL != et; et = next_et)
{
next_et = et->next;
if (et->thread == thread)
{
TRACE2("ncai.break", "Calling local breakpoint callback, address = " << addr);
func((ncaiEnv*)ncai_env, thread, addr);
TRACE2("ncai.break", "Finished local breakpoint callback, address = " << addr);
}
et = next_et;
}
}
}
if (!suspend_enabled)
hythread_suspend_disable();
jvmti_thread->flag_ncai_handler = false;
return true;
}
ncaiError JNICALL
ncaiSetBreakpoint(ncaiEnv *env, void* code_addr)
{
TRACE2("ncai.break", "SetBreakpoint called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (code_addr == NULL)
return NCAI_ERROR_INVALID_ADDRESS;
NCAIEnv *p_env = (NCAIEnv*)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(code_addr);
if (NULL != bp_ref)
return NCAI_ERROR_DUPLICATE;
if (!brpt_intf->add_reference(code_addr, 0))
return NCAI_ERROR_INTERNAL;
TRACE2("ncai.break", "SetBreakpoint is successfull");
return NCAI_ERROR_NONE;
}
ncaiError JNICALL
ncaiClearBreakpoint(ncaiEnv *env, void* code_addr)
{
TRACE2("ncai.break", "ClearBreakpoint called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (code_addr == NULL)
return NCAI_ERROR_INVALID_ADDRESS;
NCAIEnv *p_env = (NCAIEnv*)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(code_addr);
if (NULL == bp_ref)
return NCAI_ERROR_NOT_FOUND;
if (!brpt_intf->remove_reference(bp_ref))
return NCAI_ERROR_INTERNAL;
TRACE2("ncai.break", "ClearBreakpoint is successfull");
return NCAI_ERROR_NONE;
}