blob: 8dcf1fb3e4b2bd60cd0c14e28fcea371037b10ac [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.
*/
/**
* @author Ilya Berezhniuk
*/
#define LOG_DOMAIN "ncai.signal"
#include "cxxlog.h"
#include "suspend_checker.h"
#include "jvmti_internal.h"
#include "environment.h"
#include "port_crash_handler.h"
#include "ncai_utils.h"
#include "ncai_direct.h"
#include "ncai_internal.h"
struct st_signal_info
{
jint signal;
const char* name;
size_t name_size;
};
static size_t ncai_get_signal_count();
static st_signal_info* find_signal(jint sig);
static jint ncai_get_min_signal();
static jint ncai_get_max_signal();
static const char* ncai_get_signal_name(jint signal);
static size_t ncai_get_signal_name_size(jint signal);
bool ncai_is_signal_in_range(jint signal);
ncaiError JNICALL
ncaiGetSignalCount(ncaiEnv *env, jint* count_ptr)
{
TRACE2("ncai.signal", "GetSignalCount called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (count_ptr == NULL)
return NCAI_ERROR_NULL_POINTER;
*count_ptr = (jint)ncai_get_signal_count();
return NCAI_ERROR_NONE;
}
ncaiError JNICALL
ncaiGetSignalInfo(ncaiEnv *env, jint signal, ncaiSignalInfo* info_ptr)
{
TRACE2("ncai.signal", "GetSignalInfo called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (info_ptr == NULL)
return NCAI_ERROR_NULL_POINTER;
if (!ncai_is_signal_in_range(signal))
return NCAI_ERROR_ILLEGAL_ARGUMENT;
const char* name = ncai_get_signal_name(signal);
if (name == NULL)
return NCAI_ERROR_ILLEGAL_ARGUMENT;
size_t name_size = ncai_get_signal_name_size(signal);
char* out_name = (char*)ncai_alloc(name_size);
if (out_name == NULL)
return NCAI_ERROR_OUT_OF_MEMORY;
memcpy(out_name, name, name_size);
info_ptr->name = out_name;
return NCAI_ERROR_NONE;
}
void ncai_process_signal_event(NativeCodePtr addr,
jint code, bool is_internal, bool* p_handled)
{
if (!GlobalNCAI::isEnabled())
return;
DebugUtilsTI* ti = VM_Global_State::loader_env->TI;
hythread_t hythread = hythread_self();
ncaiThread thread = reinterpret_cast<ncaiThread>(hythread);
bool skip_handler = false;
TIEnv* next_env;
for (TIEnv* env = ti->getEnvironments(); env; env = next_env)
{
next_env = env->next;
NCAIEnv* ncai_env = env->ncai_env;
if (NULL == ncai_env)
continue;
ncaiSignal func =
(ncaiSignal)ncai_env->get_event_callback(NCAI_EVENT_SIGNAL);
if (NULL != func)
{
if (ncai_env->global_events[NCAI_EVENT_SIGNAL - NCAI_MIN_EVENT_TYPE_VAL])
{
TRACE2("ncai.signal", "Calling global Signal callback, address = "
<< addr << ", code = " << (void*)(size_t)code);
jboolean is_h = *p_handled;
func((ncaiEnv*)ncai_env, thread, (void*)addr, code, is_internal, &is_h);
if (!(*p_handled) && is_h)
skip_handler = true;
TRACE2("ncai.signal", "Finished global Signal callback, address = "
<< addr << ", code = " << (void*)(size_t)code);
continue;
}
ncaiEventThread* next_et;
ncaiEventThread* first_et =
ncai_env->event_threads[NCAI_EVENT_SIGNAL - 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.signal", "Calling local Signal callback, address = "
<< addr << ", code = " << (void*)(size_t)code);
jboolean is_h = *p_handled;
func((ncaiEnv*)ncai_env, thread, (void*)addr, code, is_internal, &is_h);
if (!(*p_handled) && is_h)
skip_handler = true;
TRACE2("ncai.signal", "Finished local Signal callback, address = "
<< addr << ", code = " << (void*)(size_t)code);
}
et = next_et;
}
}
}
}
#define STR_AND_SIZE(_x_) _x_, (strlen(_x_) + 1)
static st_signal_info sig_table[] = {
{PORT_SIGNAL_GPF, STR_AND_SIZE("PORT_SIGNAL_GPF")},
{PORT_SIGNAL_STACK_OVERFLOW,STR_AND_SIZE("PORT_SIGNAL_STACK_OVERFLOW")},
{PORT_SIGNAL_ABORT, STR_AND_SIZE("PORT_SIGNAL_ABORT")},
{PORT_SIGNAL_QUIT, STR_AND_SIZE("PORT_SIGNAL_QUIT")},
{PORT_SIGNAL_CTRL_BREAK, STR_AND_SIZE("PORT_SIGNAL_CTRL_BREAK")},
{PORT_SIGNAL_CTRL_C, STR_AND_SIZE("PORT_SIGNAL_CTRL_C")},
{PORT_SIGNAL_BREAKPOINT, STR_AND_SIZE("PORT_SIGNAL_BREAKPOINT")},
{PORT_SIGNAL_ARITHMETIC, STR_AND_SIZE("PORT_SIGNAL_ARITHMETIC")},
};
static size_t ncai_get_signal_count()
{
return sizeof(sig_table)/sizeof(sig_table[0]);
}
static st_signal_info* find_signal(jint sig)
{
for (size_t i = 0; i < ncai_get_signal_count(); i++)
{
if (sig_table[i].signal == sig)
return &sig_table[i];
}
return NULL;
}
static jint ncai_get_min_signal()
{
static int min_sig_value = sig_table[1].signal;
if (min_sig_value != sig_table[1].signal)
return min_sig_value;
min_sig_value = sig_table[0].signal;
for (size_t i = 1; i < ncai_get_signal_count(); i++)
{
if (sig_table[i].signal < min_sig_value)
min_sig_value = sig_table[i].signal;
}
return min_sig_value;
}
static jint ncai_get_max_signal()
{
static int max_sig_value = -1;
if (max_sig_value != -1)
return max_sig_value;
max_sig_value = sig_table[0].signal;
for (size_t i = 1; i < ncai_get_signal_count(); i++)
{
if (sig_table[i].signal > max_sig_value)
max_sig_value = sig_table[i].signal;
}
return max_sig_value;
}
static const char* ncai_get_signal_name(jint signal)
{
st_signal_info* psig = find_signal(signal);
return psig ? psig->name : NULL;
}
static size_t ncai_get_signal_name_size(jint signal)
{
st_signal_info* psig = find_signal(signal);
return psig ? psig->name_size : 0;
}
bool ncai_is_signal_in_range(jint signal)
{
return (signal >= ncai_get_min_signal() ||
signal <= ncai_get_max_signal());
}