blob: 43072872bef492944feb710bc40742e1bd411338 [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.
*/
#define LOG_DOMAIN "signals"
#include "cxxlog.h"
#include "open/platform_types.h"
#include "port_crash_handler.h"
#include "init.h"
#include "vm_threads.h"
#include "environment.h"
#include "exceptions.h"
#include "signals.h"
#ifdef PLATFORM_POSIX
#if defined(HYX86_64)
#define RESTORE_STACK_SIZE 0x0400
#elif defined (HYX86)
#define RESTORE_STACK_SIZE 0x0100
#else // IPF
#define RESTORE_STACK_SIZE 0x0200
#endif
#else // WINDOWS
#define RESTORE_STACK_SIZE 0x0100
#endif
size_t get_available_stack_size()
{
size_t stack_addr = (size_t)port_thread_get_stack_address();
size_t stack_size = port_thread_get_effective_stack_size();
size_t used_stack_size = stack_addr - (size_t)&stack_size;
size_t available_stack_size = stack_size - used_stack_size;
return (available_stack_size > 0) ? available_stack_size : 0;
}
bool check_available_stack_size(size_t required_size)
{
size_t available_stack_size = get_available_stack_size();
if (available_stack_size < required_size)
{
port_thread_clear_guard_page();
p_TLS_vmthread->restore_guard_page = true;
Global_Env *env = VM_Global_State::loader_env;
exn_raise_by_class(env->java_lang_StackOverflowError_Class);
return false;
}
return true;
}
static inline size_t get_available_stack_size(void* sp) {
size_t stack_addr = (size_t)port_thread_get_stack_address();
size_t stack_size = port_thread_get_effective_stack_size();
size_t used_stack_size = stack_addr - (size_t)sp;
size_t available_stack_size = stack_size - used_stack_size;
return (available_stack_size > 0) ? available_stack_size : 0;
}
bool check_stack_size_enough_for_exception_catch(void* sp)
{
size_t stack_addr = (size_t)port_thread_get_stack_address();
size_t stack_size = port_thread_get_effective_stack_size();
size_t used_stack_size = stack_addr - (size_t)sp;
size_t available_stack_size = stack_size - used_stack_size;
return RESTORE_STACK_SIZE < available_stack_size;
}
Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr)
{
TRACE2("signals", ("SOE detected at ip=%p, sp=%p",
regs->get_ip(), regs->get_sp()));
vm_thread_t vmthread = get_thread_ptr();
Global_Env* env = VM_Global_State::loader_env;
void* saved_ip = regs->get_ip();
void* new_ip = NULL;
if (is_in_ti_handler(vmthread, saved_ip))
{
new_ip = vm_get_ip_from_regs(vmthread);
regs->set_ip(new_ip);
}
if (!vmthread || env == NULL)
return FALSE; // Crash
port_thread_postpone_guard_page();
vmthread->restore_guard_page = true;
// Pass exception to NCAI exception handler
bool is_handled = 0;
ncai_process_signal_event((NativeCodePtr)regs->get_ip(),
(jint)signum, false, &is_handled);
if (is_handled)
{
if (new_ip)
regs->set_ip(saved_ip);
return TRUE;
}
Class* exn_class = env->java_lang_StackOverflowError_Class;
if (is_in_java(regs))
{
signal_throw_java_exception(regs, exn_class);
}
else if (is_unwindable())
{
if (hythread_is_suspend_enabled())
hythread_suspend_disable();
signal_throw_exception(regs, exn_class);
} else {
exn_raise_by_class(exn_class);
}
if (new_ip && regs->get_ip() == new_ip)
regs->set_ip(saved_ip);
return TRUE;
}
Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr)
{
TRACE2("signals", "NPE detected at " << regs->get_ip());
vm_thread_t vmthread = get_thread_ptr();
Global_Env* env = VM_Global_State::loader_env;
void* saved_ip = regs->get_ip();
void* new_ip = NULL;
if (is_in_ti_handler(vmthread, saved_ip))
{
new_ip = vm_get_ip_from_regs(vmthread);
regs->set_ip(new_ip);
}
if (!vmthread || env == NULL)
return FALSE; // Crash
if (!is_in_java(regs) || interpreter_enabled())
return FALSE; // Crash
// Pass exception to NCAI exception handler
bool is_handled = 0;
ncai_process_signal_event((NativeCodePtr)regs->get_ip(),
(jint)signum, false, &is_handled);
if (is_handled)
{
if (new_ip)
regs->set_ip(saved_ip);
return TRUE;
}
signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class);
if (new_ip && regs->get_ip() == new_ip)
regs->set_ip(saved_ip);
return TRUE;
}
Boolean abort_handler(port_sigtype UNREF signum, Registers* UNREF regs, void* fault_addr)
{
TRACE2("signals", "Abort detected at " << regs->get_ip());
// Crash always
return FALSE;
}
Boolean ctrl_backslash_handler(port_sigtype UNREF signum, Registers* UNREF regs, void* UNREF fault_addr)
{
TRACE2("signals", "Ctrl+\\ pressed");
vm_dump_handler();
return TRUE;
}
Boolean ctrl_break_handler(port_sigtype UNREF signum, Registers* UNREF regs, void* UNREF fault_addr)
{
TRACE2("signals", "Ctrl+Break pressed");
vm_dump_handler();
return TRUE;
}
Boolean ctrl_c_handler(port_sigtype UNREF signum, Registers* UNREF regs, void* UNREF fault_addr)
{
TRACE2("signals", "Ctrl+C pressed");
vm_interrupt_handler();
// Continue execution - the process will be terminated from
// the separate thread started in vm_interrupt_handler()
return TRUE;
}
Boolean native_breakpoint_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr)
{
TRACE2("signals", "Native breakpoint detected at " << regs->get_ip());
#ifdef _IPF_
LDIE(51, "Not implemented");
#endif
if (VM_Global_State::loader_env == NULL || interpreter_enabled())
return FALSE; // Crash
vm_thread_t vmthread = get_thread_ptr();
if (is_in_ti_handler(vmthread, regs->get_ip()))
// Breakpoints should not occur in breakpoint buffer
return FALSE; // Crash
// Pass exception to NCAI exception handler
bool is_handled = 0;
ncai_process_signal_event((NativeCodePtr)regs->get_ip(),
(jint)signum, true, &is_handled);
if (is_handled)
return TRUE;
return (Boolean)jvmti_jit_breakpoint_handler(regs);
}
Boolean arithmetic_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr)
{
TRACE2("signals", "ArithmeticException detected at " << regs->get_ip());
#ifdef _IPF_
LDIE(51, "Not implemented");
#endif
vm_thread_t vmthread = get_thread_ptr();
void* saved_ip = regs->get_ip();
void* new_ip = NULL;
if (is_in_ti_handler(vmthread, saved_ip))
{
new_ip = vm_get_ip_from_regs(vmthread);
regs->set_ip(new_ip);
}
// Pass exception to NCAI exception handler
bool is_handled = 0;
ncai_process_signal_event((NativeCodePtr)regs->get_ip(),
(jint)signum, false, &is_handled);
if (is_handled)
{
if (new_ip)
regs->set_ip(saved_ip);
return TRUE;
}
if (!vmthread || VM_Global_State::loader_env == NULL ||
!is_in_java(regs) || interpreter_enabled())
return FALSE; // Crash
signal_throw_java_exception(regs, VM_Global_State::loader_env->java_lang_ArithmeticException_Class);
if (new_ip && regs->get_ip() == new_ip)
regs->set_ip(saved_ip);
return TRUE;
}