From 102be6be7e5fb8d527b68fa9c85405ad72003139 Mon Sep 17 00:00:00 2001 From: Berezhniuk Date: Tue, 11 Mar 2008 03:20:22 +0300 Subject: [PATCH] Move signal and crash handling to the Port to be used with new Port interfaces --- make/vm/port.xml | 29 +- vm/em/src/DrlEMImpl.cpp | 19 +- vm/em/src/DrlEMImpl.h | 2 +- vm/em/src/EBProfileCollector.cpp | 25 +- vm/em/src/EBProfileCollector.h | 2 +- vm/em/src/EdgeProfileCollector.cpp | 25 +- vm/em/src/EdgeProfileCollector.h | 2 +- vm/em/src/NValueProfileCollector.cpp | 16 +- vm/em/src/NValueProfileCollector.h | 9 +- vm/gc_gen/src/common/gc_common.cpp | 2 - vm/include/open/hycomp.h | 6 - vm/include/open/hycond_win.h | 2 +- vm/include/open/hythread_ext.h | 29 +- vm/include/open/platform_types.h | 1 + vm/interpreter/src/interp_exports.cpp | 7 - vm/port/include/port_crash_handler.h | 89 +++- vm/port/include/port_frame_info.h | 14 +- vm/port/include/port_general.h | 19 +- vm/port/include/port_memaccess.h | 53 ++ vm/port/include/port_modules.h | 8 +- vm/port/include/port_mutex.h | 157 ++++++ vm/port/include/port_thread.h | 12 +- vm/port/include/port_unwind.h | 44 ++ .../src/crash_handler/em64t/native_unwind_arch.cpp | 40 +- vm/port/src/crash_handler/em64t/reg_state.cpp | 4 +- .../src/crash_handler/ia32/native_unwind_arch.cpp | 40 +- vm/port/src/crash_handler/ia32/reg_state.cpp | 4 +- vm/port/src/crash_handler/include/native_unwind.h | 45 ++ vm/port/src/crash_handler/include/stack_dump.h | 89 ++-- .../src/crash_handler/ipf/native_unwind_arch.cpp | 16 +- vm/port/src/crash_handler/ipf/reg_state.cpp | 4 +- .../src/crash_handler/linux/gdb_crash_handler.cpp | 37 +- .../linux/include/gdb_crash_handler.h | 12 +- .../src/crash_handler/linux/native_unwind_os.cpp | 8 +- vm/port/src/crash_handler/linux/stack_dump_os.cpp | 115 +--- vm/port/src/crash_handler/native_unwind.cpp | 98 ++++ vm/port/src/crash_handler/port_crash_handler.cpp | 119 ++++- vm/port/src/crash_handler/stack_dump.cpp | 577 ++++++-------------- vm/port/src/crash_handler/win/native_unwind_os.cpp | 9 +- vm/port/src/crash_handler/win/stack_dump_os.cpp | 155 ++---- vm/port/src/memaccess/linux/memaccess.cpp | 307 +++-------- vm/port/src/memaccess/linux/memaccess_em64t.s | 42 ++ vm/port/src/memaccess/linux/memaccess_ia32.s | 49 ++ vm/port/src/memaccess/linux/memaccess_ipf.cpp | 51 ++ vm/port/src/memaccess/win/memaccess.cpp | 46 +- vm/port/src/modules/linux/native_modules_os.c | 2 +- vm/port/src/modules/native_modules.c | 2 +- vm/port/src/modules/win/native_modules_os.c | 2 +- vm/port/src/signals/include/signals_internal.h | 114 ++++ vm/port/src/signals/linux/signals_common.cpp | 179 ++++++ vm/port/src/signals/linux/signals_ipf.cpp | 283 ++++++++++ vm/port/src/signals/port_signals.cpp | 54 ++ vm/port/src/signals/win/signals_common.cpp | 320 +++++++++++ vm/port/src/signals/win/signals_ia32.cpp | 4 +- vm/tests/unit/thread/test_native_fat_monitor.c | 2 +- vm/tests/unit/thread/test_stress_suspend.h | 11 +- vm/thread/src/hythr.def | 5 - vm/thread/src/hythr.exp | 5 - vm/thread/src/linux/os_condvar.c | 2 +- vm/thread/src/linux/os_mutex.c | 10 +- vm/thread/src/thread_init.c | 29 +- vm/thread/src/thread_native_basic.c | 61 +- vm/thread/src/thread_native_condvar.c | 10 +- vm/thread/src/thread_native_fat_monitor.c | 23 +- vm/thread/src/thread_native_latch.c | 29 +- vm/thread/src/thread_native_park.c | 19 +- vm/thread/src/thread_native_semaphore.c | 31 +- vm/thread/src/thread_native_suspend.c | 15 +- vm/thread/src/thread_native_thin_monitor.c | 27 +- vm/thread/src/thread_private.h | 14 +- vm/thread/src/win/os_condvar.c | 27 +- vm/thread/src/win/os_mutex.c | 10 +- vm/vmcore/include/crash_dump.h | 32 ++ vm/vmcore/include/exceptions.h | 2 - vm/vmcore/include/finalizer_thread.h | 4 +- vm/vmcore/include/init.h | 4 +- vm/vmcore/include/jvmti_break_intf.h | 9 - vm/vmcore/include/jvmti_direct.h | 2 +- vm/vmcore/include/lock_manager.h | 2 +- vm/vmcore/include/native_stack.h | 25 +- vm/vmcore/include/ncai_internal.h | 9 - vm/vmcore/include/ref_enqueue_thread.h | 2 +- vm/vmcore/include/signals.h | 77 +++ vm/vmcore/src/class_support/C_Interface.cpp | 9 +- vm/vmcore/src/class_support/Verifier_stub.cpp | 2 +- vm/vmcore/src/init/finalizer_thread.cpp | 17 +- vm/vmcore/src/init/ref_enqueue_thread.cpp | 11 +- vm/vmcore/src/init/vm_init.cpp | 10 +- vm/vmcore/src/init/vm_properties.cpp | 2 +- vm/vmcore/src/init/vm_shutdown.cpp | 10 +- vm/vmcore/src/jvmti/jvmti.cpp | 5 +- vm/vmcore/src/jvmti/jvmti_break_intf.cpp | 22 +- vm/vmcore/src/jvmti/jvmti_capability.cpp | 5 +- vm/vmcore/src/jvmti/jvmti_event.cpp | 35 +- vm/vmcore/src/jvmti/jvmti_heap.cpp | 5 +- vm/vmcore/src/jvmti/jvmti_step.cpp | 4 +- vm/vmcore/src/ncai/ncai_memory.cpp | 22 +- vm/vmcore/src/ncai/ncai_modules.cpp | 6 +- vm/vmcore/src/ncai/ncai_signals.cpp | 102 ++++ vm/vmcore/src/ncai/ncai_stack.cpp | 6 +- vm/vmcore/src/ncai/utils/ncai_signals_linux.cpp | 110 ---- vm/vmcore/src/ncai/utils/ncai_signals_win.cpp | 92 ---- vm/vmcore/src/ncai/utils/ncai_step_ia32.cpp | 4 +- vm/vmcore/src/stack/native_stack.cpp | 157 ++---- vm/vmcore/src/thread/lock_manager.cpp | 13 +- vm/vmcore/src/thread/thread_generic.cpp | 1 - vm/vmcore/src/thread/thread_manager.cpp | 2 +- vm/vmcore/src/thread/thread_ti_monitors.cpp | 15 +- vm/vmcore/src/util/crash_dump.cpp | 315 +++++++++++ vm/vmcore/src/util/linux/crash_dump_os.cpp | 88 +++ .../src/util/linux/ia32_em64t/signals_common.cpp | 411 +++------------ .../src/util/linux/include/exception_filter.h | 27 - .../src/util/linux/include/platform_lowlevel.h | 9 - vm/vmcore/src/util/linux/include/signals_common.h | 3 - vm/vmcore/src/util/linux/signals_ipf.cpp | 465 ++++------------- vm/vmcore/src/util/natives_support.cpp | 8 +- vm/vmcore/src/util/signals.cpp | 125 +++++ vm/vmcore/src/util/win/crash_dump_os.cpp | 82 +++ .../win/ia32_em64t/nt_exception_filter_common.cpp | 408 +++----------- vm/vmcore/src/util/win/include/exception_filter.h | 56 -- vm/vmcore/src/util/win/include/platform_lowlevel.h | 16 +- vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp | 2 - vm/vmcore/src/util/win/nt_platform_utils.cpp | 42 -- 123 files changed, 3634 insertions(+), 2987 deletions(-) create mode 100644 vm/port/include/port_memaccess.h create mode 100644 vm/port/include/port_mutex.h create mode 100644 vm/port/include/port_unwind.h create mode 100644 vm/port/src/crash_handler/include/native_unwind.h create mode 100644 vm/port/src/crash_handler/native_unwind.cpp create mode 100644 vm/port/src/memaccess/linux/memaccess_em64t.s create mode 100644 vm/port/src/memaccess/linux/memaccess_ia32.s create mode 100644 vm/port/src/memaccess/linux/memaccess_ipf.cpp create mode 100644 vm/port/src/signals/include/signals_internal.h create mode 100644 vm/port/src/signals/linux/signals_common.cpp create mode 100644 vm/port/src/signals/linux/signals_ipf.cpp create mode 100644 vm/port/src/signals/port_signals.cpp create mode 100644 vm/port/src/signals/win/signals_common.cpp create mode 100644 vm/vmcore/include/crash_dump.h create mode 100644 vm/vmcore/include/signals.h delete mode 100644 vm/vmcore/src/ncai/utils/ncai_signals_linux.cpp delete mode 100644 vm/vmcore/src/ncai/utils/ncai_signals_win.cpp create mode 100644 vm/vmcore/src/util/crash_dump.cpp create mode 100644 vm/vmcore/src/util/linux/crash_dump_os.cpp delete mode 100644 vm/vmcore/src/util/linux/include/exception_filter.h create mode 100644 vm/vmcore/src/util/signals.cpp create mode 100644 vm/vmcore/src/util/win/crash_dump_os.cpp delete mode 100644 vm/vmcore/src/util/win/include/exception_filter.h diff --git a/make/vm/port.xml b/make/vm/port.xml index 3664591..4571fe5 100644 --- a/make/vm/port.xml +++ b/make/vm/port.xml @@ -29,6 +29,9 @@ + + + @@ -75,6 +78,9 @@ + + + @@ -97,6 +103,23 @@ + + + + + + + + + + + + + + + + + @@ -104,7 +127,11 @@ - + + + + + diff --git a/vm/em/src/DrlEMImpl.cpp b/vm/em/src/DrlEMImpl.cpp index 4aa12a7..f321ede 100644 --- a/vm/em/src/DrlEMImpl.cpp +++ b/vm/em/src/DrlEMImpl.cpp @@ -37,6 +37,7 @@ #include #include #include "port_threadunsafe.h" +#include "port_mutex.h" #define LOG_DOMAIN "em" @@ -106,13 +107,13 @@ DrlEMImpl::DrlEMImpl() : jh(NULL), _execute_method(NULL) { nMethodsCompiled=0; nMethodsRecompiled=0; tick=0; - hymutex_create(&recompilationLock, TM_MUTEX_NESTED); + port_mutex_create(&recompilationLock, APR_THREAD_MUTEX_NESTED); initProfileAccess(); } DrlEMImpl::~DrlEMImpl() { deallocateResources(); - hymutex_destroy(&recompilationLock); + port_mutex_destroy(&recompilationLock); } void DrlEMImpl::initProfileAccess() { @@ -353,10 +354,6 @@ std::string DrlEMImpl::readConfiguration() { bool DrlEMImpl::init() { _execute_method = JIT_execute_method_default; - if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) { - disable_assert_dialogs(); - } - std::string config = readConfiguration(); if (!config.empty()) { buildChains(config); @@ -773,16 +770,16 @@ bool DrlEMImpl::initProfileCollectors(RChain* chain, const std::string& config) void DrlEMImpl::methodProfileIsReady(MethodProfile* mp) { - hymutex_lock(&recompilationLock); + port_mutex_lock(&recompilationLock); if (methodsInRecompile.find((Method_Profile_Handle)mp)!=methodsInRecompile.end()) { //method is already recompiling by another thread or by this thread(recursion) - hymutex_unlock(&recompilationLock); + port_mutex_unlock(&recompilationLock); return; } methodsInRecompile.insert((Method_Profile_Handle)mp); nMethodsRecompiled++; - hymutex_unlock(&recompilationLock); + port_mutex_unlock(&recompilationLock); const char* methodName = NULL; const char* className = NULL; @@ -826,9 +823,9 @@ void DrlEMImpl::methodProfileIsReady(MethodProfile* mp) { } } } - hymutex_lock(&recompilationLock); + port_mutex_lock(&recompilationLock); methodsInRecompile.erase((Method_Profile_Handle)mp); - hymutex_unlock(&recompilationLock); + port_mutex_unlock(&recompilationLock); } ProfileCollector* DrlEMImpl::getProfileCollector(EM_PCTYPE type, JIT_Handle jh, EM_JIT_PC_Role jitRole) const { diff --git a/vm/em/src/DrlEMImpl.h b/vm/em/src/DrlEMImpl.h index bd60424..fe05a87 100644 --- a/vm/em/src/DrlEMImpl.h +++ b/vm/em/src/DrlEMImpl.h @@ -131,7 +131,7 @@ private: uint32 tick; - hymutex_t recompilationLock; + osmutex_t recompilationLock; std::set methodsInRecompile; }; diff --git a/vm/em/src/EBProfileCollector.cpp b/vm/em/src/EBProfileCollector.cpp index 69f3c17..dfeb07b 100644 --- a/vm/em/src/EBProfileCollector.cpp +++ b/vm/em/src/EBProfileCollector.cpp @@ -26,6 +26,7 @@ #include "cxxlog.h" #include +#include "port_mutex.h" #define LOG_DOMAIN "em" @@ -52,7 +53,7 @@ EBProfileCollector::EBProfileCollector(EM_PC_Interface* em, const std::string& n INFO2(catName.c_str(), msg.str().c_str()); } - hymutex_create(&profilesLock, TM_MUTEX_NESTED); + port_mutex_create(&profilesLock, APR_THREAD_MUTEX_NESTED); } Method_Profile_Handle eb_profiler_create_profile(PC_Handle ph, Method_Handle mh) { @@ -112,24 +113,24 @@ EBProfileCollector::~EBProfileCollector() { delete profile; } - hymutex_destroy(&profilesLock); + port_mutex_destroy(&profilesLock); } MethodProfile* EBProfileCollector::getMethodProfile(Method_Handle mh) const { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); MethodProfile* res = NULL; EBProfilesMap::const_iterator it = profilesByMethod.find(mh); if (it != profilesByMethod.end()) { res = it->second; } - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return res; } EBMethodProfile* EBProfileCollector::createProfile(Method_Handle mh) { EBMethodProfile* profile = new EBMethodProfile(this, mh); - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); assert(profilesByMethod.find(mh) == profilesByMethod.end()); profilesByMethod[mh] = profile; @@ -138,7 +139,7 @@ EBMethodProfile* EBProfileCollector::createProfile(Method_Handle mh) { newProfiles.push_back(profile); } - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return profile; } @@ -159,10 +160,10 @@ static void logReadyProfile(const std::string& catName, const std::string& profi void EBProfileCollector::onTimeout() { assert(mode == EB_PCMODE_ASYNC); if(!newProfiles.empty()) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); greenProfiles.insert(greenProfiles.end(), newProfiles.begin(), newProfiles.end()); newProfiles.clear(); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); } if (!unloadedMethodProfiles.empty()) { @@ -177,10 +178,10 @@ void EBProfileCollector::onTimeout() { } } if (!tmpProfiles.empty()) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); std::remove(greenProfiles.begin(), greenProfiles.end(), (EBMethodProfile*)NULL); greenProfiles.resize(greenProfiles.size() - tmpProfiles.size()); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); for (EBProfiles::iterator it = tmpProfiles.begin(), end = tmpProfiles.end(); it!=end; ++it) { EBMethodProfile* profile = *it; if (loggingEnabled) { @@ -236,7 +237,7 @@ void EBProfileCollector::cleanUnloadedProfiles(bool removeFromGreen) { } void EBProfileCollector::classloaderUnloadingCallback(ClassLoaderHandle h) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); //can't modify profiles map in async mode here -> it could be iterated by the checker thread without lock bool erase = mode != EB_PCMODE_ASYNC; @@ -247,5 +248,5 @@ void EBProfileCollector::classloaderUnloadingCallback(ClassLoaderHandle h) { cleanUnloadedProfiles(false); } - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); } diff --git a/vm/em/src/EBProfileCollector.h b/vm/em/src/EBProfileCollector.h index 1f0d3af..1fe182c 100644 --- a/vm/em/src/EBProfileCollector.h +++ b/vm/em/src/EBProfileCollector.h @@ -97,7 +97,7 @@ private: EBProfiles unloadedMethodProfiles; - mutable hymutex_t profilesLock; + mutable osmutex_t profilesLock; }; class EBMethodProfile : public MethodProfile { diff --git a/vm/em/src/EdgeProfileCollector.cpp b/vm/em/src/EdgeProfileCollector.cpp index b7253d5..4a2c425 100644 --- a/vm/em/src/EdgeProfileCollector.cpp +++ b/vm/em/src/EdgeProfileCollector.cpp @@ -25,6 +25,7 @@ #include #include "cxxlog.h" #include +#include "port_mutex.h" #define LOG_DOMAIN "em" @@ -95,7 +96,7 @@ EdgeProfileCollector::EdgeProfileCollector(EM_PC_Interface* em, const std::strin : ProfileCollector(em, name, EM_PCTYPE_EDGE, genJit), initialTimeout(_initialTimeout), timeout(_timeout),eThreshold(_eThreshold), bThreshold(_bThreshold) { - hymutex_create(&profilesLock, TM_MUTEX_NESTED); + port_mutex_create(&profilesLock, APR_THREAD_MUTEX_NESTED); catName = std::string(LOG_DOMAIN) + ".profiler." + name; loggingEnabled = is_info_enabled(LOG_DOMAIN) || is_info_enabled(catName.c_str()); if (loggingEnabled) { @@ -113,19 +114,19 @@ EdgeProfileCollector::~EdgeProfileCollector() EdgeMethodProfile* profile = it->second; delete profile; } - hymutex_destroy(&profilesLock); + port_mutex_destroy(&profilesLock); } MethodProfile* EdgeProfileCollector::getMethodProfile(Method_Handle mh) const { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); MethodProfile* res = NULL; EdgeProfilesMap::const_iterator it = profilesByMethod.find(mh); if (it != profilesByMethod.end()) { res = it->second; } - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return res; } @@ -177,7 +178,7 @@ EdgeMethodProfile* EdgeProfileCollector::createProfile( Method_Handle mh, uint32* counterKeys, uint32 checkSum) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); EdgeMethodProfile* profile = new EdgeMethodProfile(this, mh); @@ -193,7 +194,7 @@ EdgeMethodProfile* EdgeProfileCollector::createProfile( Method_Handle mh, profilesByMethod[mh] = profile; newProfiles.push_back(profile); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return profile; } @@ -234,10 +235,10 @@ static void logReadyProfile(const std::string& catName, const std::string& profi void EdgeProfileCollector::onTimeout() { if(!newProfiles.empty()) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); greenProfiles.insert(greenProfiles.end(), newProfiles.begin(), newProfiles.end()); newProfiles.clear(); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); } if (!unloadedMethodProfiles.empty()) { @@ -255,10 +256,10 @@ void EdgeProfileCollector::onTimeout() { } if (!tmpProfiles.empty()) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); std::remove(greenProfiles.begin(), greenProfiles.end(), (EdgeMethodProfile*)NULL); greenProfiles.resize(greenProfiles.size() - tmpProfiles.size()); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); for (EdgeProfiles::iterator it = tmpProfiles.begin(), end = tmpProfiles.end(); it!=end; ++it) { EdgeMethodProfile* profile = *it; if (loggingEnabled) { @@ -298,11 +299,11 @@ static void addProfilesForClassloader(ClassLoaderHandle h, EdgeProfiles& from, E } void EdgeProfileCollector::classloaderUnloadingCallback(ClassLoaderHandle h) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); //can't modify profiles map in async mode here -> it could be iterated by the checker thread without lock addProfilesForClassloader(h, greenProfiles, unloadedMethodProfiles); addProfilesForClassloader(h, newProfiles, unloadedMethodProfiles); - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); } diff --git a/vm/em/src/EdgeProfileCollector.h b/vm/em/src/EdgeProfileCollector.h index 8f849f6..dda8463 100644 --- a/vm/em/src/EdgeProfileCollector.h +++ b/vm/em/src/EdgeProfileCollector.h @@ -71,7 +71,7 @@ private: EdgeProfiles newProfiles; EdgeProfiles tmpProfiles; EdgeProfiles unloadedMethodProfiles; - mutable hymutex_t profilesLock; + mutable osmutex_t profilesLock; }; class EdgeMethodProfile : public MethodProfile { diff --git a/vm/em/src/NValueProfileCollector.cpp b/vm/em/src/NValueProfileCollector.cpp index 77ac147..d8c27a5 100644 --- a/vm/em/src/NValueProfileCollector.cpp +++ b/vm/em/src/NValueProfileCollector.cpp @@ -298,7 +298,7 @@ void TNVTableDividedManager::addNewValue(ValueMethodProfile* methProfile, ValueMethodProfile* ValueProfileCollector::createProfile (Method_Handle mh, uint32 numkeys, uint32 keys[]) { - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); ValueMethodProfile* profile = new ValueMethodProfile(this, mh); // Allocate space for value maps for (uint32 index = 0; index < numkeys; index++){ @@ -309,7 +309,7 @@ ValueMethodProfile* ValueProfileCollector::createProfile } assert(profilesByMethod.find(mh) == profilesByMethod.end()); profilesByMethod[mh] = profile; - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return profile; } @@ -320,7 +320,7 @@ ValueProfileCollector::ValueProfileCollector(EM_PC_Interface* em, const std::str : ProfileCollector(em, name, EM_PCTYPE_VALUE, genJit), updateStrategy(update_strategy) { - hymutex_create(&profilesLock, TM_MUTEX_NESTED); + port_mutex_create(&profilesLock, APR_THREAD_MUTEX_NESTED); if (_TNV_algo_type == TNV_DIVIDED) { tnvTableManager = new TNVTableDividedManager (_TNV_steady_size, _TNV_clear_size, _clear_interval, update_strategy); @@ -346,18 +346,18 @@ ValueProfileCollector::~ValueProfileCollector() delete profile; } delete tnvTableManager; - hymutex_destroy(&profilesLock); + port_mutex_destroy(&profilesLock); } MethodProfile* ValueProfileCollector::getMethodProfile(Method_Handle mh) const { MethodProfile* res = NULL; - hymutex_lock(&profilesLock); + port_mutex_lock(&profilesLock); ValueProfilesMap::const_iterator it = profilesByMethod.find(mh); if (it != profilesByMethod.end()) { res = it->second; } - hymutex_unlock(&profilesLock); + port_mutex_unlock(&profilesLock); return res; } //------------------------------------------------------------------------------ @@ -365,12 +365,12 @@ MethodProfile* ValueProfileCollector::getMethodProfile(Method_Handle mh) const ValueMethodProfile::ValueMethodProfile(ValueProfileCollector* pc, Method_Handle mh) : MethodProfile(pc, mh), updatingState(0) { - hymutex_create(&lock, TM_MUTEX_DEFAULT); + port_mutex_create(&lock, APR_THREAD_MUTEX_DEFAULT); } ValueMethodProfile::~ValueMethodProfile() { - hymutex_destroy(&lock); + port_mutex_destroy(&lock); } void ValueMethodProfile::addNewValue diff --git a/vm/em/src/NValueProfileCollector.h b/vm/em/src/NValueProfileCollector.h index 85e1bc0..b0bb00f 100644 --- a/vm/em/src/NValueProfileCollector.h +++ b/vm/em/src/NValueProfileCollector.h @@ -27,6 +27,7 @@ #define _VALUE_PROFILE_COLLECTOR_H_ #include "DrlProfileCollectionFramework.h" +#include "port_mutex.h" #include "open/vm_util.h" #include @@ -166,7 +167,7 @@ private: bool loggingEnabled; typedef std::map ValueProfilesMap; ValueProfilesMap profilesByMethod; - mutable hymutex_t profilesLock; + mutable osmutex_t profilesLock; TNVTableManager* tnvTableManager; ProfileUpdateStrategy updateStrategy; }; @@ -193,8 +194,8 @@ class ValueMethodProfile : public MethodProfile { public: ValueMethodProfile(ValueProfileCollector* pc, Method_Handle mh); ~ValueMethodProfile(); - void lockProfile() {hymutex_lock(&lock);} - void unlockProfile() {hymutex_unlock(&lock);} + void lockProfile() {port_mutex_lock(&lock);} + void unlockProfile() {port_mutex_unlock(&lock);} void dumpValues(std::ostream& os); void addNewValue(uint32 instructionKey, POINTER_SIZE_INT valueToAdd); POINTER_SIZE_INT getResult(uint32 instructionKey); @@ -212,7 +213,7 @@ private: // The lock and the atomically modified updatingState flag operate per // method to allow simultaneous updates for distinct methods. - hymutex_t lock; + osmutex_t lock; uint8 updatingState; }; diff --git a/vm/gc_gen/src/common/gc_common.cpp b/vm/gc_gen/src/common/gc_common.cpp index 75ee11f..cca70e1 100644 --- a/vm/gc_gen/src/common/gc_common.cpp +++ b/vm/gc_gen/src/common/gc_common.cpp @@ -137,8 +137,6 @@ static size_t get_size_property(const char* name) void gc_parse_options(GC* gc) { TRACE2("gc.process", "GC: parse options ...\n"); - if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) - disable_assert_dialogs(); POINTER_SIZE_INT max_heap_size = HEAP_SIZE_DEFAULT; POINTER_SIZE_INT min_heap_size = min_heap_size_bytes; diff --git a/vm/include/open/hycomp.h b/vm/include/open/hycomp.h index 93cd7a5..2f756cb 100644 --- a/vm/include/open/hycomp.h +++ b/vm/include/open/hycomp.h @@ -182,12 +182,6 @@ typedef char I_8; #endif -#if !defined(FALSE) -#define FALSE ((BOOLEAN) 0) -#if !defined(TRUE) -#define TRUE ((BOOLEAN) (!FALSE)) -#endif -#endif #if !defined(NULL) #if defined(__cplusplus) diff --git a/vm/include/open/hycond_win.h b/vm/include/open/hycond_win.h index 01e3189..4c3f389 100644 --- a/vm/include/open/hycond_win.h +++ b/vm/include/open/hycond_win.h @@ -46,7 +46,7 @@ struct waiting_node { struct HyCond { // Synchronization is necessary because signal() caller is not required // to hold mutex associated with the condition variable. - hymutex_t queue_mutex; + osmutex_t queue_mutex; // head-tail marker node struct waiting_node dummy_node; }; diff --git a/vm/include/open/hythread_ext.h b/vm/include/open/hythread_ext.h index 176896c..666042a 100644 --- a/vm/include/open/hythread_ext.h +++ b/vm/include/open/hythread_ext.h @@ -143,12 +143,12 @@ extern "C" { #if defined(LINUX) || defined(FREEBSD) #include -#define hymutex_t pthread_mutex_t +#define osmutex_t pthread_mutex_t #define hycond_t pthread_cond_t #endif // LINUX || FREEBSD #ifdef _WIN32 -#define hymutex_t CRITICAL_SECTION +#define osmutex_t CRITICAL_SECTION #define hycond_t struct HyCond #include "hycond_win.h" #endif // _WIN32 @@ -308,7 +308,7 @@ typedef struct HyThread { /** * Thread local lock, used to serialize thread state; */ - hymutex_t mutex; + osmutex_t mutex; /** * Monitor used to implement wait function for sleep/park; @@ -473,10 +473,10 @@ IDATA VMCALL hythread_decrease_nondaemon_threads_count(hythread_t thread, IDATA //@{ IDATA VMCALL hycond_create (hycond_t *cond); -IDATA VMCALL hycond_wait (hycond_t *cond, hymutex_t *mutex); -IDATA VMCALL hycond_wait_timed (hycond_t *cond, hymutex_t *mutex, I_64 millis, IDATA nanos); -IDATA VMCALL hycond_wait_timed_raw(hycond_t * cond, hymutex_t * mutex, I_64 ms, IDATA nano); -IDATA VMCALL hycond_wait_interruptable (hycond_t *cond, hymutex_t *mutex, I_64 millis, IDATA nanos); +IDATA VMCALL hycond_wait (hycond_t *cond, osmutex_t *mutex); +IDATA VMCALL hycond_wait_timed (hycond_t *cond, osmutex_t *mutex, I_64 millis, IDATA nanos); +IDATA VMCALL hycond_wait_timed_raw(hycond_t * cond, osmutex_t * mutex, I_64 ms, IDATA nano); +IDATA VMCALL hycond_wait_interruptable (hycond_t *cond, osmutex_t *mutex, I_64 millis, IDATA nanos); IDATA VMCALL hycond_notify (hycond_t *cond); IDATA VMCALL hycond_notify_all (hycond_t *cond); IDATA VMCALL hycond_destroy (hycond_t *cond); @@ -537,17 +537,6 @@ IDATA VMCALL hysem_getvalue(IDATA *count, hysem_t sem); IDATA hysem_set(hysem_t sem, IDATA count); //@} -/** @name Mutex - */ -//@{ - -IDATA hymutex_create (hymutex_t *mutex, UDATA flags); -IDATA hymutex_lock(hymutex_t *mutex); -IDATA hymutex_trylock (hymutex_t *mutex); -IDATA hymutex_unlock (hymutex_t *mutex); -IDATA hymutex_destroy (hymutex_t *mutex); - -//@} /** @name Thin monitors support */ //@{ @@ -707,10 +696,6 @@ hy_inline void VMCALL hythread_suspend_disable() // has not called back into the VM or Java programming language code. #define TM_THREAD_STATE_IN_NATIVE JVMTI_THREAD_STATE_IN_NATIVE -#define TM_MUTEX_DEFAULT 0 -#define TM_MUTEX_NESTED 1 -#define TM_MUTEX_UNNESTED 2 - #define WAIT_INTERRUPTABLE 1 #define WAIT_NONINTERRUPTABLE 0 diff --git a/vm/include/open/platform_types.h b/vm/include/open/platform_types.h index b3c90d1..105414d 100644 --- a/vm/include/open/platform_types.h +++ b/vm/include/open/platform_types.h @@ -61,6 +61,7 @@ #ifndef FALSE #define FALSE 0 #endif + typedef unsigned Boolean; typedef unsigned char Byte; diff --git a/vm/interpreter/src/interp_exports.cpp b/vm/interpreter/src/interp_exports.cpp index 2cda17d..1189d53 100644 --- a/vm/interpreter/src/interp_exports.cpp +++ b/vm/interpreter/src/interp_exports.cpp @@ -122,13 +122,6 @@ void EXPORT JIT_init(JIT_Handle UNREF h, const char* UNREF name) { interpreter->interpreter_ti_notify_frame_pop = &interpreter_ti_notify_frame_pop; interpreter->interpreter_ti_pop_frame = &interpreter_ti_pop_frame; interpreter->stack_dump = &stack_dump; - -#if defined (PLATFORM_NT) && defined (_DEBUG) - if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) - { - disable_assert_dialogs(); - } -#endif } EXPORT Boolean JIT_supports_compressed_references(JIT_Handle UNREF jh) { diff --git a/vm/port/include/port_crash_handler.h b/vm/port/include/port_crash_handler.h index 9f2bbb2..deca7f1 100644 --- a/vm/port/include/port_crash_handler.h +++ b/vm/port/include/port_crash_handler.h @@ -15,7 +15,7 @@ * limitations under the License. */ -#ifdef _PORT_CRASH_HANDLER_ +#ifndef _PORT_CRASH_HANDLER_ #define _PORT_CRASH_HANDLER_ @@ -27,7 +27,7 @@ #include "port_frame_info.h" #ifdef __cplusplus -extern "C" +extern "C" { #endif /** @@ -38,7 +38,7 @@ typedef enum /** * General protection fault, e.g. SIGSEGV on unix. */ - PORT_SIGNAL_GPF, + PORT_SIGNAL_GPF = 0, /** * Special type of GPF when crash happens because of stack * overflow. It can be handled on the same stack because guard @@ -50,20 +50,31 @@ typedef enum */ PORT_SIGNAL_ABORT, /** - * Process executed a trap, e.g. INT3 on x86. + * Ctrl-\ combination was pressed. */ - PORT_SIGNAL_TRAP, + PORT_SIGNAL_QUIT, /** - * Process executed a privileged instruction (only on Windows), - * e.g. CLI. + * Ctrl-Break combination was pressed. */ - PORT_SIGNAL_PRIV_INSTR, + PORT_SIGNAL_CTRL_BREAK, + /** + * Ctrl-C combination was pressed. + */ + PORT_SIGNAL_CTRL_C, + /** + * Process met a breakpoint set with port_set_breakpoint(). + */ + PORT_SIGNAL_BREAKPOINT, /** * Process encountered an arithmeric error, e.g. division by * zero. */ PORT_SIGNAL_ARITHMETIC, /** + * Unknown signal - does not have a handler. + */ + PORT_SIGNAL_UNKNOWN, + /** * Maximum identifier for signal type */ PORT_SIGNAL_MIN = PORT_SIGNAL_GPF, @@ -83,13 +94,15 @@ typedef enum * @param signum - signal that in the thread. * @param regs - platform dependent register context of the process at * signal point. + * @param fault_addr - fault address. * @return TRUE if signal is handled by the process and * execution should continue. FALSE if signal is not handled * by the process and crash handler should execute crash sequence. */ -typedef Boolean (port_signal_handler *)( +typedef Boolean (*port_signal_handler)( port_sigtype signum, - Registers *regs); + Registers *regs, + void* fault_addr); /** * Signal callback registration information. @@ -124,7 +137,7 @@ typedef struct */ Boolean port_init_crash_handler( port_signal_handler_registration *registrations, - unsigned count + unsigned count, port_unwind_compiled_frame unwind_callback); /** @@ -178,19 +191,28 @@ typedef enum /** * Crash handler should create a core/mini dump of program state. */ - PORT_CRASH_DUMP_PROCESS_CORE = 0x400 + PORT_CRASH_DUMP_PROCESS_CORE = 0x0400 } port_crash_handler_flags; /** + * Returns supported features from the list of crash handler flags. + * When unsupported feature is requested, port_crash_handler_set_flags + * does not fail. + * + * @returns supported crash handler features. + */ +unsigned port_crash_handler_get_capabilities(); + +/** * Set crash handler output flags. Default mode is * PORT_CRASH_DUMP_TO_STDERR | * PORT_CRASH_STACK_DUMP | PORT_CRASH_PRINT_COMMAND_LINE | * PORT_CRASH_PRINT_ENVIRONMENT | PORT_CRASH_PRINT_MODULES | - * PORT_CRASH_PRINT_REGISTERS | PORT_CRASH_PRINT_THREADS_LIST. + * PORT_CRASH_PRINT_REGISTERS. * * @param flags - crash handler output flags. */ -void port_crash_handler_set_flags(port_crash_handler_flags flags); +void port_crash_handler_set_flags(unsigned flags); /** * Callback function that is called at the end of shutdown sequence. @@ -201,8 +223,12 @@ void port_crash_handler_set_flags(port_crash_handler_flags flags); * @param signum - signal that in the thread. * @param regs - platform dependent register context of the process at * signal point. + * @param fault_addr - fault address. */ -typedef void (port_crash_handler_action *)(port_sigtype signum, Registers *regs); +typedef void (*port_crash_handler_action)( + port_sigtype signum, + Registers *regs, + void* fault_addr); /** * Add an action to be done at the end of crash sequence. Actions may @@ -231,8 +257,39 @@ Boolean port_crash_handler_add_action(port_crash_handler_action action); */ Boolean port_shutdown_crash_handler(); + +/** +* Instruments specified location to produce PORT_SIGNAL_BREAKPOINT event. +* @param [in] addr - memory location to instrument. +* @param [out] prev - address to store previous value of the instrumented byte. +* @return 0 if OK; nonzero if the location is already +* instrumented or if an error occured. +* @note Caller should keep store previous byte to restore +* the location in future. +*/ +int port_set_breakpoint(void* addr, unsigned char* prev); + +/** +* Restores original byte in the location previously instrumented +* with port_set_breakpoint. +* @param [in] addr - memory location to deinstrument. +* @param [in] prev - previous byte to restore. +* @return 0 if OK; nonzero if the location was not +* instrumented yet or if an error occured. +*/ +int port_clear_breakpoint(void* addr, unsigned char prev); + +/** +* Checks if the location is instrumented. +* @param [in] addr - memory location to deinstrument. +* @return TRUE if instrumented; FALSE otherwise. +*/ +Boolean port_is_breakpoint_set(void* addr); + + + #ifdef __cplusplus } #endif -#endif // _PORT_CRASH_HANDLER_ +#endif /* _PORT_CRASH_HANDLER_ */ diff --git a/vm/port/include/port_frame_info.h b/vm/port/include/port_frame_info.h index 781620a..5b85566 100644 --- a/vm/port/include/port_frame_info.h +++ b/vm/port/include/port_frame_info.h @@ -15,7 +15,7 @@ * limitations under the License. */ -#ifdef _PORT_FRAME_INFO_ +#ifndef _PORT_FRAME_INFO_ #define _PORT_FRAME_INFO_ #include "open/platform_types.h" @@ -32,19 +32,19 @@ typedef struct { /** * Method class name executed at specified stack frame */ - char *method_class_name; + const char *method_class_name; /** * Method name executed at specified stack frame */ - char *method_name; + const char *method_name; /** * Method signature executed at specified stack frame */ - char *method_signature; + const char *method_signature; /** * Method source file executed at specified stack frame */ - char *source_file_name; + const char *source_file_name; /** * Source line number */ @@ -75,8 +75,8 @@ typedef struct { * allocated in frame_info->iteration_state. Zero if unwinding is * successful and -1 if unwinding is not successful. */ -typedef int (port_unwind_compiled_frame *)(Registers *regs, +typedef int (*port_unwind_compiled_frame)(Registers *regs, port_stack_frame_info *frame_info); -#endif // _PORT_FRAME_INFO_ +#endif /* _PORT_FRAME_INFO_ */ diff --git a/vm/port/include/port_general.h b/vm/port/include/port_general.h index 20ec145..754dd4c 100644 --- a/vm/port/include/port_general.h +++ b/vm/port/include/port_general.h @@ -23,6 +23,7 @@ #define _PORT_GENERAL_H_ #include +#include #ifndef NULL #ifdef __cplusplus @@ -32,24 +33,30 @@ #endif /* __cplusplus */ #endif /* NULL */ +#ifdef WIN32 +#define PORT_PATH_MAX _MAX_PATH +#else /* !WIN32 */ +#define PORT_PATH_MAX PATH_MAX +#endif + #ifdef __cplusplus #define PORT_INLINE inline -#else // !__cplusplus +#else /* !__cplusplus */ #ifdef WIN32 #define PORT_INLINE __forceinline -#else // !WIN32 +#else /* !WIN32 */ #ifdef __linux__ #define PORT_INLINE static __attribute__((always_inline)) -#else // !__linux__ +#else /* !__linux__ */ #define PORT_INLINE static -#endif // __linux__ +#endif /* __linux__ */ -#endif // WIN32 +#endif /* WIN32 */ -#endif // __cplusplus +#endif /* __cplusplus */ #endif /* _PORT_GENERAL_H_ */ diff --git a/vm/port/include/port_memaccess.h b/vm/port/include/port_memaccess.h new file mode 100644 index 0000000..3122cae --- /dev/null +++ b/vm/port/include/port_memaccess.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef _PORT_MEMACCESS_H_ +#define _PORT_MEMACCESS_H_ + +#include +#include "open/platform_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** +* Tries to read specified number of bytes from given address into buffer. +* @param addr - memory address to read. +* @param size - size of bytes to read. +* @param buf - buffer to read to. +* @return 0 if OK; nonzero if an error occured. +*/ +int port_read_memory(void* addr, size_t size, void* buf); + +/** +* Tries to write specified number of bytes from buffer to given address. +* @param addr - memory address to write. +* @param size - size of bytes to write. +* @param buf - buffer to write from. +* @return 0 if OK; nonzero if an error occured. +*/ +int port_write_memory(void* addr, size_t size, void* buf); + + +#ifdef __cplusplus +} +#endif + +#endif /* _PORT_MEMACCESS_H_ */ diff --git a/vm/port/include/port_modules.h b/vm/port/include/port_modules.h index 2b382f0..3bd59bd 100644 --- a/vm/port/include/port_modules.h +++ b/vm/port/include/port_modules.h @@ -19,12 +19,12 @@ * @version $Revision: 1.1.2.1 $ */ -#ifndef _NATIVE_MODULES_H_ -#define _NATIVE_MODULES_H_ +#ifndef _PORT_MODULES_H_ +#define _PORT_MODULES_H_ #include #include -#include "open/types.h" +#include "open/platform_types.h" typedef enum { @@ -89,4 +89,4 @@ native_module_t* port_find_module(native_module_t* modules, void* code_ptr); } #endif -#endif // _NATIVE_MODULES_H_ +#endif // _PORT_MODULES_H_ diff --git a/vm/port/include/port_mutex.h b/vm/port/include/port_mutex.h new file mode 100644 index 0000000..35d8478 --- /dev/null +++ b/vm/port/include/port_mutex.h @@ -0,0 +1,157 @@ +/* + * 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. + */ + +#ifndef _PORT_MUTEX_H_ +#define _PORT_MUTEX_H_ + +/** + * @file port_mutex.h + * @brief PORT mutex support + */ + +/* error codes */ +#include "apr_errno.h" +/* mutex flags */ +#include "apr_thread_mutex.h" +/* osmutex_t type */ +#include "open/hythread_ext.h" + +#include "port_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup port_mutex Basic mutexes + * @ingroup port_apr + * @{ + */ + +/** + * Initializes a mutex. + * + * A memory for mutex must be preallocated. + * + * @param[in] mutex the address of the mutex to be initialized + * @param[in] flags Or'ed value of: + *
+ *           APR_THREAD_MUTEX_DEFAULT   platform-optimal lock behavior.
+ *           APR_THREAD_MUTEX_NESTED    enable nested (recursive) locks.
+ *           APR_THREAD_MUTEX_UNNESTED  disable nested locks (non-recursive).
+ * 
+ */ +PORT_INLINE apr_status_t port_mutex_create(osmutex_t *mutex, UDATA flags) { +#if defined(WIN32) + int r = 0; + if (flags & APR_THREAD_MUTEX_UNNESTED) { + assert(!"not implemented"); + return -1; + } + InitializeCriticalSection(mutex); + return r; +#else /* PTHREADS */ + int r = 0; + if (flags & APR_THREAD_MUTEX_NESTED) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + r = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + if (r) return r; + r = pthread_mutex_init(mutex, &attr); + pthread_mutexattr_destroy(&attr); + } else { + r = pthread_mutex_init(mutex, NULL); + } + return r; +#endif +} + +/** + * Acquires the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * + * @param[in] mutex the mutex on which to acquire the lock. + * @sa apr_thread_mutex_lock() + */ +PORT_INLINE apr_status_t port_mutex_lock(osmutex_t *mutex) { +#if defined(WIN32) + EnterCriticalSection(mutex); + return 0; +#else /* PTHREADS */ + return pthread_mutex_lock(mutex); +#endif +} + +/** + * Attempts to acquire the lock for the given mutex. + * + * @param[in] mutex the mutex on which to attempt the lock acquiring. + * @sa apr_thread_mutex_trylock() + */ +PORT_INLINE apr_status_t port_mutex_trylock(osmutex_t *mutex) { +#if defined(WIN32) + int r; + r = TryEnterCriticalSection(mutex); + // Return code is non-zero on success + if (r == 0) return TM_ERROR_EBUSY; + return 0; +#else /* PTHREADS */ + int r; + r = pthread_mutex_trylock(mutex); + if (r == EBUSY) return TM_ERROR_EBUSY; + return r; +#endif +} + +/** + * Releases the lock for the given mutex. + * + * @param[in] mutex the mutex from which to release the lock. + * @sa apr_thread_mutex_unlock() + */ +PORT_INLINE apr_status_t port_mutex_unlock(osmutex_t *mutex) { +#if defined(WIN32) + LeaveCriticalSection(mutex); + return 0; +#else /* PTHREADS */ + return pthread_mutex_unlock(mutex); +#endif +} + +/** + * Destroys the mutex. + * + * @param[in] mutex the mutex to destroy. + * @sa apr_thread_mutex_destroy() + */ +PORT_INLINE apr_status_t port_mutex_destroy(osmutex_t *mutex) { +#if defined(WIN32) + DeleteCriticalSection(mutex); + return 0; +#else /* PTHREADS */ + return pthread_mutex_destroy(mutex); +#endif +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PORT_MUTEX_H_ */ diff --git a/vm/port/include/port_thread.h b/vm/port/include/port_thread.h index 78904bb..85014ba 100644 --- a/vm/port/include/port_thread.h +++ b/vm/port/include/port_thread.h @@ -23,9 +23,10 @@ * @brief PORT thread support */ -/* For osthread_t and thread_context_t types */ +/* osthread_t and thread_context_t types, and proper windows.h inclusion */ #include "open/hythread_ext.h" +#include "port_general.h" /* Thread context definition for UNIX-like systems */ #if defined(LINUX) || defined(FREEBSD) @@ -61,10 +62,19 @@ extern "C" { */ //@{ +PORT_INLINE int port_gettid() +{ +#ifdef PLATFORM_POSIX + return gettid(); +#else + return (int)GetCurrentThreadId(); +#endif +} void port_thread_yield_other(osthread_t thread); int port_thread_cancel(osthread_t os_thread); + int port_thread_suspend(osthread_t thread); int port_thread_resume(osthread_t thread); int port_thread_get_suspend_count(osthread_t thread); diff --git a/vm/port/include/port_unwind.h b/vm/port/include/port_unwind.h new file mode 100644 index 0000000..8067073 --- /dev/null +++ b/vm/port/include/port_unwind.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef __PORT_UNWIND_H__ +#define __PORT_UNWIND_H__ + +#include "port_modules.h" + +typedef struct UnwindContext { + native_module_t* modules; + bool clean_modules; + native_segment_t stack; +} UnwindContext; + +#ifdef __cplusplus +extern "C" { +#endif + + +bool port_init_unwind_context(UnwindContext* context, native_module_t* modules, Registers* regs); +void port_clean_unwind_context(UnwindContext* context); + +bool port_unwind_frame(UnwindContext* context, Registers* regs); + + +#ifdef __cplusplus +} +#endif + +#endif // __PORT_UNWIND_H__ diff --git a/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp b/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp index c8f139c..9998228 100644 --- a/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp +++ b/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp @@ -19,13 +19,12 @@ * @version $Revision: 1.1.2.1 $ */ -#include "method_lookup.h" #include "dec_base.h" -#include "native_modules.h" -#include "native_stack.h" +#include "port_modules.h" +#include "native_unwind.h" -bool native_is_frame_exists(WalkContext* context, Registers* regs) +bool native_is_frame_exists(UnwindContext* context, Registers* regs) { // Check for frame layout and stack values if ((regs->rbp < regs->rsp) || !native_is_in_stack(context, (void*)regs->rbp)) @@ -35,10 +34,10 @@ bool native_is_frame_exists(WalkContext* context, Registers* regs) void* rip = frame_ptr[1]; // Return address // Check return address for meaning - return (native_is_in_code(context, rip) || native_is_ip_stub(rip)); + return (native_is_in_code(context, rip)); } -bool native_unwind_stack_frame(WalkContext* context, Registers* regs) +bool native_unwind_stack_frame(UnwindContext* context, Registers* regs) { void** frame = (void**)regs->rbp; @@ -49,7 +48,7 @@ bool native_unwind_stack_frame(WalkContext* context, Registers* regs) if (native_is_in_stack(context, rsp) && - (native_is_in_code(context, rip) || native_is_ip_stub(rip))) + (native_is_in_code(context, rip))) { regs->rbp = (uint64)rbp; regs->rsp = (uint64)rsp; @@ -60,14 +59,7 @@ bool native_unwind_stack_frame(WalkContext* context, Registers* regs) return false; } -void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) -{ - regs->rip = *jfc->p_rip; - regs->rbp = *jfc->p_rbp; - regs->rsp = jfc->rsp; -} - -static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) +static bool fill_regs_from_sp(UnwindContext* context, Registers* regs, void** sp) { regs->rsp = (uint64)(sp + 1); regs->rip = (uint64)*sp; @@ -75,7 +67,7 @@ static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) return true; } -static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) +static unsigned native_dec_instr(UnwindContext* context, void* addr, void** target) { Inst inst; @@ -95,7 +87,7 @@ static unsigned native_dec_instr(WalkContext* context, void* addr, void** target return len; } -static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) +static bool native_check_caller(UnwindContext* context, Registers* regs, void** sp) { void* target = NULL; char* ptr = (char*)*sp; @@ -127,7 +119,7 @@ static bool native_check_caller(WalkContext* context, Registers* regs, void** sp #define MAX_SPECIAL_DEPTH 0x900 #define NATIVE_STRICT_UNWINDING 1 -bool native_unwind_special(WalkContext* context, Registers* regs) +bool native_unwind_special(UnwindContext* context, Registers* regs) { for (void** cur_sp = (void**)regs->rsp; (char*)cur_sp < ((char*)regs->rsp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); @@ -146,15 +138,3 @@ bool native_unwind_special(WalkContext* context, Registers* regs) return false; } - -void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) -{ - frame->java_depth = jdepth; - - if (!regs) - return; - - frame->ip = (void*)regs->rip; - frame->frame = (void*)regs->rbp; - frame->stack = (void*)regs->rsp; -} diff --git a/vm/port/src/crash_handler/em64t/reg_state.cpp b/vm/port/src/crash_handler/em64t/reg_state.cpp index b79c436..56a0c25 100644 --- a/vm/port/src/crash_handler/em64t/reg_state.cpp +++ b/vm/port/src/crash_handler/em64t/reg_state.cpp @@ -16,7 +16,9 @@ */ #include -#include "vm_core_types.h" +#include "open/platform_types.h" +#include "stack_dump.h" + void print_reg_state(Registers* regs) { diff --git a/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp b/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp index cbfc211..bc93d34 100644 --- a/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp +++ b/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp @@ -19,13 +19,12 @@ * @version $Revision: 1.1.2.1 $ */ -#include "method_lookup.h" #include "dec_base.h" -#include "native_modules.h" -#include "native_stack.h" +#include "port_modules.h" +#include "native_unwind.h" -bool native_is_frame_exists(WalkContext* context, Registers* regs) +bool native_is_frame_exists(UnwindContext* context, Registers* regs) { // Check for frame layout and stack values if ((regs->ebp < regs->esp) || !native_is_in_stack(context, (void*)regs->ebp)) @@ -35,10 +34,10 @@ bool native_is_frame_exists(WalkContext* context, Registers* regs) void* eip = frame_ptr[1]; // Return address // Check return address for meaning - return (native_is_in_code(context, eip) || native_is_ip_stub(eip)); + return (native_is_in_code(context, eip)); } -bool native_unwind_stack_frame(WalkContext* context, Registers* regs) +bool native_unwind_stack_frame(UnwindContext* context, Registers* regs) { void** frame = (void**)regs->ebp; @@ -49,7 +48,7 @@ bool native_unwind_stack_frame(WalkContext* context, Registers* regs) if (native_is_in_stack(context, esp) && - (native_is_in_code(context, eip) || native_is_ip_stub(eip))) + (native_is_in_code(context, eip))) { regs->ebp = (uint32)ebp; regs->esp = (uint32)esp; @@ -60,14 +59,7 @@ bool native_unwind_stack_frame(WalkContext* context, Registers* regs) return false; } -void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) -{ - regs->eip = *jfc->p_eip; - regs->ebp = *jfc->p_ebp; - regs->esp = jfc->esp; -} - -static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) +static bool fill_regs_from_sp(UnwindContext* context, Registers* regs, void** sp) { regs->esp = (uint32)(sp + 1); regs->eip = (uint32)*sp; @@ -75,7 +67,7 @@ static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) return true; } -static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) +static unsigned native_dec_instr(UnwindContext* context, void* addr, void** target) { Inst inst; @@ -95,7 +87,7 @@ static unsigned native_dec_instr(WalkContext* context, void* addr, void** target return len; } -static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) +static bool native_check_caller(UnwindContext* context, Registers* regs, void** sp) { void* target = NULL; char* ptr = (char*)*sp; @@ -127,7 +119,7 @@ static bool native_check_caller(WalkContext* context, Registers* regs, void** sp #define MAX_SPECIAL_DEPTH 0x400 #define NATIVE_STRICT_UNWINDING 1 -bool native_unwind_special(WalkContext* context, Registers* regs) +bool native_unwind_special(UnwindContext* context, Registers* regs) { for (void** cur_sp = (void**)regs->esp; (char*)cur_sp < ((char*)regs->esp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); @@ -146,15 +138,3 @@ bool native_unwind_special(WalkContext* context, Registers* regs) return false; } - -void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) -{ - frame->java_depth = jdepth; - - if (!regs) - return; - - frame->ip = (void*)regs->eip; - frame->frame = (void*)regs->ebp; - frame->stack = (void*)regs->esp; -} diff --git a/vm/port/src/crash_handler/ia32/reg_state.cpp b/vm/port/src/crash_handler/ia32/reg_state.cpp index 0ac5a4c..47af028 100644 --- a/vm/port/src/crash_handler/ia32/reg_state.cpp +++ b/vm/port/src/crash_handler/ia32/reg_state.cpp @@ -16,7 +16,9 @@ */ #include -#include "vm_core_types.h" +#include "open/platform_types.h" +#include "stack_dump.h" + void print_reg_state(Registers* regs) { diff --git a/vm/port/src/crash_handler/include/native_unwind.h b/vm/port/src/crash_handler/include/native_unwind.h new file mode 100644 index 0000000..a91043e --- /dev/null +++ b/vm/port/src/crash_handler/include/native_unwind.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + + +#ifndef __NATIVE_UNWIND_H__ +#define __NATIVE_UNWIND_H__ + +#include "port_modules.h" +#include "port_unwind.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +// Interchange between platform-dependent and general functions + +bool native_unwind_stack_frame(UnwindContext* context, Registers* regs); +bool native_get_stack_range(UnwindContext* context, Registers* regs, native_segment_t* seg); +bool native_is_frame_exists(UnwindContext* context, Registers* regs); +bool native_unwind_special(UnwindContext* context, Registers* regs); +bool native_is_in_code(UnwindContext* context, void* ip); +bool native_is_in_stack(UnwindContext* context, void* sp); + + +#ifdef __cplusplus +} +#endif + +#endif /* !__NATIVE_UNWIND_H__ */ diff --git a/vm/port/src/crash_handler/include/stack_dump.h b/vm/port/src/crash_handler/include/stack_dump.h index 8126316..d7e8b29 100644 --- a/vm/port/src/crash_handler/include/stack_dump.h +++ b/vm/port/src/crash_handler/include/stack_dump.h @@ -14,72 +14,55 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @author Vladimir Nenashev - * @version $Revision$ - */ -#ifndef __STACK_DUMP_H_ -#define __STACK_DUMP_H_ +#ifndef __STACK_DUMP_H__ +#define __STACK_DUMP_H__ -#include "open/hythread_ext.h" -#include "vm_core_types.h" -#include "jni.h" -#include "native_modules.h" +#include "open/platform_types.h" +#include "port_general.h" +#include "port_modules.h" +#include "port_crash_handler.h" -#ifdef _DEBUG -#define SD_UPDATE_MODULES -#endif +#define SD_MNAME_LENGTH 2048 -#ifdef SD_UPDATE_MODULES -#define sd_update_modules() sd_update_modules() -#else -#define sd_update_modules() -#endif +/** + * Symbolic method info: + * method name, source file name and a line number of an instruction + * within the method + */ +struct CFunInfo { + char name[SD_MNAME_LENGTH]; + char filename[PORT_PATH_MAX]; + int line; +}; -#ifdef PLATFORM_POSIX -#include -#define strcmp_case strcasecmp -#else // Win -#include -#define strcmp_case _stricmp +#ifdef __cplusplus +extern "C" { #endif -#include "platform_lowlevel.h" +void sd_init_crash_handler(); +void sd_cleanup_crash_handler(); +void sd_get_c_method_info(CFunInfo* info, native_module_t* module, void* ip); +void sd_print_cmdline_cwd(); +void sd_print_environment(); -#define SD_MNAME_LENGTH 2048 +unsigned port_crash_handler_get_flags(); +int initialize_signals(); +int shutdown_signals(); -// Symbolic method info: method name, source file name and a line number of an instruction within the method -struct MethodInfo { - char method_name[SD_MNAME_LENGTH]; - char file_name[_MAX_PATH]; - int line; -}; +void sd_print_crash_info(int signum, Registers* regs, port_unwind_compiled_frame unwind); +void print_reg_state(Registers* regs); -/** - * Prints a stack trace using given register context for current thread - */ -void sd_print_stack(Registers* regs); +/* Returns 0 when execution should be continued with (updated) Registers + Returns 1 when crash occured and process should invoke a debugger + Returns -1 when crash occured and process should be terminated */ +int port_process_signal(port_sigtype signum, Registers *regs, void* fault_addr, Boolean iscrash); -/** - * Updates modules list for crash reporting - */ -#ifdef SD_UPDATE_MODULES -void sd_update_modules(); +#ifdef __cplusplus +} #endif -// platform-dependent functions -bool sd_initialize(hymutex_t** p_lock); -void sd_parse_module_info(native_module_t* module, void* ip); -void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip); -int sd_get_cur_tid(); -void sd_init_crash_handler(); -void sd_print_cwdcmdenv(); - -// general functions to call from platform-dependent code -const char* sd_get_module_type(const char* short_name); - -#endif //!__STACK_DUMP_H_ +#endif /* !__STACK_DUMP_H__ */ diff --git a/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp b/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp index e91c555..dbba0cc 100644 --- a/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp +++ b/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp @@ -19,28 +19,20 @@ * @version $Revision: 1.1.2.1 $ */ -#include "native_stack.h" +#include "native_unwind.h" -bool native_is_frame_exists(WalkContext* UNREF context, Registers* UNREF regs) +bool native_is_frame_exists(UnwindContext* UNREF context, Registers* UNREF regs) { return false; } -bool native_unwind_stack_frame(WalkContext* UNREF context, Registers* UNREF regs) +bool native_unwind_stack_frame(UnwindContext* UNREF context, Registers* UNREF regs) { return false; } -void native_get_regs_from_jit_context(JitFrameContext* UNREF jfc, Registers* UNREF regs) -{ -} - -bool native_unwind_special(WalkContext* UNREF context, Registers* UNREF regs) +bool native_unwind_special(UnwindContext* UNREF context, Registers* UNREF regs) { return false; } - -void native_fill_frame_info(Registers* UNREF regs, native_frame_t* UNREF frame, jint UNREF jdepth) -{ -} diff --git a/vm/port/src/crash_handler/ipf/reg_state.cpp b/vm/port/src/crash_handler/ipf/reg_state.cpp index 149cb94..d3e413c 100644 --- a/vm/port/src/crash_handler/ipf/reg_state.cpp +++ b/vm/port/src/crash_handler/ipf/reg_state.cpp @@ -16,7 +16,9 @@ */ #include -#include "vm_core_types.h" +#include "open/platform_types.h" +#include "stack_dump.h" + void print_reg_state(Registers* regs) { diff --git a/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp index 16b0bf1..e9b9e58 100644 --- a/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp +++ b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp @@ -24,19 +24,16 @@ #include #include -#include "vm_core_types.h" -#include "environment.h" +#include "open/platform_types.h" #include "port_sysinfo.h" -#include "platform_lowlevel.h" -#include "exception_filter.h" #include "port_thread.h" +#include "port_malloc.h" -#include "crash_handler.h" +#include "../linux/include/gdb_crash_handler.h" static char* g_executable = NULL;// Executable file name static sem_t g_sem_started; // Prevent forking debugger more than once static bool g_prepared = false; // Flag is set if gdb crash handler is prepared -static bool g_enabled = false; // vm.crash_handler value is stored here #if defined (__INTEL_COMPILER) @@ -45,21 +42,12 @@ static bool g_enabled = false; // vm.crash_handler value is stored here #endif -bool is_gdb_crash_handler_enabled() -{ - return (g_prepared && g_enabled); -} - bool gdb_crash_handler(Registers* regs) { - if (!g_prepared || !g_enabled || - !g_executable || + if (!g_prepared || !g_executable || 0 != sem_trywait(&g_sem_started)) // gdb was already started return false; - // Print register info - print_reg_state(regs); - static const int tid_len = 10; char tid[tid_len]; snprintf(tid, tid_len, "%d", gettid()); @@ -94,19 +82,22 @@ static int get_executable_name() } -void init_gdb_crash_handler() +bool init_gdb_crash_handler() { if (sem_init(&g_sem_started, 0, 1) != 0 || get_executable_name() != 0) { g_prepared = false; - return; + return false; } - if (!VM_Global_State::loader_env) - g_enabled = true; - else - g_enabled = get_boolean_property("vm.crash_handler", FALSE, VM_PROPERTIES); - g_prepared = true; + return true; +} + + +void cleanup_gdb_crash_handler() +{ + STD_FREE(g_executable); + g_prepared = false; } diff --git a/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h b/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h index 333b646..c94fc4c 100644 --- a/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h +++ b/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h @@ -22,7 +22,7 @@ #ifndef _CRASH_HANDLER_H #define _CRASH_HANDLER_H -#include "vm_core_types.h" +#include "open/platform_types.h" /** * \file @@ -30,18 +30,16 @@ */ /** - * Checks if gdb crash handler is enabled and prepared. + * Initializes the static state needed for gdb crash handler. * - * @return true if gdb crash handler is enabled and ready for use. + * @return true on success or false on failure */ -bool is_gdb_crash_handler_enabled(); +bool init_gdb_crash_handler(); /** * Initializes the static state needed for gdb crash handler. - * - * @return 0 on success or negative value on failure */ -void init_gdb_crash_handler(); +void cleanup_gdb_crash_handler(); /** * Invokes gdb. diff --git a/vm/port/src/crash_handler/linux/native_unwind_os.cpp b/vm/port/src/crash_handler/linux/native_unwind_os.cpp index 5af1425..7493d9c 100644 --- a/vm/port/src/crash_handler/linux/native_unwind_os.cpp +++ b/vm/port/src/crash_handler/linux/native_unwind_os.cpp @@ -17,11 +17,11 @@ #include -#include "native_modules.h" -#include "native_stack.h" +#include "port_modules.h" +#include "native_unwind.h" -bool native_is_in_code(WalkContext* context, void* ip) +bool native_is_in_code(UnwindContext* context, void* ip) { if (!ip) return false; @@ -41,7 +41,7 @@ bool native_is_in_code(WalkContext* context, void* ip) return false; } -bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) +bool native_get_stack_range(UnwindContext* context, Registers* regs, native_segment_t* seg) { int err; pthread_attr_t pthread_attr; diff --git a/vm/port/src/crash_handler/linux/stack_dump_os.cpp b/vm/port/src/crash_handler/linux/stack_dump_os.cpp index 1bfd0c6..57b83b0 100644 --- a/vm/port/src/crash_handler/linux/stack_dump_os.cpp +++ b/vm/port/src/crash_handler/linux/stack_dump_os.cpp @@ -16,57 +16,24 @@ */ #include -#include #include +#include +#include #include #include #include #include +#include +#include -#include "open/hythread_ext.h" -#include "native_stack.h" -#include "port_filepath.h" #include "port_dso.h" -#include "port_thread.h" +#include "port_malloc.h" #include "stack_dump.h" -static hymutex_t g_lock; -static const char* g_curdir = NULL; -static const char* g_cmdline = NULL; - - -bool sd_initialize(hymutex_t** p_lock) -{ - static int initialized = 0; - - if (!initialized) - { - IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); - - if (err != APR_SUCCESS) - return false; - - initialized = true; - } - - if (p_lock) - *p_lock = &g_lock; - - return true; -} - - -static bool sd_is_predefined_name(const char* name) -{ - if (*name != '[') - return false; +static char* g_curdir = NULL; +static char* g_cmdline = NULL; - return true; -// return (!strcmp(name, "[heap]") || -// !strcmp(name, "[stack]") || -// !strcmp(name, "[vdso]")); -} static inline native_segment_t* sd_find_segment(native_module_t* module, void* ip) { @@ -81,48 +48,10 @@ static inline native_segment_t* sd_find_segment(native_module_t* module, void* i return NULL; } -void sd_parse_module_info(native_module_t* module, void* ip) -{ - fprintf(stderr, "\nCrashed module:\n"); - - if (!module) - { // Unknown address - fprintf(stderr, "Unknown address 0x%"W_PI_FMT"\n", - (POINTER_SIZE_INT)ip); - return; - } - - native_segment_t* segment = sd_find_segment(module, ip); - - if (!module->filename) - { - fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - if (sd_is_predefined_name(module->filename)) - { // Special memory region - fprintf(stderr, "%s memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - module->filename, - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - // Common shared module - const char* short_name = port_filepath_basename(module->filename); - const char* module_type = sd_get_module_type(short_name); - - fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); -} - - -void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) +void sd_get_c_method_info(CFunInfo* info, native_module_t* module, void* ip) { - *info->method_name = 0; - *info->file_name = 0; + *info->name = 0; + *info->filename = 0; info->line = -1; if (!module || !module->filename) @@ -154,7 +83,7 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) else { close(po[1]); - char buf[sizeof(info->method_name) + sizeof(info->file_name)]; + char buf[sizeof(info->name) + sizeof(info->filename)]; int status; wait(&status); int count = read(po[0], buf, sizeof(buf) - 1); @@ -177,7 +106,7 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) if (buf[i] == '\n') { // Function name is limited by '\n' buf[i] = '\0'; - strncpy(info->method_name, buf, sizeof(info->method_name)); + strncpy(info->name, buf, sizeof(info->name)); break; } } @@ -193,7 +122,7 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) return; buf[i] = '\0'; - strncpy(info->file_name, fn, sizeof(info->file_name)); + strncpy(info->filename, fn, sizeof(info->filename)); info->line = atoi(buf + i + 1); // Line number @@ -202,11 +131,6 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) } } -int sd_get_cur_tid() -{ - return gettid(); -} - void sd_init_crash_handler() { // Get current directory @@ -251,15 +175,24 @@ void sd_init_crash_handler() } } -void sd_print_cwdcmdenv() +void sd_cleanup_crash_handler() { - fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); + STD_FREE(g_curdir); + STD_FREE(g_cmdline); +} +void sd_print_cmdline_cwd() +{ fprintf(stderr, "\nCommand line:\n"); for (const char* ptr = g_cmdline; *ptr; ptr += strlen(ptr) + 1) fprintf(stderr, "%s ", ptr); fprintf(stderr, "\n"); + fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); +} + +void sd_print_environment() +{ fprintf(stderr, "\nEnvironment variables:\n"); for (char** env = environ; *env; ++env) fprintf(stderr, "%s\n", *env); diff --git a/vm/port/src/crash_handler/native_unwind.cpp b/vm/port/src/crash_handler/native_unwind.cpp new file mode 100644 index 0000000..861351d --- /dev/null +++ b/vm/port/src/crash_handler/native_unwind.cpp @@ -0,0 +1,98 @@ +/* + * 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 + * @version $Revision: 1.1.2.1 $ + */ + +#include +#include "port_modules.h" +#include "native_unwind.h" + + +////////////////////////////////////////////////////////////////////////////// +/// Helper functions + +bool native_is_in_stack(UnwindContext* context, void* sp) +{ + return (sp >= context->stack.base && + sp < (char*)context->stack.base + context->stack.size); +} + +/// Helper functions +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +// + +bool port_init_unwind_context(UnwindContext* context, native_module_t* modules, Registers* regs) +{ + if (!context) + return false; + + if (!modules) + { + int mod_count; + native_module_t* mod_list = NULL; + + if (!port_get_all_modules(&mod_list, &mod_count)) + return false; + + context->clean_modules = true; + context->modules = mod_list; + } + else + { + context->clean_modules = false; + context->modules = modules; + } + + if (!native_get_stack_range(context, regs, &context->stack)) + { + if (context->clean_modules) + port_clear_modules(&context->modules); + return false; + } + + return true; +} + +void port_clean_unwind_context(UnwindContext* context) +{ + if (!context) + return; + + if (context->modules && context->clean_modules) + { + port_clear_modules(&context->modules); + } + + context->modules = NULL; +} + +bool port_unwind_frame(UnwindContext* context, Registers* regs) +{ + if (native_is_frame_exists(context, regs)) + { // Stack frame (x86) + return native_unwind_stack_frame(context, regs); + } + else + { // Stack frame does not exist, try using heuristics + return native_unwind_special(context, regs); + } +} diff --git a/vm/port/src/crash_handler/port_crash_handler.cpp b/vm/port/src/crash_handler/port_crash_handler.cpp index 0ab94af..b699310 100644 --- a/vm/port/src/crash_handler/port_crash_handler.cpp +++ b/vm/port/src/crash_handler/port_crash_handler.cpp @@ -16,15 +16,22 @@ */ #include +#include +#include "port_malloc.h" +#include "port_mutex.h" +#include "stack_dump.h" +#include "signals_internal.h" #include "port_crash_handler.h" -static port_signal_handler signal_callbacks[PORT_SIGNAL_MAX] = +static port_signal_handler signal_callbacks[] = { NULL, // PORT_SIGNAL_GPF NULL, // PORT_SIGNAL_STACK_OVERFLOW NULL, // PORT_SIGNAL_ABORT - NULL, // PORT_SIGNAL_TRAP - NULL, // PORT_SIGNAL_PRIV_INSTR + NULL, // PORT_SIGNAL_QUIT + NULL, // PORT_SIGNAL_CTRL_BREAK + NULL, // PORT_SIGNAL_CTRL_C + NULL, // PORT_SIGNAL_BREAKPOINT NULL // PORT_SIGNAL_ARITHMETIC }; @@ -36,32 +43,70 @@ struct crash_additional_actions static crash_additional_actions *crash_actions = NULL; -static unisigned crash_output_flags; +static unsigned crash_output_flags; -Boolean port_init_crash_handler(port_signal_handler_registration *registrations, - unsigned count) +static osmutex_t g_mutex; + +static port_unwind_compiled_frame g_unwind_callback = NULL; + + +Boolean port_init_crash_handler( + port_signal_handler_registration *registrations, + unsigned count, + port_unwind_compiled_frame unwind_callback) { - if (initialize_signals() == FALSE) + if (initialize_signals() != 0) return FALSE; - for (int iii = 0; iii < count; iii++) + if (init_private_tls_data() != 0) + return FALSE; + + port_mutex_create(&g_mutex, APR_THREAD_MUTEX_NESTED); + + sd_init_crash_handler(); + + for (unsigned iii = 0; iii < count; iii++) { - assert(registrations[iii]->signum >= PORT_SIGNAL_MIN); - assert(registrations[iii]->signum <= PORT_SIGNAL_MAX); - signal_callbacks[registrations[iii]->signum] = registrations[iii]->callback; + assert(registrations[iii].signum >= PORT_SIGNAL_MIN); + assert(registrations[iii].signum <= PORT_SIGNAL_MAX); + signal_callbacks[registrations[iii].signum] = registrations[iii].callback; } + g_unwind_callback = unwind_callback; + return TRUE; } -void port_crash_handler_set_flags(port_crash_handler_flags flags) +unsigned port_crash_handler_get_capabilities() +{ + // Return the features we currently support + return (port_crash_handler_flags) + (PORT_CRASH_CALL_DEBUGGER | + PORT_CRASH_DUMP_TO_STDERR | + PORT_CRASH_STACK_DUMP | + PORT_CRASH_DUMP_ALL_THREADS | + PORT_CRASH_PRINT_COMMAND_LINE | + PORT_CRASH_PRINT_ENVIRONMENT | + PORT_CRASH_PRINT_MODULES | + PORT_CRASH_PRINT_REGISTERS | + PORT_CRASH_DUMP_PROCESS_CORE); + +} + +void port_crash_handler_set_flags(unsigned flags) { crash_output_flags = flags; } +unsigned port_crash_handler_get_flags() +{ + return crash_output_flags; +} + Boolean port_crash_handler_add_action(port_crash_handler_action action) { - crash_additional_actions *a = STD_MALLOC(sizeof(crash_additional_actions)); + crash_additional_actions *a = + (crash_additional_actions*)STD_MALLOC(sizeof(crash_additional_actions)); if (NULL == a) return FALSE; @@ -73,9 +118,12 @@ Boolean port_crash_handler_add_action(port_crash_handler_action action) Boolean port_shutdown_crash_handler() { - if (shutdown_signals() == FALSE) + if (shutdown_signals() != 0) return FALSE; + if (free_private_tls_data() != 0) + return FALSE; + for (crash_additional_actions *a = crash_actions; NULL != a;) { crash_additional_actions *next = a->next; @@ -83,5 +131,48 @@ Boolean port_shutdown_crash_handler() a = next; } + sd_cleanup_crash_handler(); + + port_mutex_destroy(&g_mutex); + return TRUE; } + +/* Returns 0 when execution should be continued with (updated) Registers + Returns 1 when crash occured and process should invoke a debugger + Returns -1 when crash occured and process should be terminated */ +int port_process_signal(port_sigtype signum, Registers *regs, void* fault_addr, Boolean iscrash) +{ + if (!iscrash) + { + assert(signum >= PORT_SIGNAL_MIN); + assert(signum <= PORT_SIGNAL_MAX); + + if (signal_callbacks[signum] != NULL) + { + Boolean cres = signal_callbacks[signum](signum, regs, fault_addr); + + if (cres) // signal was processed + return 0; + } + } + + // CRASH + port_mutex_lock(&g_mutex); + + sd_print_crash_info(signum, regs, g_unwind_callback); + + for (crash_additional_actions* action = crash_actions; + action; action = action->next) + { + action->action(signum, regs, fault_addr); + } + + if ((crash_output_flags & PORT_CRASH_CALL_DEBUGGER) != 0) + { + port_mutex_unlock(&g_mutex); + return 1; + } + + return -1; +} diff --git a/vm/port/src/crash_handler/stack_dump.cpp b/vm/port/src/crash_handler/stack_dump.cpp index 948a988..07b900e 100644 --- a/vm/port/src/crash_handler/stack_dump.cpp +++ b/vm/port/src/crash_handler/stack_dump.cpp @@ -14,28 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @author Vladimir Nenashev - * @version $Revision$ - */ #include -#include "vm_threads.h" +#include +#include +// offsetof macro +#if defined(WIN32) +#include +#else +#include +#endif + #include "port_malloc.h" -#include "port_dso.h" -#include "jit_intf_cpp.h" -#include "Class.h" -#include "class_member.h" -#include "exceptions.h" -#include "stack_trace.h" -#include "interpreter_exports.h" -#include "cci.h" -#include "m2n.h" -#include "native_stack.h" -#include "native_modules.h" -#include "natives_support.h" -#include "exception_filter.h" +#include "port_unwind.h" +#include "port_modules.h" +#include "port_crash_handler.h" +#include "port_frame_info.h" #include "stack_dump.h" @@ -52,461 +47,223 @@ static void sd_fill_modules() assert(res && g_modules && count); } -#ifdef SD_UPDATE_MODULES -// Is called to update modules info -void sd_update_modules() -{ - hymutex_t* sd_lock; - bool res = sd_initialize(&sd_lock); - - if (!res) - return; - - hymutex_lock(sd_lock); - - if (g_modules) - port_clear_modules(&g_modules); - - int count; - res = port_get_all_modules(&g_modules, &count); - assert(res && g_modules && count); - - hymutex_unlock(sd_lock); -} -#endif // SD_UPDATE_MODULES - -static char* sd_construct_java_method_name(Method* m, char* buf) +// "%s::%s (%s): %s:%d" - class::name (signature): file:line +static const char* vm_fmt_tbl[] = { +// method_class_name is present + "%s::%s (%s): %s:%d\n", + "%s::%s (%s)\n", // No sourcefile + "%s::%s: %s:%d\n", // No signature + "%s::%s\n", // No signature no sourcefile +// method_class_name is absent + "%s (%s): %s:%d\n", + "%s (%s)\n", // No sourcefile + "%s: %s:%d\n", // No signature + "%s\n", // No signature no sourcefile +}; + +static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi) { - if (!m || !buf) - { - *buf = 0; - return NULL; - } - - char* ptr = buf; + if (!fi->method_name) + return; - const char* err_str = "<--Truncated: too long name"; - size_t err_len = strlen(err_str); + if (count >= 0) + fprintf(file, "%3d: ", count); + else + fprintf(file, " "); // additional VM info - indent - size_t remain = SD_MNAME_LENGTH - 1; - const char* cname = m->get_class()->get_name()->bytes; - size_t clen = m->get_class()->get_name()->len; - const char* mname = m->get_name()->bytes; - size_t mlen = m->get_name()->len; - const char* descr = m->get_descriptor()->bytes; - size_t dlen = m->get_descriptor()->len; + const void* args[5] = {fi->method_class_name, fi->method_name, + fi->method_signature, fi->source_file_name, + (const void*)(size_t)fi->source_line_number}; + const void** pargs = args; + int fmt_num = 0; - if (clen + 1 > remain) + if (!fi->method_class_name) { - size_t len = remain - err_len; - memcpy(ptr, cname, len); - strcpy(ptr + len, err_str); - return buf; + fmt_num += 4; + pargs++; } - - memcpy(ptr, cname, clen); - ptr += clen; - *ptr++ = '.'; - remain -= clen + 1; - - if (mlen > remain) + if (!fi->method_signature) { - if (remain > err_len) - memcpy(ptr, mname, remain - err_len); - - strcpy(ptr + remain - err_len, err_str); - return buf; + fmt_num += 2; + args[2] = args[3]; + args[3] = args[4]; } + if (!fi->source_file_name) + fmt_num += 1; - memcpy(ptr, mname, mlen); - ptr += mlen; - remain -= mlen; - - if (dlen > remain) - { - if (remain > err_len) - memcpy(ptr, descr, remain - err_len); - - strcpy(ptr + remain - err_len, err_str); - return buf; - } - - strcpy(ptr, descr); - return buf; + fprintf(file, vm_fmt_tbl[fmt_num], + pargs[0], pargs[1], pargs[2], pargs[3], pargs[4]); } -static void sd_get_java_method_info(MethodInfo* info, Method* m, void* ip, - bool is_ip_past, int inl_depth) -{ - *info->method_name = 0; - *info->file_name = 0; - info->line = -1; - if (!m || !method_get_class(m)) - return; - - if (!sd_construct_java_method_name(m, info->method_name)) +static void sd_print_c_line(FILE* file, int count, CFunInfo* cfi) +{ + if (!cfi->name) return; - const char* fname = NULL; - get_file_and_line(m, ip, is_ip_past, inl_depth, &fname, &info->line); - - if (fname) - { - if (strlen(fname) >= sizeof(info->file_name)) - { - memcpy(info->file_name, fname, sizeof(info->file_name)); - info->file_name[sizeof(info->file_name) - 1] = 0; - } - else - strcpy(info->file_name, fname); - } + fprintf(file, "%3d: %s (%s:%d)\n", + count, cfi->name, + cfi->filename ? cfi->filename : "??", + cfi->line); } -static void sd_print_line(int count, MethodInfo* m) { - fprintf(stderr, "%3d: %s (%s:%d)\n", - count, - *m->method_name ? m->method_name : "??", - *m->file_name ? m->file_name : "??", - m->line); +static void sd_print_modules() +{ + sd_fill_modules(); // Fill modules table if needed + fprintf(stderr, "\nLoaded modules:\n\n"); + port_dump_modules(g_modules, stderr); } -static void sd_print_stack_jit(VM_thread* thread, - native_frame_t* frames, jint num_frames) +static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind) { - jint frame_num = 0; - jint count = 0; - StackIterator* si = NULL; - - if (thread) - si = si_create_from_native(thread); - - while ((si && !si_is_past_end(si)) || frame_num < num_frames) + if (!regs) { - MethodInfo m; - void* cur_ip = frames[frame_num].ip; - - if (frame_num < num_frames && frames[frame_num].java_depth < 0) - { - if (native_is_ip_stub(cur_ip)) // Generated stub - { - char buf[81]; - char* stub_name = - native_get_stub_name(cur_ip, buf, sizeof(buf)); - - fprintf(stderr, "%3d: 0x%"W_PI_FMT": stub '%s'\n", - count++, (POINTER_SIZE_INT)cur_ip, - stub_name ? stub_name : "??"); - ++frame_num; - continue; - } - - // pure native frame - native_module_t* module = port_find_module(g_modules, cur_ip); - sd_get_c_method_info(&m, module, cur_ip); - sd_print_line(count++, &m); - ++frame_num; - continue; - } + fprintf(stderr, "No stack trace due to registers info absence\n"); + return; + } - // Java/JNI frame, look into stack iterator + UnwindContext uwcontext; + bool hasnative = false; - // If iterator is exhausted - if (si_is_past_end(si) || - (si_is_native(si) && !m2n_get_previous_frame(si_get_m2n(si)))) - break; + if (port_init_unwind_context(&uwcontext, g_modules, regs)) + hasnative = true; - if (si_is_native(si) && frame_num < num_frames) - { - // Print information from native stack trace for JNI frames - native_module_t* module = port_find_module(g_modules, cur_ip); - sd_get_c_method_info(&m, module, cur_ip); - sd_print_line(count, &m); - } - else if (si_is_native(si) && frame_num >= num_frames) - { - // Print information about JNI frames from iterator - // when native stack trace is not available - Method* method = m2n_get_method(si_get_m2n(si)); - void* ip = m2n_get_ip(si_get_m2n(si)); - sd_get_java_method_info(&m, method, ip, false, -1); - sd_print_line(count, &m); - } - else // !si_is_native(si) - { - // Print information about Java method from iterator - CodeChunkInfo* cci = si_get_code_chunk_info(si); - Method* method = cci->get_method(); - void* ip = (void*)si_get_ip(si); - - uint32 inlined_depth = si_get_inline_depth(si); - uint32 offset = (uint32)((POINTER_SIZE_INT)ip - - (POINTER_SIZE_INT)cci->get_code_block_addr()); - bool is_ip_past = (frame_num != 0); - - if (inlined_depth) - { - for (uint32 i = inlined_depth; i > 0; i--) - { - Method* inl_method = cci->get_jit()->get_inlined_method( - cci->get_inline_info(), offset, i); - - sd_get_java_method_info(&m, inl_method, ip, is_ip_past, i); - sd_print_line(count++, &m); - - if (frame_num < num_frames) - ++frame_num; // Go to the next native frame - } - } - - sd_get_java_method_info(&m, method, ip, is_ip_past, -1); - sd_print_line(count, &m); - } + port_stack_frame_info uwinfo; - ++count; - si_goto_previous(si); + int framenum = 0; + int uwresult = -1; + Registers locregs = *regs; + Registers tmpregs = locregs; - if (frame_num < num_frames) - ++frame_num; // Go to the next native frame + // Prepare VM-specific struct for stack iteration + if (unwind) + { + memset(&uwinfo, 0, sizeof(port_stack_frame_info)); + uwresult = unwind(&tmpregs, &uwinfo); } - if (si) - si_free(si); -} - -static void sd_print_stack_interpreter(VM_thread* thread, - native_frame_t* frames, jint num_frames) -{ - FrameHandle* frame = interpreter.interpreter_get_last_frame(thread); - jint frame_num = 0; - jint count = 0; - - while (frame || frame_num < num_frames) + if (uwresult > 0) { - MethodInfo m; - - if (frame_num < num_frames && frames[frame_num].java_depth < 0) - { // pure native frame - native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); - sd_get_c_method_info(&m, module, frames[frame_num].ip); - sd_print_line(count++, &m); - ++frame_num; - continue; - } - - // Java/JNI frame, look into stack iterator - - Method* method = (Method*)interpreter.interpreter_get_frame_method(frame); - uint8* bc_ptr = interpreter.interpreter_get_frame_bytecode_ptr(frame); - - // Print information from native stack trace - // when method is not available or is native - if (frame_num < num_frames && - (!method || method_is_native(method))) - { - native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); - sd_get_c_method_info(&m, module, frames[frame_num].ip); - sd_print_line(count, &m); - } + uwinfo.iteration_state = STD_ALLOCA(uwresult); + uwresult = unwind(&tmpregs, &uwinfo); + assert(uwresult <= 0); + } - // Print information about method from iterator - // when is Java method or when native stack trace is not available - if (method && - (!method_is_native(method) || frame_num >= num_frames)) + while (true) + { + // Unwinding with VM callback + if (unwind && uwresult == 0) { - sd_get_java_method_info(&m, method, (void*)bc_ptr, false, -1); - sd_print_line(count, &m); + sd_print_vm_line(stderr, framenum++, &uwinfo); + locregs = tmpregs; + // Cleanup frame info except 'iteration_state' + memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state)); + // Try unwinding by the callback for next iteration + uwresult = unwind(&tmpregs, &uwinfo); + continue; } - ++count; - frame = interpreter.interpreter_get_prev_frame(frame); + // Print native frame info + CFunInfo cfi = {0}; + native_module_t* module = port_find_module(g_modules, tmpregs.get_ip()); + sd_get_c_method_info(&cfi, module, tmpregs.get_ip()); + sd_print_c_line(stderr, framenum++, &cfi); - if (frame_num < num_frames) - ++frame_num; // Go to the next native frame - } -} - -const char* sd_get_module_type(const char* short_name) -{ - char name[256]; - - if (strlen(short_name) > 255) - return "Too long short name"; - - strcpy(name, short_name); - char* dot = strchr(name, '.'); + if (!hasnative) // Native unwinding is not initialized + break; - // Strip suffix/extension - if (dot) - *dot = 0; + // Try native unwinding + bool nativeres = port_unwind_frame(&uwcontext, &tmpregs); - // Strip prefix - char* nameptr = name; + if (nativeres) + locregs = tmpregs; - if (!memcmp(short_name, PORT_DSO_PREFIX, strlen(PORT_DSO_PREFIX))) - nameptr += strlen(PORT_DSO_PREFIX); + if (unwind && uwresult < 0 && uwinfo.method_name) + { // VM has not unwound but has provided additional frame info + sd_print_vm_line(stderr, -1, &uwinfo); // Print as additional info + } - char* vm_modules[] = {"java", "em", "encoder", "gc_gen", "gc_gen_uncomp", "gc_cc", - "harmonyvm", "hythr", "interpreter", "jitrino", "vmi"}; + if (!nativeres) + break; // Neither VM calback nor native unwinding can unwind the frame - for (size_t i = 0; i < sizeof(vm_modules)/sizeof(vm_modules[0]); i++) - { - if (!strcmp_case(name, vm_modules[i])) - return "VM native code"; + // Cleanup frame info except 'iteration_state' + memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state)); + // Try unwinding by the callback for next iteration + uwresult = unwind(&tmpregs, &uwinfo); } - if (natives_is_library_loaded_slow(short_name)) - return "JNI native library"; + if (hasnative) + port_clean_unwind_context(&uwcontext); - return "Unknown/system native module"; + fflush(stderr); } -static void sd_print_module_info(Registers* regs) +struct sig_name_t { -#ifdef SD_UPDATE_MODULES - sd_fill_modules(); // Fill modules table if needed -#endif - - native_module_t* module = port_find_module(g_modules, (void*)regs->get_ip()); - sd_parse_module_info(module, (void*)regs->get_ip()); -} + int num; + char* name; +}; -static void sd_print_modules() +static sig_name_t sig_names[] = { - fprintf(stderr, "\nLoaded modules:\n\n"); - port_dump_modules(g_modules, stderr); -} - - -static void sd_print_threads_info(VM_thread* cur_thread) + {PORT_SIGNAL_GPF, "GENERAL_PROTECTION_FAULT"}, + {PORT_SIGNAL_STACK_OVERFLOW, "STACK_OVERFLOW"}, + {PORT_SIGNAL_ABORT, "ABORT" }, + {PORT_SIGNAL_QUIT, "QUIT"}, + {PORT_SIGNAL_CTRL_C, "CTRL_C" }, + {PORT_SIGNAL_CTRL_BREAK, "CTRL_BREAK" }, + {PORT_SIGNAL_BREAKPOINT, "BREAKPOINT"}, + {PORT_SIGNAL_ARITHMETIC, "ARITHMETIC_EXCEPTION" }, + {PORT_SIGNAL_UNKNOWN, "UNKNOWN"} +}; + +static const char* get_sig_name(int signum) { - if (!cur_thread) - fprintf(stderr, "\nCurrent thread is not attached to VM, ID: %d\n", sd_get_cur_tid()); - - fprintf(stderr, "\nVM attached threads:\n\n"); - - hythread_iterator_t it = hythread_iterator_create(NULL); - int count = (int)hythread_iterator_size (it); - - for (int i = 0; i < count; i++) + for (int i = 0; i < sizeof(sig_names)/sizeof(sig_names[0]); i++) { - hythread_t thread = hythread_iterator_next(&it); - VM_thread* vm_thread = jthread_get_vm_thread(thread); - - if (!vm_thread) - continue; - - jthread java_thread = jthread_get_java_thread(thread); - JNIEnv* jni_env = vm_thread->jni_env; - - if (cur_thread && java_thread) - { - jclass cl = GetObjectClass(jni_env, java_thread); - jmethodID id = jni_env->GetMethodID(cl, "getName","()Ljava/lang/String;"); - jstring name = jni_env->CallObjectMethod(java_thread, id); - char* java_name = (char*)jni_env->GetStringUTFChars(name, NULL); - - fprintf(stderr, "%s[%p] '%s'\n", - (cur_thread && vm_thread == cur_thread) ? "--->" : " ", - thread->os_handle, java_name); - - jni_env->ReleaseStringUTFChars(name, java_name); - } - else - { - fprintf(stderr, "%s[%p]\n", - (cur_thread && vm_thread == cur_thread) ? "--->" : " ", - thread->os_handle); - } + if (signum == sig_names[i].num) + return sig_names[i].name; } - hythread_iterator_release(&it); + return "unknown signal"; } - -void sd_print_stack(Registers* regs) +static void print_name_and_context(int signum, Registers* regs) { - hymutex_t* sd_lock; - int disable_count; - bool unwindable; - - VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread - - // Enable suspend to allow working with threads - if (thread) - disable_count = hythread_reset_suspend_disable(); - - // Acquire global lock to print threads list and stop other crashed threads - hythread_global_lock(); - - if (!sd_initialize(&sd_lock)) - return; + // Print signal name + fprintf(stderr, "\nSignal reported: %s\n", get_sig_name(signum)); + + // Print register state + if (regs) + print_reg_state(regs); + else + fprintf(stderr, "\nRegisters info is absent\n"); +} - hymutex_lock(sd_lock); - if (thread) - unwindable = set_unwindable(false); // To call Java code - // Print register info - print_reg_state(regs); +void sd_print_crash_info(int signum, Registers* regs, port_unwind_compiled_frame unwind) +{ + // Print signal name and register info + if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_REGISTERS) + print_name_and_context(signum, regs); - // Print crashed modile info - sd_print_module_info(regs); + // Print command line and working directory + if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_COMMAND_LINE) + sd_print_cmdline_cwd(); // Print program environment info - sd_print_cwdcmdenv(); + if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_ENVIRONMENT) + sd_print_environment(); // Print the whole list of modules - sd_print_modules(); - - native_frame_t* frames = NULL; - - // Print threads info - sd_print_threads_info(thread); - - // We are trying to get native stack trace using walk_native_stack_registers - // function and get corresponding Java methods for stack trace from - // JIT/interpreter stack iterator. - // When native stack trace is not complete (for example, when - // walk_native_stack_registers cannot unwind frames in release build), - // we will use JIT/interpreter stack iterator to complete stack trace. - - WalkContext context; - - if (native_init_walk_context(&context, g_modules, regs)) - { - jint num_frames = - walk_native_stack_registers(&context, regs, thread, -1, NULL); - - if (num_frames) - frames = (native_frame_t*)STD_ALLOCA(sizeof(native_frame_t)*num_frames); - - if (num_frames && frames) - walk_native_stack_registers(&context, regs, thread, num_frames, frames); - else - num_frames = 0; // Consider native stack trace empty - - fprintf(stderr, "\nStack trace:\n"); - - if (interpreter_enabled() && thread) - sd_print_stack_interpreter(thread, frames, num_frames); - else // It should be used also for threads without VM_thread structure - sd_print_stack_jit(thread, frames, num_frames); - - fprintf(stderr, "\n"); - fflush(stderr); - } - - if (thread) - set_unwindable(unwindable); - - // Do not unlock to prevent other threads from printing crash stack - //hymutex_unlock(sd_lock); + if (port_crash_handler_get_flags() & PORT_CRASH_PRINT_MODULES) + sd_print_modules(); - hythread_global_unlock(); - if (thread) - hythread_set_suspend_disable(disable_count); + // Print stack of crashed module + if (port_crash_handler_get_flags() & PORT_CRASH_STACK_DUMP) + sd_print_stack(regs, unwind); } diff --git a/vm/port/src/crash_handler/win/native_unwind_os.cpp b/vm/port/src/crash_handler/win/native_unwind_os.cpp index 3c32489..9f67729 100644 --- a/vm/port/src/crash_handler/win/native_unwind_os.cpp +++ b/vm/port/src/crash_handler/win/native_unwind_os.cpp @@ -16,11 +16,12 @@ */ -#include "native_modules.h" -#include "native_stack.h" +#include "open/hythread_ext.h" // for correct Windows.h inclusion +#include "port_modules.h" +#include "native_unwind.h" -bool native_is_in_code(WalkContext* context, void* ip) +bool native_is_in_code(UnwindContext* context, void* ip) { if (!ip) return false; @@ -37,7 +38,7 @@ bool native_is_in_code(WalkContext* context, void* ip) PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0); } -bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) +bool native_get_stack_range(UnwindContext* context, Registers* regs, native_segment_t* seg) { MEMORY_BASIC_INFORMATION mem_info; diff --git a/vm/port/src/crash_handler/win/stack_dump_os.cpp b/vm/port/src/crash_handler/win/stack_dump_os.cpp index 4005c1d..3bbc6d7 100644 --- a/vm/port/src/crash_handler/win/stack_dump_os.cpp +++ b/vm/port/src/crash_handler/win/stack_dump_os.cpp @@ -15,10 +15,10 @@ * limitations under the License. */ -#include "open/hythread_ext.h" -#include "native_stack.h" +#include +#include "open/hythread_ext.h" // for correct Windows.h inclusion +#include "port_malloc.h" #include "stack_dump.h" -#include "port_filepath.h" #ifndef NO_DBGHELP #include @@ -26,10 +26,9 @@ #endif -static hymutex_t g_lock; -static const char* g_curdir = NULL; -static const char* g_cmdline = NULL; -static const char* g_environ = NULL; +static char* g_curdir = NULL; +static char* g_cmdline = NULL; +static char* g_environ = NULL; #ifndef NO_DBGHELP typedef BOOL (WINAPI *SymFromAddr_type) @@ -55,105 +54,10 @@ static SymGetLineFromAddr_type g_SymGetLineFromAddr = NULL; #endif // #ifndef NO_DBGHELP -bool sd_initialize(hymutex_t** p_lock) +void sd_get_c_method_info(CFunInfo* info, native_module_t* module, void* ip) { - static int initialized = 0; - - if (!initialized) - { - IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); - - if (err != APR_SUCCESS) - return false; - -#ifndef NO_DBGHELP -// Preventive initialization does not work -// if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) -// return false; - - HMODULE hdbghelp = ::LoadLibrary("dbghelp"); - - if (hdbghelp) - { - SymSetOptions(SYMOPT_LOAD_LINES); - g_SymFromAddr = (SymFromAddr_type)::GetProcAddress(hdbghelp, "SymFromAddr"); - g_SymGetLineFromAddr64 = (SymGetLineFromAddr64_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr64"); - g_SymGetLineFromAddr = (SymGetLineFromAddr_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr"); - } -#endif // #ifndef NO_DBGHELP - - initialized = true; - } - - if (p_lock) - *p_lock = &g_lock; - - return true; -} - - -static const char* sd_get_region_access_info(MEMORY_BASIC_INFORMATION* pinfo) -{ - if ((pinfo->State & MEM_COMMIT) == 0) - return "not committed"; - - if ((pinfo->Protect & PAGE_GUARD) != 0) - return "guard page occured"; - - if ((pinfo->Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | - PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | - PAGE_READWRITE | PAGE_READONLY)) != 0) - return ""; - - if ((pinfo->Protect & (PAGE_READWRITE | PAGE_READONLY)) != 0) - return "without execution rights"; - - return "without read rights";; -} - -void sd_parse_module_info(native_module_t* module, void* ip) -{ - fprintf(stderr, "\nCrashed module:\n"); - - if (module) - { - native_segment_t* segment = module->segments; - - assert(module->filename); - - if (!module->filename) - { // We should not reach this code - fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - // Common shared module - const char* short_name = port_filepath_basename(module->filename); - const char* module_type = sd_get_module_type(short_name); - fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); - return; - } - - // module == NULL - size_t start_addr, end_addr, region_size; - MEMORY_BASIC_INFORMATION mem_info; - - VirtualQuery(ip, &mem_info, sizeof(mem_info)); - start_addr = (size_t)mem_info.BaseAddress; - region_size = (size_t)mem_info.RegionSize; - end_addr = start_addr + region_size; - - fprintf(stderr, "Memory region 0x%"W_PI_FMT":0x%"W_PI_FMT" %s\n", - start_addr, end_addr, sd_get_region_access_info(&mem_info)); -} - - -void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* ip) -{ - *info->method_name = 0; - *info->file_name = 0; + *info->name = 0; + *info->filename = 0; info->line = -1; #ifndef NO_DBGHELP @@ -170,7 +74,7 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* if (g_SymFromAddr && g_SymFromAddr(GetCurrentProcess(), (DWORD64)(POINTER_SIZE_INT)ip, &funcDispl, pSymb)) { - strcpy(info->method_name, pSymb->Name); + strcpy(info->name, pSymb->Name); } if (g_SymGetLineFromAddr64) @@ -184,7 +88,7 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* &offset, &lineinfo)) { info->line = lineinfo.LineNumber; - strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); + strncpy(info->filename, lineinfo.FileName, sizeof(info->filename)); return; } } @@ -200,20 +104,31 @@ void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* &offset, &lineinfo)) { info->line = lineinfo.LineNumber; - strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); + strncpy(info->filename, lineinfo.FileName, sizeof(info->filename)); } } #endif // #ifndef NO_DBGHELP } -int sd_get_cur_tid() -{ - return GetCurrentThreadId(); -} - void sd_init_crash_handler() { +#ifndef NO_DBGHELP +// Preventive initialization does not work +// if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) +// return false; + + HMODULE hdbghelp = ::LoadLibrary("dbghelp"); + + if (hdbghelp) + { + SymSetOptions(SYMOPT_LOAD_LINES); + g_SymFromAddr = (SymFromAddr_type)::GetProcAddress(hdbghelp, "SymFromAddr"); + g_SymGetLineFromAddr64 = (SymGetLineFromAddr64_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr64"); + g_SymGetLineFromAddr = (SymGetLineFromAddr_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr"); + } +#endif // #ifndef NO_DBGHELP + // Get current directory DWORD required = GetCurrentDirectory(0, NULL); char* ptr = (char*)STD_MALLOC(required); @@ -256,11 +171,21 @@ void sd_init_crash_handler() FreeEnvironmentStrings((char*)env_block); } -void sd_print_cwdcmdenv() +void sd_cleanup_crash_handler() +{ + STD_FREE(g_curdir); + STD_FREE(g_cmdline); + STD_FREE(g_environ); +} + +void sd_print_cmdline_cwd() { - fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); fprintf(stderr, "\nCommand line:\n%s\n", g_cmdline); + fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); +} +void sd_print_environment() +{ fprintf(stderr, "\nEnvironment variables:\n"); const char* penv = (char*)g_environ; diff --git a/vm/port/src/memaccess/linux/memaccess.cpp b/vm/port/src/memaccess/linux/memaccess.cpp index ec98839..4f08fc1 100644 --- a/vm/port/src/memaccess/linux/memaccess.cpp +++ b/vm/port/src/memaccess/linux/memaccess.cpp @@ -1,3 +1,19 @@ +/* + * 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 * @version $Revision$ @@ -5,283 +21,98 @@ #include #include +#include "port_general.h" #include "port_vmem.h" -#ifdef _IA32_ -#include "encoder.h" -#include "jit_intf_cpp.h" -#endif // #ifdef _IA32_ -#include "nogc.h" -#include "dump.h" -#include "ncai_direct.h" -#include "ncai_internal.h" - - -typedef void* (__cdecl *get_return_address_stub_type)(); - - -#ifdef _IA32_ - -static get_return_address_stub_type gen_get_return_address_stub() -{ - static get_return_address_stub_type addr = NULL; - - if (addr) - return addr; +#include "port_barriers.h" - const int stub_size = 0x04; - char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); -#ifdef _DEBUG - memset(stub, 0xcc /*int 3*/, stub_size); -#endif - char *ss = stub; +#include "signals_internal.h" +#include "port_memaccess.h" - M_Base_Opnd m1(esp_reg, 0); - ss = mov(ss, eax_opnd, m1); - ss = ret(ss); - addr = (get_return_address_stub_type)stub; - assert(ss - stub <= stub_size); +extern "C" void port_memcpy_asm(void* dst, const void* src, size_t size, + void** prestart_addr, void* memcpyaddr); - /* - The following code will be generated: - mov eax,dword ptr [esp] - ret - */ - - DUMP_STUB(stub, "get_return_address", ss - stub); - - return addr; -} -#endif // #ifdef _IA32_ - - -ncaiError ncai_read_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) +static int memcpy_internal(void* dst, const void* src, size_t size, int from) { -#ifndef _IA32_ - // SIGSEGV processing is not implemented for EM64T/IPF - memcpy(buf, addr, size); - return NCAI_ERROR_NONE; -#else // #ifndef _IA32_ - -static void* read_memory_1st_label = NULL; -static void* read_memory_2nd_label = NULL; + port_tls_data tlsdata; - char dummy_str[3]; - - if (calc_pass) + if (!get_private_tls_data()) { - addr = dummy_str; - buf = dummy_str; - *dummy_str = 'a'; // To avoid warnings - size = 1; + if (set_private_tls_data(&tlsdata) != 0) + return -1; } - jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; - - unsigned char* src_ptr = (unsigned char*)addr; - unsigned char* dest_ptr = (unsigned char*)buf; + tlsdata.violation_flag = 1; - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = read_memory_1st_label; + void* memcpyaddr = (void*)&memcpy; + port_memcpy_asm(dst, src, size, &tlsdata.restart_address, memcpyaddr); - size_t i; - for (i = 0; i < size; i++) + if (tlsdata.violation_flag == 1) { - *dest_ptr = *src_ptr; - - void* label = (gen_get_return_address_stub())(); - read_memory_1st_label = label; - - if (jvmti_thread->violation_flag == 0) - break; - - ++src_ptr; - ++dest_ptr; + pthread_setspecific(port_tls_key, NULL); + return 0; } - if (jvmti_thread->violation_flag == 0 || calc_pass) - { - if (!calc_pass) - { - size_t* page_sizes = port_vmem_page_sizes(); - size_t page_size = page_sizes[0]; - - POINTER_SIZE_INT start = - ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); - POINTER_SIZE_INT pastend = - ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); + // Try changing memory access + size_t* page_sizes = port_vmem_page_sizes(); + size_t page_size = page_sizes[0]; - int result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); + const void* addr = from ? src : dst; - if (result == EAGAIN) - { - timespec delay = {0, 10}; - nanosleep(&delay, NULL); - result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - } + POINTER_SIZE_INT start = + (POINTER_SIZE_INT)addr & ~(page_size - 1); + POINTER_SIZE_INT pastend = + ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); - if (result != 0) - return NCAI_ERROR_ACCESS_DENIED; - } + int result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); - if (calc_pass) - ++size; + if (result == EAGAIN) + { + timespec delay = {0, 10}; + nanosleep(&delay, NULL); + result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + } - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = read_memory_2nd_label; + if (result != 0) + return -1; - for (; i < size; i++) - { - *dest_ptr++ = *src_ptr++; + tlsdata.violation_flag = 1; - void* label = (gen_get_return_address_stub())(); - read_memory_2nd_label = label; + port_memcpy_asm(dst, src, size, &tlsdata.restart_address, memcpyaddr); - if (jvmti_thread->violation_flag == 0) - return NCAI_ERROR_ACCESS_DENIED; - } - } - - jvmti_thread->violation_flag = 0; - return NCAI_ERROR_NONE; -#endif // #ifndef _IA32_ + pthread_setspecific(port_tls_key, NULL); + return (tlsdata.violation_flag == 1) ? 0 : -1; } -ncaiError ncai_read_memory(void* addr, size_t size, void* buf) +int port_read_memory(void* addr, size_t size, void* buf) { if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; + return -1; if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; - - if (p_TLS_vmthread == NULL) - return NCAI_ERROR_INTERNAL; + return 0; - if (ncai_read_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) - return NCAI_ERROR_INTERNAL; - - return ncai_read_memory_internal(addr, size, buf, false); + return memcpy_internal(buf, addr, size, 1); } - -static ncaiError ncai_write_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) -{ -#ifndef _IA32_ - // SIGSEGV processing is not implemented for EM64T/IPF - memcpy(addr, buf, size); - return NCAI_ERROR_NONE; -#else // #ifndef _IA32_ - -static void* write_memory_1st_label = NULL; -static void* write_memory_2nd_label = NULL; - - char dummy_str[3]; - - if (calc_pass) - { - addr = dummy_str; - buf = dummy_str; - *dummy_str = 'a'; // To avoid warnings - size = 1; - } - - jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; - - unsigned char* src_ptr = (unsigned char*)buf; - unsigned char* dest_ptr = (unsigned char*)addr; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = write_memory_1st_label; - - size_t i; - for (i = 0; i < size; i++) - { - *dest_ptr = *src_ptr; - - void* label = (gen_get_return_address_stub())(); - write_memory_1st_label = label; - - if (jvmti_thread->violation_flag == 0) - break; - - ++src_ptr; - ++dest_ptr; - } - - if (jvmti_thread->violation_flag == 0 || calc_pass) - { - if (!calc_pass) - { - size_t* page_sizes = port_vmem_page_sizes(); - size_t page_size = page_sizes[0]; - - POINTER_SIZE_INT start = - ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); - POINTER_SIZE_INT pastend = - ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); - - int result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - - if (result == EAGAIN) - { - timespec delay = {0, 10}; - nanosleep(&delay, NULL); - result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - - if (result != 0) - return NCAI_ERROR_ACCESS_DENIED; - } - - if (calc_pass) - ++size; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = write_memory_2nd_label; - - for (; i < size; i++) - { - *dest_ptr++ = *src_ptr++; - - void* label = (gen_get_return_address_stub())(); - write_memory_2nd_label = label; - - if (jvmti_thread->violation_flag == 0) - return NCAI_ERROR_ACCESS_DENIED; - } - } - -#ifdef _IPF_ - asm volatile ("mf" ::: "memory"); -#else - __asm__("mfence"); -#endif - - jvmti_thread->violation_flag = 0; - return NCAI_ERROR_NONE; -#endif // #ifndef _IA32_ -} - -ncaiError ncai_write_memory(void* addr, size_t size, void* buf) +int port_write_memory(void* addr, size_t size, void* buf) { if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; + return -1; if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; + return 0; - if (p_TLS_vmthread == NULL) - return NCAI_ERROR_INTERNAL; + int result = memcpy_internal(addr, buf, size, 0); - if (ncai_write_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) - return NCAI_ERROR_INTERNAL; + if (result == 0) + { + port_rw_barrier(); + } - return ncai_write_memory_internal(addr, size, buf, false); + return result; } diff --git a/vm/port/src/memaccess/linux/memaccess_em64t.s b/vm/port/src/memaccess/linux/memaccess_em64t.s new file mode 100644 index 0000000..4b4a154 --- /dev/null +++ b/vm/port/src/memaccess/linux/memaccess_em64t.s @@ -0,0 +1,42 @@ +// +// 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. +// + .text + .align 16 + +// port_memcpy_asm(void* dst, const void* src, size_t size, +// void** prestart_addr, void* memcpyaddr); +// 1st arg (RDI) - dest +// 2nd arg (RSI) - src +// 3rd arg (RDX) - len +// 4th arg (RCX) - address of restart_address storage +// 5th arg (R8) - address of memcpy - to avoid PIC problems in GNU asm + +.globl port_memcpy_asm + .type port_memcpy_asm, @function +port_memcpy_asm: + pushq %rbx + callq precall +precall: + popq %rax + addq $(preret - precall), %rax + movq %rax, (%rcx) + + callq *%r8 + +preret: + popq %rbx + ret diff --git a/vm/port/src/memaccess/linux/memaccess_ia32.s b/vm/port/src/memaccess/linux/memaccess_ia32.s new file mode 100644 index 0000000..d32a6c2 --- /dev/null +++ b/vm/port/src/memaccess/linux/memaccess_ia32.s @@ -0,0 +1,49 @@ +// +// 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. +// + .text + .align 4 + +// port_memcpy_asm(void* dst, const void* src, size_t size, +// void** prestart_addr, void* memcpyaddr); +// 1st arg (EBP + 8) - dest +// 2nd arg (EBP + 12) - src +// 3rd arg (EBP + 16) - len +// 4th arg (EBP + 20) - address of restart_address storage +// 5th arg (EBP + 24) - address of memcpy - not used on x86 + +.globl port_memcpy_asm + .type port_memcpy_asm, @function +port_memcpy_asm: + pushl %ebp + movl %esp, %ebp + subl $20, %esp + + movl 20(%ebp), %eax + movl $preret, (%eax) + + movl 8(%ebp), %eax + movl %eax, (%esp) + movl 12(%ebp), %eax + movl %eax, 4(%esp) + movl 16(%ebp), %eax + movl %eax, 8(%esp) + call memcpy + +preret: + addl $20, %esp + popl %ebp + ret diff --git a/vm/port/src/memaccess/linux/memaccess_ipf.cpp b/vm/port/src/memaccess/linux/memaccess_ipf.cpp new file mode 100644 index 0000000..161e417 --- /dev/null +++ b/vm/port/src/memaccess/linux/memaccess_ipf.cpp @@ -0,0 +1,51 @@ +/* + * 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 + * @version $Revision$ + */ + +#include +#include "port_memaccess.h" + + +int port_read_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return -1; + + if (size == 0) + return 0; + + memcpy(buf, addr, size); + + return 0; +} + +int port_write_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return -1; + + if (size == 0) + return 0; + + memcpy(addr, buf, size); + asm volatile ("mf" ::: "memory"); + + return 0; +} diff --git a/vm/port/src/memaccess/win/memaccess.cpp b/vm/port/src/memaccess/win/memaccess.cpp index 1c72ef6..2c48e19 100644 --- a/vm/port/src/memaccess/win/memaccess.cpp +++ b/vm/port/src/memaccess/win/memaccess.cpp @@ -1,49 +1,63 @@ +/* + * 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 * @version $Revision$ */ -#include "ncai_direct.h" -#include "ncai_internal.h" +#include +#include "port_memaccess.h" -ncaiError ncai_read_memory(void* addr, size_t size, void* buf) +int port_read_memory(void* addr, size_t size, void* buf) { if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; + return -1; if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; + return 0; SIZE_T bytes_read; BOOL result = ReadProcessMemory(GetCurrentProcess(), addr, buf, size, &bytes_read); - assert(bytes_read == size); - if (!result) - return NCAI_ERROR_ACCESS_DENIED; + if (!result || bytes_read != size) + return -1; - return NCAI_ERROR_NONE; + return 0; } -ncaiError ncai_write_memory(void* addr, size_t size, void* buf) +int port_write_memory(void* addr, size_t size, void* buf) { if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; + return -1; if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; + return 0; SIZE_T bytes_written; BOOL result = WriteProcessMemory(GetCurrentProcess(), addr, buf, size, &bytes_written); - assert(bytes_written == size); - if (!result) - return NCAI_ERROR_ACCESS_DENIED; + if (!result || bytes_written != size) + return -1; FlushInstructionCache(GetCurrentProcess(), addr, size); - return NCAI_ERROR_NONE; + return 0; } diff --git a/vm/port/src/modules/linux/native_modules_os.c b/vm/port/src/modules/linux/native_modules_os.c index 391ccd5..8ba15d3 100644 --- a/vm/port/src/modules/linux/native_modules_os.c +++ b/vm/port/src/modules/linux/native_modules_os.c @@ -26,7 +26,7 @@ #include #include "open/types.h" #include "port_malloc.h" -#include "native_modules.h" +#include "port_modules.h" typedef struct _raw_module raw_module; diff --git a/vm/port/src/modules/native_modules.c b/vm/port/src/modules/native_modules.c index ac2c6ca..161c233 100644 --- a/vm/port/src/modules/native_modules.c +++ b/vm/port/src/modules/native_modules.c @@ -18,7 +18,7 @@ #include #include "open/types.h" #include "port_malloc.h" -#include "native_modules.h" +#include "port_modules.h" native_module_t* port_find_module(native_module_t* modules, void* code_ptr) diff --git a/vm/port/src/modules/win/native_modules_os.c b/vm/port/src/modules/win/native_modules_os.c index 19fe9ce..44299f4 100644 --- a/vm/port/src/modules/win/native_modules_os.c +++ b/vm/port/src/modules/win/native_modules_os.c @@ -23,7 +23,7 @@ #include #include #include "port_malloc.h" -#include "native_modules.h" +#include "port_modules.h" static native_module_t* fill_module(MODULEENTRY32 src); diff --git a/vm/port/src/signals/include/signals_internal.h b/vm/port/src/signals/include/signals_internal.h new file mode 100644 index 0000000..c7c39c0 --- /dev/null +++ b/vm/port/src/signals/include/signals_internal.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef _SIGNALS_INTERNAL_H_ +#define _SIGNALS_INTERNAL_H_ + +#include "port_general.h" +#include "port_thread.h" +#include "open/platform_types.h" +#include "open/hythread_ext.h" /* For windows.h */ + + +/* Thread-specific structure */ +typedef struct +{ + /* Previous crash handling stage to restart crash processing */ + int crash_stage; + +#ifndef WIN32 /* UNIX */ + /* Flag and restart address for memory access violation detection */ + int violation_flag; + void* restart_address; +#endif /* UNIX */ + + /* Flag to produce minidump/core on the second exception catch */ + Boolean produce_core; + +} port_tls_data; + + +#ifdef WIN32 +typedef DWORD port_tls_key_t; +#else +typedef pthread_key_t port_tls_key_t; +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern port_tls_key_t port_tls_key; + +int init_private_tls_data(); +int free_private_tls_data(); + +PORT_INLINE port_tls_data* get_private_tls_data() +{ +#ifdef WIN32 + return (port_tls_data*)TlsGetValue(port_tls_key); +#else + return (port_tls_data*)pthread_getspecific(port_tls_key); +#endif +} + +PORT_INLINE int set_private_tls_data(port_tls_data* data) +{ +#ifdef WIN32 + return TlsSetValue(port_tls_key, data) ? 0 : -1; +#else + return pthread_setspecific(port_tls_key, data); +#endif +} + + +#define INSTRUMENTATION_BYTE_HLT 0xf4 // HLT instruction +#define INSTRUMENTATION_BYTE_CLI 0xfa // CLI instruction +#define INSTRUMENTATION_BYTE_INT3 0xcc // INT 3 instruction + +#ifdef WINNT +#define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_CLI +#else +#define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_INT3 +#endif + + +#ifdef WIN32 + +/** + * Assembler wrapper for clearing CLD flag - bug in VEHs + * appeared in debug prolog. + */ +LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception); + +/* Internal exception handler */ +LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception); + +#else /* UNIX */ + +// + +#endif /* WIN32 */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _SIGNALS_INTERNAL_H_ */ diff --git a/vm/port/src/signals/linux/signals_common.cpp b/vm/port/src/signals/linux/signals_common.cpp new file mode 100644 index 0000000..95b71fe --- /dev/null +++ b/vm/port/src/signals/linux/signals_common.cpp @@ -0,0 +1,179 @@ +/* + * 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. + */ + +#include +#undef __USE_XOPEN +#include + +#include "open/platform_types.h" +#include "port_crash_handler.h" +#include "stack_dump.h" +#include "../linux/include/gdb_crash_handler.h" +#include "signals_internal.h" + + +port_tls_key_t port_tls_key; + +int init_private_tls_data() +{ + return (pthread_key_create(&port_tls_key, NULL) == 0) ? 0 : -1; +} + +int free_private_tls_data() +{ + return (pthread_key_delete(port_tls_key) == 0) ? 0 : -1; +} + + +static void c_handler(Registers* pregs, size_t signum, void* fault_addr) +{ // this exception handler is executed *after* VEH handler returned + int result; + Registers regs = *pregs; + + // Check if SIGSEGV is produced by port_read/write_memory + port_tls_data* tlsdata = get_private_tls_data(); + if (tlsdata && tlsdata->violation_flag) + { + tlsdata->violation_flag = 0; + pregs->set_ip(tlsdata->restart_address); + return; + } + + switch ((int)signum) + { + case SIGSEGV: + result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE); + break; + case SIGFPE: + result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE); + break; + case SIGTRAP: + // Correct return address + pregs->set_ip((void*)((POINTER_SIZE_INT)pregs->get_ip() - 1)); + result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, FALSE); + break; + case SIGINT: + result = port_process_signal(PORT_SIGNAL_CTRL_C, pregs, fault_addr, FALSE); + break; + case SIGQUIT: + result = port_process_signal(PORT_SIGNAL_QUIT, pregs, fault_addr, FALSE); + break; + default: + result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE); + } + + if (result == 0) + return; + + // We've got a crash + if (result > 0) + { // result > 0 - invoke debugger + bool result = gdb_crash_handler(®s); + // Continue with exiting process if not sucessful... + } + + // result < 0 - exit process + if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + { // Return to the same place to produce the same crash and generate core + signal(signum, SIG_DFL); // setup default handler + return; + } + // No core needed - simply terminate + _exit(-1); +} + +static void general_signal_handler(int signum, siginfo_t* info, void* context) +{ + Registers regs; + // Convert OS context to Registers + port_thread_context_to_regs(®s, (ucontext_t*)context); + // Prepare registers for transfering control out of signal handler + void* callback = (void*)&c_handler; + port_set_longjump_regs(callback, ®s, 3, + ®s, (void*)(size_t)signum, info->si_addr); + // Convert prepared Registers back to OS context + port_thread_regs_to_context((ucontext_t*)context, ®s); + // Return from signal handler to go to C handler +} + + +struct sig_reg +{ + int signal; + int flags; + bool set_up; +}; + +static sig_reg signals_used[] = +{ + { SIGTRAP, SA_SIGINFO, false }, + { SIGSEGV, SA_SIGINFO | SA_ONSTACK, false }, + { SIGFPE, SA_SIGINFO, false }, + { SIGINT, SA_SIGINFO, false }, + { SIGQUIT, SA_SIGINFO, false }, + { SIGABRT, SA_SIGINFO, false } +}; + +static struct sigaction old_actions[sizeof(signals_used)/sizeof(signals_used[0])]; + + +static void restore_signals() +{ + for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++) + { + if (!signals_used[i].set_up) + continue; + + signals_used[i].set_up = false; + sigaction(signals_used[i].signal, &old_actions[i], NULL); + } +} + +int initialize_signals() +{ + struct sigaction sa; + + for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++) + { + sigemptyset(&sa.sa_mask); + sa.sa_flags = signals_used[i].flags; + sa.sa_sigaction = &general_signal_handler; + + if (0 != sigaction(signals_used[i].signal, &sa, &old_actions[i])) + { + restore_signals(); + return -1; + } + } + + // Prepare gdb crash handler + if (!init_gdb_crash_handler()) + { + restore_signals(); + return -1; + } + + return 0; + +} //initialize_signals + +int shutdown_signals() +{ + cleanup_gdb_crash_handler(); + restore_signals(); + return 0; +} //shutdown_signals diff --git a/vm/port/src/signals/linux/signals_ipf.cpp b/vm/port/src/signals/linux/signals_ipf.cpp new file mode 100644 index 0000000..5a6e29c --- /dev/null +++ b/vm/port/src/signals/linux/signals_ipf.cpp @@ -0,0 +1,283 @@ +/* + * 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. + */ + +#include +#undef __USE_XOPEN +#include + +#include "open/platform_types.h" +#include "port_crash_handler.h" +#include "stack_dump.h" +#include "../linux/include/gdb_crash_handler.h" +#include "signals_internal.h" + + +port_tls_key_t port_tls_key; + +int init_private_tls_data() +{ + return (pthread_key_create(&port_tls_key, NULL) == 0) ? 0 : -1; +} + +int free_private_tls_data() +{ + return (pthread_key_delete(port_tls_key) == 0) ? 0 : -1; +} + + +/* Out-of-signal-handler signal processing is not implemented for IPF + +static void c_handler(Registers* pregs, size_t signum, void* fault_addr) +{ // this exception handler is executed *after* VEH handler returned +} +*/ + +static void general_signal_handler(int signum, siginfo_t* info, void* context) +{ + Registers regs; +/* Not implemented + // Check if SIGSEGV is produced by port_read/write_memory + port_tls_data* tlsdata = get_private_tls_data(); + if (tlsdata && tlsdata->violation_flag) + { + tlsdata->violation_flag = 0; + pregs->set_ip(tlsdata->restart_address); + return; + } +*/ + // Convert OS context to Registers + port_thread_context_to_regs(®s, (ucontext_t*)context); + + void* fault_addr = info->si_addr; + int result; + + switch ((int)signum) + { + case SIGSEGV: + result = port_process_signal(PORT_SIGNAL_GPF, ®s, fault_addr, FALSE); + break; + case SIGFPE: + result = port_process_signal(PORT_SIGNAL_ARITHMETIC, ®s, fault_addr, FALSE); + break; + case SIGTRAP: + // Correct return address - FIXME ??? probably not needed on IPF + regs.set_ip((void*)((POINTER_SIZE_INT)regs.get_ip() - 1)); + result = port_process_signal(PORT_SIGNAL_BREAKPOINT, ®s, fault_addr, FALSE); + break; + case SIGINT: + result = port_process_signal(PORT_SIGNAL_CTRL_C, ®s, fault_addr, FALSE); + break; + case SIGQUIT: + result = port_process_signal(PORT_SIGNAL_QUIT, ®s, fault_addr, FALSE); + break; + default: + result = port_process_signal(PORT_SIGNAL_UNKNOWN, ®s, fault_addr, TRUE); + } + + if (result == 0) + return; + + // We've got a crash + if (result > 0) + { // result > 0 - invoke debugger + bool result = gdb_crash_handler(®s); + // Continue with exiting process if not sucessful... + } + + // Convert Registers back to OS context + port_thread_regs_to_context((ucontext_t*)context, ®s); + + // result < 0 - exit process + if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + { // Return to the same place to produce the same crash and generate core + signal(signum, SIG_DFL); // setup default handler + return; + } + // No core needed - simply terminate + _exit(-1); +} + + +struct sig_reg +{ + int signal; + int flags; + bool set_up; +}; + +static sig_reg signals_used[] = +{ + { SIGTRAP, SA_SIGINFO, false }, + { SIGSEGV, SA_SIGINFO | SA_ONSTACK, false }, + { SIGFPE, SA_SIGINFO, false }, + { SIGINT, SA_SIGINFO, false }, + { SIGQUIT, SA_SIGINFO, false }, + { SIGABRT, SA_SIGINFO, false } +}; + +static struct sigaction old_actions[sizeof(signals_used)/sizeof(signals_used[0])]; + + +static void restore_signals() +{ + for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++) + { + if (!signals_used[i].set_up) + continue; + + signals_used[i].set_up = false; + sigaction(signals_used[i].signal, &old_actions[i], NULL); + } +} + +int initialize_signals() +{ + struct sigaction sa; + + for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++) + { + sigemptyset(&sa.sa_mask); + sa.sa_flags = signals_used[i].flags; + sa.sa_sigaction = &general_signal_handler; + + if (0 != sigaction(signals_used[i].signal, &sa, &old_actions[i])) + { + restore_signals(); + return -1; + } + } + + // Prepare gdb crash handler + if (!init_gdb_crash_handler()) + { + restore_signals(); + return -1; + } + + return 0; + +} //initialize_signals + +int shutdown_signals() { + cleanup_gdb_crash_handler(); + restore_signals(); + return 0; +} //shutdown_signals + +#if 0 + +// Variables used to locate the context from the signal handler +static int sc_nest = -1; +static bool use_ucontext = false; +static uint32 exam_point; + +/* + * We find the true signal stack frame set-up by kernel,which is located + * by locate_sigcontext() below; then change its content according to + * exception handling semantics, so that when the signal handler is + * returned, application can continue its execution in Java exception handler. + */ + +/* +See function initialize_signals() below first please. + +Two kinds of signal contexts (and stack frames) are tried in +locate_sigcontext(), one is sigcontext, which is the way of +Linux kernel implements( see Linux kernel source +arch/i386/kernel/signal.c for detail); the other is ucontext, +used in some other other platforms. + +The sigcontext locating in Linux is not so simple as expected, +because it involves not only the kernel, but also glibc/linuxthreads, +which VM is linked against. In glibc/linuxthreads, user-provided +signal handler is wrapped by linuxthreads signal handler, i.e. +the signal handler really registered in system is not the one +provided by user. So when Linux kernel finishes setting up signal +stack frame and returns to user mode for singal handler execution, +locate_sigcontext() is not the one being invoked immediately. It's +called by linuxthreads function. That means the user stack viewed by +locate_sigcontext() is NOT NECESSARILY the signal frame set-up by +kernel, we need find the true one according to glibc/linuxthreads +specific signal implementation in different versions. + +Because locate_sigcontext() uses IA32 physical register epb for +call stack frame, compilation option `-fomit-frame-pointer' MUST +not be used when gcc compiles it; and as gcc info, `-O2' will do +`-fomit-frame-pointer' by default, although we haven't seen that +in our experiments. +*/ + +volatile void locate_sigcontext(int signum) +{ + sigcontext *sc, *found_sc; + uint32 *ebp = NULL; + int i; + +//TODO: ADD correct stack handling here!! + +#define SC_SEARCH_WIDTH 3 + for (i = 0; i < SC_SEARCH_WIDTH; i++) { + sc = (sigcontext *)(ebp + 3 ); + if (sc->sc_ip == ((uint32)exam_point)) { // found + sc_nest = i; + use_ucontext = false; + found_sc = sc; + // we will try to find the real sigcontext setup by Linux kernel, + // because if we want to change the execution path after the signal + // handling, we must modify the sigcontext used by kernel. + // LinuxThreads in glibc 2.1.2 setups a sigcontext for our singal + // handler, but we should not modify it, because kernel doesn't use + // it when resumes the application. Then we must find the sigcontext + // setup by kernel, and modify it in singal handler. + // but, with glibc 2.2.3, it's useless to modify only the sigcontext + // setup by Linux kernel, because LinuxThreads does a interesting + // copy after our signal handler returns, which destroys the + // modification we have just done in the handler. So with glibc 2.2.3, + // what we need do is simply to modify the sigcontext setup by + // LinuxThreads, which will be copied to overwrite the one setup by + // kernel. Really complicated..., not really. We use a simple trick + // to overcome the changes in glibc from version to version, that is, + // we modify both sigcontexts setup by kernel and LinuxThreads. Then + // it will always work. + + } else { // not found + struct ucontext *uc; + uc = (struct ucontext *)((uint64)ebp[4]); + if ((ebp < (uint32 *)uc) && ((uint32 *)uc < ebp + 0x100)) { + sc = (sigcontext *)&uc->uc_mcontext; + if (sc->sc_ip == ((uint32)exam_point)) { // found + sc_nest = i; + use_ucontext = true; + found_sc = sc; + break; + } + } + } + + ebp = (uint32 *)((uint64)ebp[0]); + } + + if (sc_nest < 0) { + printf("cannot locate sigcontext.\n"); + printf("Please add or remove any irrelevant statement(e.g. add a null printf) in VM source code, then rebuild it. If problem remains, please submit a bug report. Thank you very much\n"); + exit(1); + } +} + + + +#endif diff --git a/vm/port/src/signals/port_signals.cpp b/vm/port/src/signals/port_signals.cpp new file mode 100644 index 0000000..23e2629 --- /dev/null +++ b/vm/port/src/signals/port_signals.cpp @@ -0,0 +1,54 @@ +/* + * 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. + */ + + +#include "port_crash_handler.h" +#include "port_memaccess.h" +#include "signals_internal.h" + + +int port_set_breakpoint(void* addr, unsigned char* prev) +{ + if (!addr || !prev) + return -1; + + unsigned char instr = INSTRUMENTATION_BYTE; + + if (port_read_memory(addr, 1, prev) != 0) + return -1; + + return port_write_memory(addr, 1, &instr); +} + +int port_clear_breakpoint(void* addr, unsigned char prev) +{ + if (!addr) + return -1; + + return port_write_memory(addr, 1, &prev); +} + +Boolean port_is_breakpoint_set(void* addr) +{ + unsigned char byte; + + if (port_read_memory(addr, 1, &byte) != 0) + return FALSE; + + return (byte == INSTRUMENTATION_BYTE); +} + diff --git a/vm/port/src/signals/win/signals_common.cpp b/vm/port/src/signals/win/signals_common.cpp new file mode 100644 index 0000000..5d90b13 --- /dev/null +++ b/vm/port/src/signals/win/signals_common.cpp @@ -0,0 +1,320 @@ +/* + * 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. + */ + + +#include +#include "open/platform_types.h" +#include "open/hythread_ext.h" +#include "port_malloc.h" + +// Windows specific +//#include +//#include +#ifndef NO_DBGHELP +#include +#pragma comment(linker, "/defaultlib:dbghelp.lib") +#endif + +#include "port_crash_handler.h" +#include "stack_dump.h" +#include "signals_internal.h" + + +#if INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 +#define JVMTI_EXCEPTION_STATUS STATUS_BREAKPOINT +#elif INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_HLT || INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_CLI +#define JVMTI_EXCEPTION_STATUS STATUS_PRIVILEGED_INSTRUCTION +#else +#error Unknown value of INSTRUMENTATION_BYTE +#endif + + +#ifndef NO_DBGHELP +typedef BOOL (WINAPI *MiniDumpWriteDump_type) + (HANDLE hProcess, + DWORD ProcessId, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + PMINIDUMP_CALLBACK_INFORMATION CallbackParam); +#endif // #ifndef NO_DBGHELP + + +port_tls_key_t port_tls_key = TLS_OUT_OF_INDEXES; + +int init_private_tls_data() +{ + DWORD key = TlsAlloc(); + + if (key == TLS_OUT_OF_INDEXES) + return -1; + + port_tls_key = key; + return 0; +} + +int free_private_tls_data() +{ + return TlsFree(port_tls_key) ? 0 : -1; +} + + +static void create_minidump(LPEXCEPTION_POINTERS exp) +{ +#ifndef NO_DBGHELP + MINIDUMP_EXCEPTION_INFORMATION mei = {GetCurrentThreadId(), exp, TRUE}; + MiniDumpWriteDump_type mdwd = NULL; + + HMODULE hdbghelp = ::LoadLibrary("dbghelp"); + + if (hdbghelp) + mdwd = (MiniDumpWriteDump_type)::GetProcAddress(hdbghelp, "MiniDumpWriteDump"); + + if (!mdwd) + { + fprintf(stderr, "Failed to open DbgHelp library"); + return; + } + + char filename[24]; + sprintf(filename, "minidump_%d.dmp", GetCurrentProcessId()); + + HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + if (file == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "Failed to create minidump file: %s", filename); + return; + } + + SymInitialize(GetCurrentProcess(), NULL, TRUE); + + BOOL res = mdwd(GetCurrentProcess(), GetCurrentProcessId(), + file, MiniDumpNormal, &mei, 0, 0); + + if (!res) + { + fprintf(stderr, "Failed to create minidump"); + } + else + { + char dir[_MAX_PATH]; + GetCurrentDirectory(_MAX_PATH, dir); + fprintf(stderr, "Minidump is generated:\n%s\\%s", dir, filename); + } + + CloseHandle(file); +#endif // #ifndef NO_DBGHELP +} + + +static void c_handler(Registers* pregs, + void* fault_addr, size_t code, size_t flags) +{ // this exception handler is executed *after* VEH handler returned + int result; + Registers regs = *pregs; + Boolean iscrash = (DWORD)flags == EXCEPTION_NONCONTINUABLE; + + switch ((DWORD)code) + { + case STATUS_STACK_OVERFLOW: + result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, iscrash); + break; + case STATUS_ACCESS_VIOLATION: + result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, iscrash); + break; + case STATUS_INTEGER_DIVIDE_BY_ZERO: + result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, iscrash); + break; + case JVMTI_EXCEPTION_STATUS: + result = port_process_signal(PORT_SIGNAL_BREAKPOINT, pregs, fault_addr, iscrash); + break; + default: + result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE); + } + + if (result == 0) + return; + + // We've got a crash + if (result < 0) + { + if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + { + // Prepare second-chance exception in the same place to produce + // minidump - because we've lost LPEXCEPTION_POINTERS structure already + // FIXME: This most probably will not work for stack overflow, because + // guard page is disabled automatically - need to restore somehow + port_tls_data* tlsdata = get_private_tls_data(); + if (!tlsdata) + { // STD_MALLOC can be harmful here + tlsdata = (port_tls_data*)STD_MALLOC(sizeof(port_tls_data)); + memset(tlsdata, 0, sizeof(port_tls_data)); + set_private_tls_data(tlsdata); + } + + tlsdata->produce_core = TRUE; + return; // To produce second-chance exception + } + + ExitProcess((UINT)-1); + } + + // result > 0 + // Remove handler and restore console settings to show assert dialog + shutdown_signals(); +} + +LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception) +{ + // Check if TLS structure is set - probably we should produce minidump + port_tls_data* tlsdata = get_private_tls_data(); + + if (tlsdata && tlsdata->produce_core) + { + create_minidump(nt_exception); + if ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0) + { + shutdown_signals(); + return EXCEPTION_CONTINUE_SEARCH; + } + else + ExitProcess((UINT)-1); + } + + switch (nt_exception->ExceptionRecord->ExceptionCode) + { + case STATUS_STACK_OVERFLOW: + case STATUS_ACCESS_VIOLATION: + case STATUS_INTEGER_DIVIDE_BY_ZERO: + case JVMTI_EXCEPTION_STATUS: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_OVERFLOW: + break; + default: + return EXCEPTION_CONTINUE_SEARCH; + } + + Registers regs; + // Convert NT context to Registers + port_thread_context_to_regs(®s, nt_exception->ContextRecord); + // Prepare to transfering control out of VEH handler + port_set_longjump_regs(&c_handler, ®s, 4, ®s, + nt_exception->ExceptionRecord->ExceptionAddress, + (void*)(size_t)nt_exception->ExceptionRecord->ExceptionCode, + (void*)(size_t)nt_exception->ExceptionRecord->ExceptionFlags); + // Convert prepared Registers back to NT context + port_thread_regs_to_context(nt_exception->ContextRecord, ®s); + // Return from VEH - presumably continue execution + return EXCEPTION_CONTINUE_EXECUTION; +} + +BOOL ctrl_handler(DWORD ctrlType) +{ + int result = 0; + + switch (ctrlType) + { + case CTRL_BREAK_EVENT: + result = port_process_signal(PORT_SIGNAL_CTRL_BREAK, NULL, NULL, FALSE); + if (result == 0) + return TRUE; + else + return FALSE; + + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + result = port_process_signal(PORT_SIGNAL_CTRL_C, NULL, NULL, FALSE); + if (result == 0) + return TRUE; + else + return FALSE; + } + + return FALSE; +} + +static int report_modes[4]; +static _HFILE report_files[3]; + +static void disable_assert_dialogs() +{ +#ifdef _DEBUG + report_modes[0] = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + report_files[0] = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + report_modes[1] = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + report_files[1] = _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + report_modes[2] = _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + report_files[2] = _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + report_modes[3] = _set_error_mode(_OUT_TO_STDERR); +#endif // _DEBUG +} + +static void restore_assert_dialogs() +{ +#ifdef _DEBUG + _CrtSetReportMode(_CRT_ASSERT, report_modes[0]); + _CrtSetReportFile(_CRT_ASSERT, report_files[0]); + _CrtSetReportMode(_CRT_ERROR, report_modes[1]); + _CrtSetReportFile(_CRT_ERROR, report_files[1]); + _CrtSetReportMode(_CRT_WARN, report_modes[2]); + _CrtSetReportFile(_CRT_WARN, report_files[2]); + _set_error_mode(report_modes[3]); +#endif // _DEBUG +} + +static PVOID veh = NULL; + +int initialize_signals() +{ + BOOL ok = SetConsoleCtrlHandler((PHANDLER_ROUTINE)ctrl_handler, TRUE); + + if (!ok) + return -1; + + // Adding vectored exception handler + veh = AddVectoredExceptionHandler(0, vectored_exception_handler); + + if (!veh) + return -1; + + disable_assert_dialogs(); + + return 0; +} + +int shutdown_signals() +{ + ULONG res; + res = RemoveVectoredExceptionHandler(veh); + + if (!res) + return -1; + + restore_assert_dialogs(); + + return 0; +} //shutdown_signals diff --git a/vm/port/src/signals/win/signals_ia32.cpp b/vm/port/src/signals/win/signals_ia32.cpp index feef001..187645e 100644 --- a/vm/port/src/signals/win/signals_ia32.cpp +++ b/vm/port/src/signals/win/signals_ia32.cpp @@ -15,9 +15,7 @@ * limitations under the License. */ -#include "platform_lowlevel.h" -#include "exceptions_jit.h" -#include "exception_filter.h" +#include "signals_internal.h" LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) diff --git a/vm/tests/unit/thread/test_native_fat_monitor.c b/vm/tests/unit/thread/test_native_fat_monitor.c index aa1b4a7..172ffd3 100644 --- a/vm/tests/unit/thread/test_native_fat_monitor.c +++ b/vm/tests/unit/thread/test_native_fat_monitor.c @@ -23,7 +23,7 @@ #define NMB 5 hythread_monitor_t monitor; -hymutex_t *mutex; +osmutex_t *mutex; hycond_t *condvar; int waiting_count; diff --git a/vm/tests/unit/thread/test_stress_suspend.h b/vm/tests/unit/thread/test_stress_suspend.h index 95bf67d..5823176 100644 --- a/vm/tests/unit/thread/test_stress_suspend.h +++ b/vm/tests/unit/thread/test_stress_suspend.h @@ -20,6 +20,7 @@ #include #include #include +#include "port_mutex.h" #include "thread_manager.h" #include "testframe.h" #include "thread_unit_test_utils.h" @@ -48,8 +49,8 @@ static uint32 test_waste_time(uint32 count); static hylatch_t wait_threads; static hylatch_t start; -static hymutex_t gc_lock; -static hymutex_t suspend_lock; +static osmutex_t gc_lock; +static osmutex_t suspend_lock; static char stop = 0; static char failed = 0; static uint64 cycle_count = 0; @@ -80,7 +81,7 @@ int test_function(void) tf_exp_assert(status == TM_ERROR_NONE); status = hylatch_create(&start, 1); tf_exp_assert(status == TM_ERROR_NONE); - status = hymutex_create(&gc_lock, TM_MUTEX_NESTED); + status = port_mutex_create(&gc_lock, APR_THREAD_MUTEX_NESTED); tf_exp_assert(status == TM_ERROR_NONE); // start tested thread @@ -333,13 +334,13 @@ static IDATA HYTHREAD_PROC test_gc_request_thread_proc(void *args) count = cycle_count; - status = hymutex_lock(&gc_lock); + status = port_mutex_lock(&gc_lock); tf_exp_assert(status == TM_ERROR_NONE); test_requestor_heap_access(); tf_exp_assert(status == TM_ERROR_NONE); - status = hymutex_unlock(&gc_lock); + status = port_mutex_unlock(&gc_lock); tf_exp_assert(status == TM_ERROR_NONE); xx += test_waste_time(RAND()); diff --git a/vm/thread/src/hythr.def b/vm/thread/src/hythr.def index fa7c8ae..f024626 100644 --- a/vm/thread/src/hythr.def +++ b/vm/thread/src/hythr.def @@ -122,11 +122,6 @@ hysem_wait_timed hysem_wait_interruptable hysem_getvalue hysem_set -hymutex_create -hymutex_lock -hymutex_trylock -hymutex_unlock -hymutex_destroy hythread_is_alive hythread_is_terminated diff --git a/vm/thread/src/hythr.exp b/vm/thread/src/hythr.exp index ef909e3..ccfb158 100644 --- a/vm/thread/src/hythr.exp +++ b/vm/thread/src/hythr.exp @@ -135,11 +135,6 @@ hysem_wait_timed; hysem_wait_interruptable; hysem_getvalue; hysem_set; -hymutex_create; -hymutex_lock; -hymutex_trylock; -hymutex_unlock; -hymutex_destroy; hythread_exit; hythread_is_alive; diff --git a/vm/thread/src/linux/os_condvar.c b/vm/thread/src/linux/os_condvar.c index e8a6ccb..9acd81d 100644 --- a/vm/thread/src/linux/os_condvar.c +++ b/vm/thread/src/linux/os_condvar.c @@ -34,7 +34,7 @@ * This function does not implement interruptability and thread state * functionality, thus the caller of this function have to handle it. */ -int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) +int os_cond_timedwait(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { int r = 0; diff --git a/vm/thread/src/linux/os_mutex.c b/vm/thread/src/linux/os_mutex.c index 6fc8b4d..9fe6b4d 100644 --- a/vm/thread/src/linux/os_mutex.c +++ b/vm/thread/src/linux/os_mutex.c @@ -45,7 +45,7 @@ * APR_THREAD_MUTEX_UNNESTED disable nested locks (non-recursive). * */ -IDATA VMCALL hymutex_create (hymutex_t *mutex, UDATA flags) { +IDATA VMCALL hymutex_create (osmutex_t *mutex, UDATA flags) { int r = 0; if (flags & APR_THREAD_MUTEX_NESTED) { pthread_mutexattr_t attr; @@ -67,7 +67,7 @@ IDATA VMCALL hymutex_create (hymutex_t *mutex, UDATA flags) { * @param[in] mutex the mutex on which to acquire the lock. * @sa apr_thread_mutex_lock() */ -IDATA VMCALL hymutex_lock(hymutex_t *mutex) { +IDATA VMCALL hymutex_lock(osmutex_t *mutex) { return pthread_mutex_lock(mutex); } @@ -77,7 +77,7 @@ IDATA VMCALL hymutex_lock(hymutex_t *mutex) { * @param[in] mutex the mutex on which to attempt the lock acquiring. * @sa apr_thread_mutex_trylock() */ -IDATA VMCALL hymutex_trylock (hymutex_t *mutex) { +IDATA VMCALL hymutex_trylock (osmutex_t *mutex) { int r; r = pthread_mutex_trylock(mutex); if (r == EBUSY) return TM_ERROR_EBUSY; @@ -90,7 +90,7 @@ IDATA VMCALL hymutex_trylock (hymutex_t *mutex) { * @param[in] mutex the mutex from which to release the lock. * @sa apr_thread_mutex_unlock() */ -IDATA VMCALL hymutex_unlock (hymutex_t *mutex) { +IDATA VMCALL hymutex_unlock (osmutex_t *mutex) { return pthread_mutex_unlock(mutex); } @@ -100,7 +100,7 @@ IDATA VMCALL hymutex_unlock (hymutex_t *mutex) { * @param[in] mutex the mutex to destroy. * @sa apr_thread_mutex_destroy() */ -IDATA VMCALL hymutex_destroy (hymutex_t *mutex) { +IDATA VMCALL hymutex_destroy (osmutex_t *mutex) { return pthread_mutex_destroy(mutex); } diff --git a/vm/thread/src/thread_init.c b/vm/thread/src/thread_init.c index 699f0a8..edc4e74 100644 --- a/vm/thread/src/thread_init.c +++ b/vm/thread/src/thread_init.c @@ -24,6 +24,7 @@ #define LOG_DOMAIN "tm.init" #include +#include "port_mutex.h" #include "thread_private.h" //global constants: @@ -38,7 +39,7 @@ apr_pool_t *TM_POOL = NULL; apr_threadkey_t *TM_THREAD_KEY; //Thread manager global lock -hymutex_t TM_START_LOCK; +osmutex_t TM_START_LOCK; static int hythread_library_state = TM_LIBRARY_STATUS_NOT_INITIALIZED; #define GLOBAL_MONITOR_NAME "global_monitor" hythread_monitor_t p_global_monitor; @@ -145,9 +146,9 @@ void VMCALL hythread_init(hythread_library_t lib) { apr_status = apr_threadkey_private_create(&TM_THREAD_KEY, NULL, TM_POOL); assert(apr_status == APR_SUCCESS); - status = hymutex_create(&lib->TM_LOCK, TM_MUTEX_NESTED); + status = port_mutex_create(&lib->TM_LOCK, APR_THREAD_MUTEX_NESTED); assert(status == TM_ERROR_NONE); - status = hymutex_create(&TM_START_LOCK, TM_MUTEX_NESTED); + status = port_mutex_create(&TM_START_LOCK, APR_THREAD_MUTEX_NESTED); assert(status == TM_ERROR_NONE); status = init_group_list(); @@ -210,7 +211,7 @@ void VMCALL hythread_lib_lock(hythread_t self) { IDATA status; assert(self == hythread_self()); - status = hymutex_lock(&self->library->TM_LOCK); + status = port_mutex_lock(&self->library->TM_LOCK); assert(status == TM_ERROR_NONE); } @@ -223,7 +224,7 @@ void VMCALL hythread_lib_unlock(hythread_t self) { IDATA status; assert(self == hythread_self()); - status = hymutex_unlock(&self->library->TM_LOCK); + status = port_mutex_unlock(&self->library->TM_LOCK); assert(status == TM_ERROR_NONE); } @@ -239,7 +240,7 @@ IDATA VMCALL hythread_global_lock() { // we need not care about suspension if the thread // is not even attached to hythread if (self == NULL) { - return hymutex_lock(&TM_LIBRARY->TM_LOCK); + return port_mutex_lock(&TM_LIBRARY->TM_LOCK); } // disable_count must be 0 on potentially @@ -247,7 +248,7 @@ IDATA VMCALL hythread_global_lock() { // meaning that the thread is safe for suspension assert(hythread_is_suspend_enabled()); - status = hymutex_lock(&TM_LIBRARY->TM_LOCK); + status = port_mutex_lock(&TM_LIBRARY->TM_LOCK); assert(status == TM_ERROR_NONE); // make sure we do not get a global thread lock @@ -255,10 +256,10 @@ IDATA VMCALL hythread_global_lock() { while (self->suspend_count) { // give up global thread lock before safepoint, // because this thread can be suspended at a safepoint - status = hymutex_unlock(&TM_LIBRARY->TM_LOCK); + status = port_mutex_unlock(&TM_LIBRARY->TM_LOCK); assert(status == TM_ERROR_NONE); hythread_safe_point(); - status = hymutex_lock(&TM_LIBRARY->TM_LOCK); + status = port_mutex_lock(&TM_LIBRARY->TM_LOCK); assert(status == TM_ERROR_NONE); } return TM_ERROR_NONE; @@ -271,7 +272,7 @@ IDATA VMCALL hythread_global_lock() { IDATA VMCALL hythread_global_unlock() { IDATA status; assert(!hythread_self() || hythread_is_suspend_enabled()); - status = hymutex_unlock(&TM_LIBRARY->TM_LOCK); + status = port_mutex_unlock(&TM_LIBRARY->TM_LOCK); assert(status == TM_ERROR_NONE); return TM_ERROR_NONE; } @@ -309,7 +310,7 @@ static IDATA init_group_list() { assert (lock_table->tables[0]); assert (lock_table->live_objs); - if (hymutex_create(&lock_table->mutex, APR_THREAD_MUTEX_NESTED)) { + if (port_mutex_create(&lock_table->mutex, APR_THREAD_MUTEX_NESTED)) { return TM_ERROR_OUT_OF_MEMORY; } @@ -357,7 +358,7 @@ static IDATA destroy_group_list() { free(lock_table->tables[i]); } - hymutex_destroy(&lock_table->mutex); + port_mutex_destroy(&lock_table->mutex); hycond_destroy(&lock_table->write); hycond_destroy(&lock_table->read); @@ -370,11 +371,11 @@ static IDATA destroy_group_list() { } IDATA acquire_start_lock() { - return hymutex_lock(&TM_START_LOCK); + return port_mutex_lock(&TM_START_LOCK); } IDATA release_start_lock() { - return hymutex_unlock(&TM_START_LOCK); + return port_mutex_unlock(&TM_START_LOCK); } /* diff --git a/vm/thread/src/thread_native_basic.c b/vm/thread/src/thread_native_basic.c index 6db927c..3391b82 100644 --- a/vm/thread/src/thread_native_basic.c +++ b/vm/thread/src/thread_native_basic.c @@ -36,6 +36,7 @@ #include #include #include "port_thread.h" +#include "port_mutex.h" #include "thread_private.h" extern hythread_group_t TM_DEFAULT_GROUP; @@ -383,11 +384,11 @@ IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable) { mon->wait_count++; // Set thread state - status = hymutex_lock(&self->mutex); + status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); self->waited_monitor = mon; self->state |= TM_THREAD_STATE_SLEEPING; - status = hymutex_unlock(&self->mutex); + status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); do { @@ -420,11 +421,11 @@ IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable) { } while(1); // Restore thread state - status = hymutex_lock(&self->mutex); + status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); self->state &= ~TM_THREAD_STATE_SLEEPING; self->waited_monitor = NULL; - status = hymutex_unlock(&self->mutex); + status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); // Release thread monitor @@ -606,9 +607,9 @@ IDATA VMCALL hythread_set_to_group(hythread_t thread, hythread_group_t group) { thread->prev = prev; prev->next = cur->prev = thread; - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state |= TM_THREAD_STATE_ALIVE | TM_THREAD_STATE_RUNNABLE; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); @@ -664,7 +665,7 @@ IDATA VMCALL hythread_struct_init(hythread_t new_thread) memset(new_thread, 0, sizeof(HyThread)); status = hysem_create(&new_thread->resume_event, 0, 1); assert(status == TM_ERROR_NONE); - status = hymutex_create(&new_thread->mutex, TM_MUTEX_NESTED); + status = port_mutex_create(&new_thread->mutex, APR_THREAD_MUTEX_NESTED); assert(status == TM_ERROR_NONE); status = hythread_monitor_init(&new_thread->monitor, 0); assert(status == TM_ERROR_NONE); @@ -672,7 +673,7 @@ IDATA VMCALL hythread_struct_init(hythread_t new_thread) // old thread, reset structure int result; hysem_t resume; - hymutex_t mutex; + osmutex_t mutex; hythread_monitor_t monitor; // release thread OS handle @@ -696,9 +697,9 @@ IDATA VMCALL hythread_struct_init(hythread_t new_thread) new_thread->priority = HYTHREAD_PRIORITY_NORMAL; new_thread->stacksize = os_get_foreign_thread_stack_size(); - hymutex_lock(&new_thread->mutex); + port_mutex_lock(&new_thread->mutex); new_thread->state = TM_THREAD_STATE_NEW; - hymutex_unlock(&new_thread->mutex); + port_mutex_unlock(&new_thread->mutex); status = hysem_set(new_thread->resume_event, 0); assert(status == TM_ERROR_NONE); @@ -718,7 +719,7 @@ IDATA VMCALL hythread_struct_release(hythread_t thread) // Release thread primitives status = hysem_destroy(thread->resume_event); assert(status == TM_ERROR_NONE); - status = hymutex_destroy(&thread->mutex); + status = port_mutex_destroy(&thread->mutex); assert(status == TM_ERROR_NONE); status = hythread_monitor_destroy(thread->monitor); assert(status == TM_ERROR_NONE); @@ -756,9 +757,9 @@ static int HYTHREAD_PROC hythread_wrapper_start_proc(void *arg) { // check hythread library state if (hythread_lib_state() != TM_LIBRARY_STATUS_INITIALIZED) { // set TERMINATED state - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state = TM_THREAD_STATE_TERMINATED; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); // set hythread_self() hythread_set_self(thread); @@ -807,9 +808,9 @@ static int HYTHREAD_PROC hythread_wrapper_start_proc(void *arg) { assert(status == TM_ERROR_NONE); // set TERMINATED state - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state = TM_THREAD_STATE_TERMINATED; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); // detach and free thread hythread_detach(thread); @@ -854,28 +855,28 @@ UDATA hythread_get_thread_stacksize(hythread_t thread) { IDATA VMCALL hythread_thread_lock(hythread_t thread) { assert(thread); - return hymutex_lock(&thread->mutex); + return port_mutex_lock(&thread->mutex); } // hythread_thread_lock IDATA VMCALL hythread_thread_unlock(hythread_t thread) { assert(thread); - return hymutex_unlock(&thread->mutex); + return port_mutex_unlock(&thread->mutex); } // hythread_thread_unlock IDATA VMCALL hythread_get_state(hythread_t thread) { IDATA state; assert(thread); - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); state = thread->state; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); return state; } // hythread_get_state IDATA VMCALL hythread_set_state(hythread_t thread, IDATA state) { assert(thread); - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state = state; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); return TM_ERROR_NONE; } // hythread_set_state @@ -934,7 +935,7 @@ IDATA VMCALL hythread_wait_for_nondaemon_threads(hythread_t thread, IDATA thread assert(thread); lib = thread->library; - status = hymutex_lock(&lib->TM_LOCK); + status = port_mutex_lock(&lib->TM_LOCK); if (status != TM_ERROR_NONE) { return status; } @@ -948,37 +949,37 @@ IDATA VMCALL hythread_wait_for_nondaemon_threads(hythread_t thread, IDATA thread lib->nondaemon_thread_count)); if (status != TM_ERROR_NONE) { - hymutex_unlock(&lib->TM_LOCK); + port_mutex_unlock(&lib->TM_LOCK); return status; } } - status = hymutex_unlock(&lib->TM_LOCK); + status = port_mutex_unlock(&lib->TM_LOCK); return status; } // hythread_wait_for_nondaemon_threads IDATA VMCALL hythread_increase_nondaemon_threads_count(hythread_t thread) { hythread_library_t lib = thread->library; - IDATA status = hymutex_lock(&lib->TM_LOCK); + IDATA status = port_mutex_lock(&lib->TM_LOCK); if (status != TM_ERROR_NONE) { return status; } lib->nondaemon_thread_count++; - status = hymutex_unlock(&lib->TM_LOCK); + status = port_mutex_unlock(&lib->TM_LOCK); return status; } // hythread_increase_nondaemon_threads_count_in_library IDATA VMCALL hythread_decrease_nondaemon_threads_count(hythread_t thread, IDATA threads_to_keep) { hythread_library_t lib = thread->library; - IDATA status = hymutex_lock(&lib->TM_LOCK); + IDATA status = port_mutex_lock(&lib->TM_LOCK); if (status != TM_ERROR_NONE) { return status; } if (lib->nondaemon_thread_count <= 0) { - status = hymutex_unlock(&lib->TM_LOCK); + status = port_mutex_unlock(&lib->TM_LOCK); if (status != TM_ERROR_NONE) { return status; } @@ -994,12 +995,12 @@ IDATA VMCALL hythread_decrease_nondaemon_threads_count(hythread_t thread, IDATA TRACE(("TM: nondaemons all dead, thread: %p count: %d\n", thread, lib->nondaemon_thread_count)); if (status != TM_ERROR_NONE) { - hymutex_unlock(&lib->TM_LOCK); + port_mutex_unlock(&lib->TM_LOCK); return status; } } - status = hymutex_unlock(&lib->TM_LOCK); + status = port_mutex_unlock(&lib->TM_LOCK); return status; } // hythread_countdown_nondaemon_threads diff --git a/vm/thread/src/thread_native_condvar.c b/vm/thread/src/thread_native_condvar.c index e2fc3d1..5a69b53 100644 --- a/vm/thread/src/thread_native_condvar.c +++ b/vm/thread/src/thread_native_condvar.c @@ -31,7 +31,7 @@ /** * Waits on a conditional, handling interruptions and thread state. */ -IDATA condvar_wait_impl(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano, IDATA interruptable) { +IDATA condvar_wait_impl(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano, IDATA interruptable) { int r; int disable_count; hythread_t self; @@ -77,7 +77,7 @@ IDATA condvar_wait_impl(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano, I * @return * TM_NO_ERROR on success */ -IDATA VMCALL hycond_wait(hycond_t *cond, hymutex_t *mutex) { +IDATA VMCALL hycond_wait(hycond_t *cond, osmutex_t *mutex) { return condvar_wait_impl(cond, mutex, 0, 0, WAIT_NONINTERRUPTABLE); } @@ -93,7 +93,7 @@ IDATA VMCALL hycond_wait(hycond_t *cond, hymutex_t *mutex) { * @return * TM_NO_ERROR on success */ -IDATA VMCALL hycond_wait_timed(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) { +IDATA VMCALL hycond_wait_timed(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { return condvar_wait_impl(cond, mutex, ms, nano, WAIT_NONINTERRUPTABLE); } @@ -102,7 +102,7 @@ IDATA VMCALL hycond_wait_timed(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA * Directly using OS interfaces. * This function does not implement interruptability and thread state functionality. */ -IDATA VMCALL hycond_wait_timed_raw(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) { +IDATA VMCALL hycond_wait_timed_raw(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { return os_cond_timedwait(cond, mutex, ms, nano); } @@ -119,7 +119,7 @@ IDATA VMCALL hycond_wait_timed_raw(hycond_t *cond, hymutex_t *mutex, I_64 ms, ID * TM_NO_ERROR on success * TM_THREAD_INTERRUPTED in case thread was interrupted during wait. */ -IDATA VMCALL hycond_wait_interruptable(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) { +IDATA VMCALL hycond_wait_interruptable(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { return condvar_wait_impl(cond, mutex, ms, nano, WAIT_INTERRUPTABLE); } diff --git a/vm/thread/src/thread_native_fat_monitor.c b/vm/thread/src/thread_native_fat_monitor.c index f54ff9d..31ebe17 100644 --- a/vm/thread/src/thread_native_fat_monitor.c +++ b/vm/thread/src/thread_native_fat_monitor.c @@ -27,6 +27,7 @@ #undef LOG_DOMAIN #define LOG_DOMAIN "tm.locks" #include +#include "port_mutex.h" #include "thread_private.h" /** @@ -50,7 +51,7 @@ IDATA VMCALL hythread_monitor_init_with_name(hythread_monitor_t *mon_ptr, UDATA if (mon == NULL) { return TM_ERROR_OUT_OF_MEMORY; } - r = hymutex_create(&mon->mutex, TM_MUTEX_NESTED); + r = port_mutex_create(&mon->mutex, APR_THREAD_MUTEX_NESTED); if (r) { goto cleanup; } @@ -87,7 +88,7 @@ IDATA VMCALL hythread_monitor_enter(hythread_monitor_t mon_ptr) { IDATA status; hythread_t self = tm_self_tls; if (mon_ptr->owner != self) { - status = hymutex_lock(&mon_ptr->mutex); + status = port_mutex_lock(&mon_ptr->mutex); mon_ptr->owner = self; assert(status == TM_ERROR_NONE); } else { @@ -115,7 +116,7 @@ IDATA VMCALL hythread_monitor_try_enter(hythread_monitor_t mon_ptr) { IDATA status; hythread_t self = tm_self_tls; if (mon_ptr->owner != self) { - status = hymutex_trylock(&mon_ptr->mutex); + status = port_mutex_trylock(&mon_ptr->mutex); if (status == TM_ERROR_NONE) { mon_ptr->owner = tm_self_tls; } @@ -149,7 +150,7 @@ IDATA VMCALL hythread_monitor_exit(hythread_monitor_t mon_ptr) { } if (mon_ptr->recursion_count == 0) { mon_ptr->owner = NULL; - status = hymutex_unlock(&mon_ptr->mutex); + status = port_mutex_unlock(&mon_ptr->mutex); } else { mon_ptr->recursion_count--; } @@ -174,10 +175,10 @@ IDATA monitor_wait_impl(hythread_monitor_t mon_ptr, I_64 ms, IDATA nano, IDATA i mon_ptr->owner = NULL; mon_ptr->recursion_count =0; mon_ptr->wait_count++; - hymutex_lock(&self->mutex); + port_mutex_lock(&self->mutex); self->state |= TM_THREAD_STATE_IN_MONITOR_WAIT; self->waited_monitor = mon_ptr; - hymutex_unlock(&self->mutex); + port_mutex_unlock(&self->mutex); do { apr_time_t start; @@ -215,21 +216,21 @@ IDATA monitor_wait_impl(hythread_monitor_t mon_ptr, I_64 ms, IDATA nano, IDATA i mon_ptr->notify_count--; } - hymutex_lock(&self->mutex); + port_mutex_lock(&self->mutex); self->state &= ~TM_THREAD_STATE_IN_MONITOR_WAIT; self->waited_monitor = NULL; - hymutex_unlock(&self->mutex); + port_mutex_unlock(&self->mutex); mon_ptr->wait_count--; assert(mon_ptr->notify_count <= mon_ptr->wait_count); if (self->request) { int save_count; - hymutex_unlock(&mon_ptr->mutex); + port_mutex_unlock(&mon_ptr->mutex); hythread_safe_point(); hythread_exception_safe_point(); save_count = hythread_reset_suspend_disable(); - hymutex_lock(&mon_ptr->mutex); + port_mutex_lock(&mon_ptr->mutex); hythread_set_suspend_disable(save_count); } @@ -378,7 +379,7 @@ IDATA VMCALL hythread_monitor_destroy(hythread_monitor_t monitor) { return TM_ERROR_ILLEGAL_STATE; } - hymutex_destroy(&monitor->mutex); + port_mutex_destroy(&monitor->mutex); hycond_destroy(&monitor->condition); free(monitor); return TM_ERROR_NONE; diff --git a/vm/thread/src/thread_native_latch.c b/vm/thread/src/thread_native_latch.c index 9e25835..f1cde6f 100644 --- a/vm/thread/src/thread_native_latch.c +++ b/vm/thread/src/thread_native_latch.c @@ -21,6 +21,7 @@ */ #include +#include "port_mutex.h" #include "thread_private.h" @@ -48,7 +49,7 @@ IDATA VMCALL hylatch_create(hylatch_t *latch_ptr, IDATA count) { if (latch == NULL) { return TM_ERROR_OUT_OF_MEMORY; } - res = hymutex_create(&latch->mutex, TM_MUTEX_DEFAULT); + res = port_mutex_create(&latch->mutex, APR_THREAD_MUTEX_DEFAULT); if (res) { goto cleanup; } @@ -61,7 +62,7 @@ IDATA VMCALL hylatch_create(hylatch_t *latch_ptr, IDATA count) { return TM_ERROR_NONE; cleanup_mutex: - hymutex_destroy(&latch->mutex); + port_mutex_destroy(&latch->mutex); cleanup: free(latch); @@ -73,7 +74,7 @@ cleanup: static IDATA latch_wait_impl(hylatch_t latch, I_64 ms, IDATA nano, IDATA interruptable) { IDATA status; - status = hymutex_lock(&latch->mutex); + status = port_mutex_lock(&latch->mutex); if (status != TM_ERROR_NONE) { return status; } @@ -81,13 +82,13 @@ static IDATA latch_wait_impl(hylatch_t latch, I_64 ms, IDATA nano, IDATA interru status = condvar_wait_impl(&latch->condition, &latch->mutex, ms, nano, interruptable); //check interruption and other problems if (status != TM_ERROR_NONE) { - hymutex_unlock(&latch->mutex); + port_mutex_unlock(&latch->mutex); return status; } if (ms || nano) break; } - status = hymutex_unlock(&latch->mutex); + status = port_mutex_unlock(&latch->mutex); return status; } @@ -143,10 +144,10 @@ IDATA VMCALL hylatch_wait_interruptable(hylatch_t latch, I_64 ms, IDATA nano) { IDATA VMCALL hylatch_set(hylatch_t latch, IDATA count) { IDATA status; - status = hymutex_lock(&latch->mutex); + status = port_mutex_lock(&latch->mutex); if (status != TM_ERROR_NONE) return status; latch->count = count; - status = hymutex_unlock(&latch->mutex); + status = port_mutex_unlock(&latch->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -162,10 +163,10 @@ IDATA VMCALL hylatch_set(hylatch_t latch, IDATA count) { IDATA VMCALL hylatch_count_down(hylatch_t latch) { IDATA status; - status = hymutex_lock(&latch->mutex); + status = port_mutex_lock(&latch->mutex); if (status != TM_ERROR_NONE) return status; if (latch->count <= 0) { - status = hymutex_unlock(&latch->mutex); + status = port_mutex_unlock(&latch->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_ILLEGAL_STATE; } @@ -173,12 +174,12 @@ IDATA VMCALL hylatch_count_down(hylatch_t latch) { if (latch->count == 0) { status = hycond_notify_all(&latch->condition); if (status != TM_ERROR_NONE) { - hymutex_unlock(&latch->mutex); + port_mutex_unlock(&latch->mutex); return status; } } - status = hymutex_unlock(&latch->mutex); + status = port_mutex_unlock(&latch->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -195,10 +196,10 @@ IDATA VMCALL hylatch_count_down(hylatch_t latch) { IDATA VMCALL hylatch_get_count(IDATA *count, hylatch_t latch) { IDATA status; - status = hymutex_lock(&latch->mutex); + status = port_mutex_lock(&latch->mutex); if (status != TM_ERROR_NONE) return status; *count = latch->count; - status = hymutex_unlock(&latch->mutex); + status = port_mutex_unlock(&latch->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -210,7 +211,7 @@ IDATA VMCALL hylatch_get_count(IDATA *count, hylatch_t latch) { * @param[in] latch the latch */ IDATA VMCALL hylatch_destroy(hylatch_t latch) { - IDATA status = hymutex_destroy(&latch->mutex); + IDATA status = port_mutex_destroy(&latch->mutex); status |= hycond_destroy(&latch->condition); free(latch); return status; diff --git a/vm/thread/src/thread_native_park.c b/vm/thread/src/thread_native_park.c index 2243095..262304d 100644 --- a/vm/thread/src/thread_native_park.c +++ b/vm/thread/src/thread_native_park.c @@ -22,6 +22,7 @@ #include #include +#include "port_mutex.h" #include "thread_private.h" /** @@ -56,25 +57,25 @@ IDATA VMCALL hythread_park(I_64 millis, IDATA nanos) { mon->wait_count++; // Set thread state - status = hymutex_lock(&self->mutex); + status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); self->waited_monitor = mon; if (!(self->state & TM_THREAD_STATE_UNPARKED)) { // if thread is not unparked stop the current thread from executing self->state |= TM_THREAD_STATE_PARKED; - status = hymutex_unlock(&self->mutex); + status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); result = condvar_wait_impl(&mon->condition, &mon->mutex, millis, nanos, WAIT_INTERRUPTABLE); // Restore thread state - status = hymutex_lock(&self->mutex); + status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); } self->state &= ~(TM_THREAD_STATE_PARKED|TM_THREAD_STATE_UNPARKED); self->waited_monitor = NULL; - status = hymutex_unlock(&self->mutex); + status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); // Release thread monitor @@ -116,26 +117,26 @@ void VMCALL hythread_unpark(hythread_t thread) { return; } - status = hymutex_lock(&thread->mutex); + status = port_mutex_lock(&thread->mutex); assert(status == TM_ERROR_NONE); if (thread->state & TM_THREAD_STATE_PARKED) { thread->state &= ~TM_THREAD_STATE_PARKED; mon = thread->waited_monitor; assert(mon); - status = hymutex_unlock(&thread->mutex); + status = port_mutex_unlock(&thread->mutex); assert(status == TM_ERROR_NONE); // Notify parked thread - status = hymutex_lock(&mon->mutex); + status = port_mutex_lock(&mon->mutex); assert(status == TM_ERROR_NONE); status = hycond_notify_all(&mon->condition); assert(status == TM_ERROR_NONE); - status = hymutex_unlock(&mon->mutex); + status = port_mutex_unlock(&mon->mutex); assert(status == TM_ERROR_NONE); } else { thread->state |= TM_THREAD_STATE_UNPARKED; - status = hymutex_unlock(&thread->mutex); + status = port_mutex_unlock(&thread->mutex); assert(status == TM_ERROR_NONE); } } diff --git a/vm/thread/src/thread_native_semaphore.c b/vm/thread/src/thread_native_semaphore.c index 1934cda..dbf568e 100644 --- a/vm/thread/src/thread_native_semaphore.c +++ b/vm/thread/src/thread_native_semaphore.c @@ -26,6 +26,7 @@ */ #include +#include "port_mutex.h" #include "thread_private.h" /** @@ -43,7 +44,7 @@ IDATA VMCALL hysem_create(hysem_t *sem, UDATA initial_count, UDATA max_count) { if (l == NULL) { return TM_ERROR_OUT_OF_MEMORY; } - r = hymutex_create(&l->mutex, TM_MUTEX_DEFAULT); + r = port_mutex_create(&l->mutex, APR_THREAD_MUTEX_DEFAULT); if (r) goto cleanup; r = hycond_create(&l->condition); if (r) goto cleanup; @@ -62,7 +63,7 @@ cleanup: IDATA sem_wait_impl(hysem_t sem, I_64 ms, IDATA nano, IDATA interruptable) { IDATA status; - status = hymutex_lock(&sem->mutex); + status = port_mutex_lock(&sem->mutex); if (status != TM_ERROR_NONE) return status; //printf("wait %x %d\n", sem, sem->count); //fflush(NULL); @@ -70,7 +71,7 @@ IDATA sem_wait_impl(hysem_t sem, I_64 ms, IDATA nano, IDATA interruptable) { status = condvar_wait_impl(&sem->condition, &sem->mutex, ms, nano, interruptable); //check interruption and timeout if (status != TM_ERROR_NONE) { - hymutex_unlock(&sem->mutex); + port_mutex_unlock(&sem->mutex); return status; } @@ -79,14 +80,14 @@ IDATA sem_wait_impl(hysem_t sem, I_64 ms, IDATA nano, IDATA interruptable) { //should we check here if timeout is not supposed to happen if (sem->count == 0 /*&& (ms || nano)*/) { if (ms || nano) { - hymutex_unlock(&sem->mutex); + port_mutex_unlock(&sem->mutex); return TM_ERROR_TIMEOUT; } else { assert(0); } } sem->count--; - status = hymutex_unlock(&sem->mutex); + status = port_mutex_unlock(&sem->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -150,10 +151,10 @@ IDATA VMCALL hysem_post(hysem_t sem) { IDATA status; //printf("post %x %d\n", sem, sem->count); //fflush(NULL); - status = hymutex_lock(&sem->mutex); + status = port_mutex_lock(&sem->mutex); if (status != TM_ERROR_NONE) return status; if (sem->count >= sem->max_count) { - hymutex_unlock(&sem->mutex); + port_mutex_unlock(&sem->mutex); //printf("illegal state %d : %d \n", sem->count, sem->max_count); //fflush(NULL); return TM_ERROR_ILLEGAL_STATE; @@ -163,7 +164,7 @@ IDATA VMCALL hysem_post(hysem_t sem) { hycond_notify(&sem->condition); } - status = hymutex_unlock(&sem->mutex); + status = port_mutex_unlock(&sem->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; } @@ -177,10 +178,10 @@ IDATA VMCALL hysem_post(hysem_t sem) { IDATA VMCALL hysem_set(hysem_t sem, IDATA count) { IDATA status; - status = hymutex_lock(&sem->mutex); + status = port_mutex_lock(&sem->mutex); if (status != TM_ERROR_NONE) return status; if (count > sem->max_count) { - hymutex_unlock(&sem->mutex); + port_mutex_unlock(&sem->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_ILLEGAL_STATE; } @@ -188,11 +189,11 @@ IDATA VMCALL hysem_set(hysem_t sem, IDATA count) { if (count > 0) { status = hycond_notify_all(&sem->condition); if (status != TM_ERROR_NONE) { - hymutex_unlock(&sem->mutex); + port_mutex_unlock(&sem->mutex); return status; } } - status = hymutex_unlock(&sem->mutex); + status = port_mutex_unlock(&sem->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -207,10 +208,10 @@ IDATA VMCALL hysem_set(hysem_t sem, IDATA count) { IDATA VMCALL hysem_getvalue(IDATA *count, hysem_t sem) { IDATA status; - status = hymutex_lock(&sem->mutex); + status = port_mutex_lock(&sem->mutex); if (status != TM_ERROR_NONE) return status; *count = sem->count; - status = hymutex_unlock(&sem->mutex); + status = port_mutex_unlock(&sem->mutex); if (status != TM_ERROR_NONE) return status; return TM_ERROR_NONE; @@ -229,7 +230,7 @@ IDATA VMCALL hysem_getvalue(IDATA *count, hysem_t sem) { * @see hysem_init, hysem_wait, hysem_post */ IDATA VMCALL hysem_destroy(hysem_t sem) { - IDATA status = hymutex_destroy(&sem->mutex); + IDATA status = port_mutex_destroy(&sem->mutex); status |= hycond_destroy(&sem->condition); free(sem); return status; diff --git a/vm/thread/src/thread_native_suspend.c b/vm/thread/src/thread_native_suspend.c index 0f43d36..2ad3cce 100644 --- a/vm/thread/src/thread_native_suspend.c +++ b/vm/thread/src/thread_native_suspend.c @@ -24,9 +24,10 @@ #define LOG_DOMAIN "tm.suspend" #include -#include "thread_private.h" #include #include "port_barriers.h" +#include "port_mutex.h" +#include "thread_private.h" static void thread_safe_point_impl(hythread_t thread); @@ -190,9 +191,9 @@ static IDATA wait_safe_region_event(hythread_t thread) TRACE(("suspend wait exit safe region thread: " "%p, suspend_count: %d, request: %d", thread, thread->suspend_count, thread->request)); - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state |= TM_THREAD_STATE_SUSPENDED; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); return TM_ERROR_NONE; } @@ -209,9 +210,9 @@ void VMCALL hythread_suspend() hythread_send_suspend_request(self); - hymutex_lock(&self->mutex); + port_mutex_lock(&self->mutex); self->state |= TM_THREAD_STATE_SUSPENDED; - hymutex_unlock(&self->mutex); + port_mutex_unlock(&self->mutex); thread_safe_point_impl(self); } @@ -302,9 +303,9 @@ void VMCALL hythread_resume(hythread_t thread) } // change thread state - hymutex_lock(&thread->mutex); + port_mutex_lock(&thread->mutex); thread->state &= ~TM_THREAD_STATE_SUSPENDED; - hymutex_unlock(&thread->mutex); + port_mutex_unlock(&thread->mutex); TRACE(("sent resume, self: %p, thread: %p, " "suspend_count: %d, request: %d", self, thread, diff --git a/vm/thread/src/thread_native_thin_monitor.c b/vm/thread/src/thread_native_thin_monitor.c index b7ca6ac..71b56a5 100644 --- a/vm/thread/src/thread_native_thin_monitor.c +++ b/vm/thread/src/thread_native_thin_monitor.c @@ -28,6 +28,7 @@ #include #include "port_barriers.h" #include "port_thread.h" +#include "port_mutex.h" #include "thread_private.h" /** @name Thin monitors support. Implement thin-fat scheme. @@ -133,7 +134,7 @@ int res_lock_count = 0; #ifdef LOCK_RESERVATION -extern hymutex_t TM_LOCK; +extern osmutex_t TM_LOCK; /* * Unreserves the lock already owned by this thread */ @@ -172,7 +173,7 @@ IDATA VMCALL hythread_unreserve_lock(hythread_thin_monitor_t *lockword_ptr) { // trylock used to prevent cyclic suspend deadlock // the java_monitor_enter calls safe_point between attempts. - /*status = hymutex_trylock(&TM_LOCK); + /*status = port_mutex_trylock(&TM_LOCK); if (status !=TM_ERROR_NONE) { return status; }*/ @@ -184,7 +185,7 @@ IDATA VMCALL hythread_unreserve_lock(hythread_thin_monitor_t *lockword_ptr) { owner = hythread_get_thread(lock_id); TRACE(("Unreserved other %d \n", ++unreserve_count/*, vm_get_object_class_name(lockword_ptr-1)*/)); if (!IS_RESERVED(lockword) || IS_FAT_LOCK(lockword)) { - // hymutex_unlock(&TM_LOCK); + // port_mutex_unlock(&TM_LOCK); return TM_ERROR_NONE; } // suspend owner @@ -245,7 +246,7 @@ IDATA VMCALL hythread_unreserve_lock(hythread_thin_monitor_t *lockword_ptr) { hythread_resume(owner); } - /* status = hymutex_unlock(&TM_LOCK);*/ + /* status = port_mutex_unlock(&TM_LOCK);*/ // Gregory - This lock, right after it was unreserved, may be // inflated by another thread and therefore instead of recursion @@ -496,7 +497,7 @@ IDATA VMCALL hythread_thin_monitor_release(hythread_thin_monitor_t *lockword_ptr hythread_monitor_t monitor = locktable_get_fat_monitor(FAT_LOCK_ID(lockword)); monitor->recursion_count = 0; - status = hymutex_unlock(&monitor->mutex); + status = port_mutex_unlock(&monitor->mutex); assert(status == TM_ERROR_NONE); } else { // this is thin monitor @@ -730,7 +731,7 @@ void deflate_lock(hythread_monitor_t fat_monitor, hythread_thin_monitor_t *lockw * Enter locktable read section */ static void locktable_reader_enter() { - IDATA status = hymutex_lock(&lock_table->mutex); + IDATA status = port_mutex_lock(&lock_table->mutex); assert(status == TM_ERROR_NONE); if (lock_table->state == HYTHREAD_LOCKTABLE_IDLE @@ -746,7 +747,7 @@ static void locktable_reader_enter() { // We are asserting here that we exited wait with the correct state assert(lock_table->state == HYTHREAD_LOCKTABLE_READING); } - status = hymutex_unlock(&lock_table->mutex); + status = port_mutex_unlock(&lock_table->mutex); assert(status == TM_ERROR_NONE); } @@ -754,7 +755,7 @@ static void locktable_reader_enter() { * Exit locktable read section */ static void locktable_reader_exit() { - IDATA status = hymutex_lock(&lock_table->mutex); + IDATA status = port_mutex_lock(&lock_table->mutex); assert(status == TM_ERROR_NONE); lock_table->readers_reading--; @@ -768,7 +769,7 @@ static void locktable_reader_exit() { } } - status = hymutex_unlock(&lock_table->mutex); + status = port_mutex_unlock(&lock_table->mutex); assert(status == TM_ERROR_NONE); } @@ -776,7 +777,7 @@ static void locktable_reader_exit() { * Enter locktable write section */ static void locktable_writer_enter() { - IDATA status = hymutex_lock(&lock_table->mutex); + IDATA status = port_mutex_lock(&lock_table->mutex); assert(status == TM_ERROR_NONE); if (lock_table->state != HYTHREAD_LOCKTABLE_IDLE) { @@ -791,7 +792,7 @@ static void locktable_writer_enter() { lock_table->state = HYTHREAD_LOCKTABLE_WRITING; } - status = hymutex_unlock(&lock_table->mutex); + status = port_mutex_unlock(&lock_table->mutex); assert(status == TM_ERROR_NONE); } @@ -799,7 +800,7 @@ static void locktable_writer_enter() { * Exit locktable write section */ static void locktable_writer_exit() { - IDATA status = hymutex_lock(&lock_table->mutex); + IDATA status = port_mutex_lock(&lock_table->mutex); assert(status == TM_ERROR_NONE); if (lock_table->readers_reading > 0) { @@ -813,7 +814,7 @@ static void locktable_writer_exit() { lock_table->state = HYTHREAD_LOCKTABLE_IDLE; } - status = hymutex_unlock(&lock_table->mutex); + status = port_mutex_unlock(&lock_table->mutex); assert(status == TM_ERROR_NONE); } diff --git a/vm/thread/src/thread_private.h b/vm/thread/src/thread_private.h index adb673c..4f59aae 100644 --- a/vm/thread/src/thread_private.h +++ b/vm/thread/src/thread_private.h @@ -78,7 +78,7 @@ extern int16 tm_tls_size; typedef struct HyThreadLibrary { IDATA a; - hymutex_t TM_LOCK; + osmutex_t TM_LOCK; IDATA nondaemon_thread_count; hycond_t nondaemon_thread_cond; } HyThreadLibrary; @@ -137,7 +137,7 @@ typedef struct HyThreadGroup { typedef struct HyThreadMonitor { /// Monitor mutex. - hymutex_t mutex; + osmutex_t mutex; /// Monitor condition varibale. hycond_t condition; @@ -183,7 +183,7 @@ typedef struct HyLatch { /** * Mutex associated with the latch data. */ - hymutex_t mutex; + osmutex_t mutex; } HyLatch; @@ -211,7 +211,7 @@ typedef struct HySemaphore { /** * Mutex associated with the semaphore data. */ - hymutex_t mutex; + osmutex_t mutex; } HySemaphore; @@ -231,7 +231,7 @@ typedef struct HyFatLockTable { hythread_monitor_t* tables[HY_MAX_FAT_TABLES]; // mutex guarding locktable - hymutex_t mutex; + osmutex_t mutex; hycond_t read; hycond_t write; @@ -297,7 +297,7 @@ IDATA acquire_start_lock(void); IDATA release_start_lock(void); IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable); -IDATA condvar_wait_impl(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano, IDATA interruptable); +IDATA condvar_wait_impl(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano, IDATA interruptable); IDATA monitor_wait_impl(hythread_monitor_t mon_ptr, I_64 ms, IDATA nano, IDATA interruptable); IDATA thin_monitor_wait_impl(hythread_thin_monitor_t *lockword_ptr, I_64 ms, IDATA nano, IDATA interruptable); IDATA sem_wait_impl(hysem_t sem, I_64 ms, IDATA nano, IDATA interruptable); @@ -314,7 +314,7 @@ void os_thread_exit(IDATA status); int os_thread_join(osthread_t os_thread); int os_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser); -int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano); +int os_cond_timedwait(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano); UDATA os_get_foreign_thread_stack_size(); diff --git a/vm/thread/src/win/os_condvar.c b/vm/thread/src/win/os_condvar.c index 5d58371..3c371fb 100644 --- a/vm/thread/src/win/os_condvar.c +++ b/vm/thread/src/win/os_condvar.c @@ -23,6 +23,7 @@ */ #include +#include "port_mutex.h" #include "thread_private.h" static void _enqueue (hycond_t *cond, struct waiting_node *node) @@ -65,7 +66,7 @@ static struct waiting_node * _dequeue (hycond_t *cond) * This function does not implement interruptability and thread state * functionality, thus the caller of this function have to handle it. */ -int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) +int os_cond_timedwait(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { int r = 0; struct waiting_node node; @@ -79,12 +80,12 @@ int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) // NULL attributes, manual reset, initially unsignalled, NULL name node.event = CreateEvent(NULL, TRUE, FALSE, NULL); - hymutex_lock(&cond->queue_mutex); + port_mutex_lock(&cond->queue_mutex); _enqueue(cond, &node); - hymutex_unlock(&cond->queue_mutex); + port_mutex_unlock(&cond->queue_mutex); // release mutex and wait for signal - hymutex_unlock(mutex); + port_mutex_unlock(mutex); res = WaitForSingleObject(node.event, timeout); if (res != WAIT_OBJECT_0) { @@ -95,12 +96,12 @@ int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) } // re-acquire mutex associated with condition variable - hymutex_lock(mutex); + port_mutex_lock(mutex); - hymutex_lock(&cond->queue_mutex); + port_mutex_lock(&cond->queue_mutex); _remove_from_queue(cond, &node); CloseHandle(node.event); - hymutex_unlock(&cond->queue_mutex); + port_mutex_unlock(&cond->queue_mutex); return r; } @@ -117,7 +118,7 @@ int os_cond_timedwait(hycond_t *cond, hymutex_t *mutex, I_64 ms, IDATA nano) */ IDATA VMCALL hycond_create (hycond_t *cond) { cond->dummy_node.next = cond->dummy_node.prev = &cond->dummy_node; - hymutex_create(&cond->queue_mutex, APR_THREAD_MUTEX_NESTED); + port_mutex_create(&cond->queue_mutex, APR_THREAD_MUTEX_NESTED); return 0; } @@ -133,7 +134,7 @@ IDATA VMCALL hycond_notify (hycond_t *cond) { DWORD res; struct waiting_node *node; - hymutex_lock(&cond->queue_mutex); + port_mutex_lock(&cond->queue_mutex); node = _dequeue(cond); if (node != NULL) { res = SetEvent(node->event); @@ -141,7 +142,7 @@ IDATA VMCALL hycond_notify (hycond_t *cond) { r = (int)GetLastError(); } } - hymutex_unlock(&cond->queue_mutex); + port_mutex_unlock(&cond->queue_mutex); return r; } @@ -156,14 +157,14 @@ IDATA VMCALL hycond_notify_all (hycond_t *cond) { DWORD res; struct waiting_node *node; - hymutex_lock(&cond->queue_mutex); + port_mutex_lock(&cond->queue_mutex); for (node = _dequeue(cond); node != NULL; node = _dequeue(cond)) { res = SetEvent(node->event); if (res == 0) { r = GetLastError(); } } - hymutex_unlock(&cond->queue_mutex); + port_mutex_unlock(&cond->queue_mutex); return r; } @@ -176,7 +177,7 @@ IDATA VMCALL hycond_notify_all (hycond_t *cond) { IDATA VMCALL hycond_destroy (hycond_t *cond) { assert(cond->dummy_node.next == &cond->dummy_node && "destroying condition variable with active waiters"); - return hymutex_destroy(&cond->queue_mutex); + return port_mutex_destroy(&cond->queue_mutex); } //@} diff --git a/vm/thread/src/win/os_mutex.c b/vm/thread/src/win/os_mutex.c index e2b9f2d..a1b810a 100644 --- a/vm/thread/src/win/os_mutex.c +++ b/vm/thread/src/win/os_mutex.c @@ -42,7 +42,7 @@ * APR_THREAD_MUTEX_UNNESTED disable nested locks (non-recursive). * */ -IDATA VMCALL hymutex_create (hymutex_t *mutex, UDATA flags) { +IDATA VMCALL hymutex_create (osmutex_t *mutex, UDATA flags) { int r = 0; if (flags & APR_THREAD_MUTEX_UNNESTED) { assert(!"not implemented"); @@ -59,7 +59,7 @@ IDATA VMCALL hymutex_create (hymutex_t *mutex, UDATA flags) { * @param[in] mutex the mutex on which to acquire the lock. * @sa apr_thread_mutex_lock() */ -IDATA VMCALL hymutex_lock(hymutex_t *mutex) { +IDATA VMCALL hymutex_lock(osmutex_t *mutex) { EnterCriticalSection(mutex); return 0; } @@ -70,7 +70,7 @@ IDATA VMCALL hymutex_lock(hymutex_t *mutex) { * @param[in] mutex the mutex on which to attempt the lock acquiring. * @sa apr_thread_mutex_trylock() */ -IDATA VMCALL hymutex_trylock (hymutex_t *mutex) { +IDATA VMCALL hymutex_trylock (osmutex_t *mutex) { int r; r = TryEnterCriticalSection(mutex); // Return code is non-zero on success @@ -84,7 +84,7 @@ IDATA VMCALL hymutex_trylock (hymutex_t *mutex) { * @param[in] mutex the mutex from which to release the lock. * @sa apr_thread_mutex_unlock() */ -IDATA VMCALL hymutex_unlock (hymutex_t *mutex) { +IDATA VMCALL hymutex_unlock (osmutex_t *mutex) { LeaveCriticalSection(mutex); return 0; } @@ -95,7 +95,7 @@ IDATA VMCALL hymutex_unlock (hymutex_t *mutex) { * @param[in] mutex the mutex to destroy. * @sa apr_thread_mutex_destroy() */ -IDATA VMCALL hymutex_destroy (hymutex_t *mutex) { +IDATA VMCALL hymutex_destroy (osmutex_t *mutex) { DeleteCriticalSection(mutex); return 0; } diff --git a/vm/vmcore/include/crash_dump.h b/vm/vmcore/include/crash_dump.h new file mode 100644 index 0000000..6a3822a --- /dev/null +++ b/vm/vmcore/include/crash_dump.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + + +#ifndef __CRASH_DUMP_H__ +#define __CRASH_DUMP_H__ + +#include "port_modules.h" + + +/* platform-dependent functions */ +void cd_parse_module_info(native_module_t* module, void* ip); + +/* general functions to call from platform-dependent code */ +const char* cd_get_module_type(const char* short_name); + + +#endif //!__CRASH_DUMP_H__ diff --git a/vm/vmcore/include/exceptions.h b/vm/vmcore/include/exceptions.h index 766e860..5b5da6c 100644 --- a/vm/vmcore/include/exceptions.h +++ b/vm/vmcore/include/exceptions.h @@ -276,8 +276,6 @@ void init_stack_info(); void* get_exception_catch_stack_addr(void* curr_ip); VMEXPORT size_t get_available_stack_size(); VMEXPORT bool check_available_stack_size(size_t required_size); -VMEXPORT size_t get_default_stack_size(); -VMEXPORT size_t get_restore_stack_size(); bool check_stack_size_enough_for_exception_catch(void* sp); #endif // _EXCEPTIONS_H_ diff --git a/vm/vmcore/include/finalizer_thread.h b/vm/vmcore/include/finalizer_thread.h index adb5dc0..4fda670 100644 --- a/vm/vmcore/include/finalizer_thread.h +++ b/vm/vmcore/include/finalizer_thread.h @@ -49,11 +49,11 @@ typedef struct Fin_Thread_Info { /* Using pair of cond and mutex rather than sem is because the waiting thread num is not constant */ hycond_t end_cond; // finalization end condition variable - hymutex_t end_mutex; // finalization end mutex + osmutex_t end_mutex; // finalization end mutex /* Using pair of cond and mutex rather than sem is because the waiting thread num is not constant */ hycond_t mutator_block_cond; // mutator block condition variable for heavy finalizable obj load - hymutex_t mutator_block_mutex; // mutator block mutex for heavy finalizable obj load + osmutex_t mutator_block_mutex; // mutator block mutex for heavy finalizable obj load vm_thread_t *thread_ids; volatile unsigned int thread_num; diff --git a/vm/vmcore/include/init.h b/vm/vmcore/include/init.h index 45a38ed..78850c4 100644 --- a/vm/vmcore/include/init.h +++ b/vm/vmcore/include/init.h @@ -32,8 +32,8 @@ jint vm_init2(JNIEnv * jni_env); */ void exec_native_shutdown_sequence(); jint vm_destroy(JavaVM_Internal * java_vm, jthread java_thread); -void vm_interrupt_handler(int); -void vm_dump_handler(int); +void vm_interrupt_handler(); +void vm_dump_handler(); void initialize_vm_cmd_state(Global_Env *p_env, JavaVMInitArgs* arguments); void set_log_levels_from_cmd(JavaVMInitArgs* vm_arguments); diff --git a/vm/vmcore/include/jvmti_break_intf.h b/vm/vmcore/include/jvmti_break_intf.h index 66a672c..b180639 100644 --- a/vm/vmcore/include/jvmti_break_intf.h +++ b/vm/vmcore/include/jvmti_break_intf.h @@ -30,15 +30,6 @@ #include "lock_manager.h" #include "environment.h" -#define INSTRUMENTATION_BYTE_HLT 0xf4 // HLT instruction -#define INSTRUMENTATION_BYTE_CLI 0xfa // CLI instruction -#define INSTRUMENTATION_BYTE_INT3 0xcc // INT 3 instruction - -#ifdef PLATFORM_NT -#define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_CLI -#else -#define INSTRUMENTATION_BYTE INSTRUMENTATION_BYTE_INT3 -#endif // Callbacks are called for interfaces according to its priority typedef enum { diff --git a/vm/vmcore/include/jvmti_direct.h b/vm/vmcore/include/jvmti_direct.h index 0bb630c..a3bd2ef 100644 --- a/vm/vmcore/include/jvmti_direct.h +++ b/vm/vmcore/include/jvmti_direct.h @@ -54,7 +54,7 @@ struct TIEnv const ti_interface *functions; /// Lock used to protect TIEnv instance - hymutex_t environment_data_lock; + osmutex_t environment_data_lock; JavaVM_Internal *vm; Agent *agent; diff --git a/vm/vmcore/include/lock_manager.h b/vm/vmcore/include/lock_manager.h index ecd582e..f55c9b1 100644 --- a/vm/vmcore/include/lock_manager.h +++ b/vm/vmcore/include/lock_manager.h @@ -50,7 +50,7 @@ public: bool _lock_enum_or_null (bool return_null_on_fail); private: - hymutex_t lock; + osmutex_t lock; }; diff --git a/vm/vmcore/include/native_stack.h b/vm/vmcore/include/native_stack.h index 1ef3e88..f28a3d1 100644 --- a/vm/vmcore/include/native_stack.h +++ b/vm/vmcore/include/native_stack.h @@ -22,9 +22,10 @@ #ifndef _NATIVE_STACK_H_ #define _NATIVE_STACK_H_ +#include "open/platform_types.h" +#include "port_unwind.h" #include "jni.h" #include "stack_iterator.h" -#include "native_modules.h" #include "vm_threads.h" #ifdef __cplusplus @@ -38,33 +39,13 @@ typedef struct { void* stack; } native_frame_t; -typedef struct WalkContext { - native_module_t* modules; - bool clean_modules; - native_segment_t stack; -} WalkContext; - // If frame_array is NULL, only returns real frame count -int walk_native_stack_registers(WalkContext* context, Registers* pregs, +int walk_native_stack_registers(UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array); -bool native_init_walk_context(WalkContext* context, native_module_t* modules, Registers* regs); -void native_clean_walk_context(WalkContext* context); - -////////////////////////////////////////////////////////////////////////////// -// Interchange between platform-dependent and general functions - -bool native_unwind_stack_frame(WalkContext* context, Registers* regs); -void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs); -bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg); -bool native_is_frame_exists(WalkContext* context, Registers* regs); -bool native_unwind_special(WalkContext* context, Registers* regs); -bool native_is_in_code(WalkContext* context, void* ip); -bool native_is_in_stack(WalkContext* context, void* sp); bool native_is_ip_stub(void* ip); char* native_get_stub_name(void* ip, char* buf, size_t buflen); -void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth); #ifdef __cplusplus diff --git a/vm/vmcore/include/ncai_internal.h b/vm/vmcore/include/ncai_internal.h index 30dea0c..abd1719 100644 --- a/vm/vmcore/include/ncai_internal.h +++ b/vm/vmcore/include/ncai_internal.h @@ -42,8 +42,6 @@ void* ncai_get_instruction_pointer(hythread_t thread); // These functions are differ for various operating systems bool ncai_get_generic_registers(hythread_t handle, Registers* regs); char* ncai_parse_module_name(char* filepath); -ncaiError ncai_read_memory(void* addr, size_t size, void* buf); -ncaiError ncai_write_memory(void* addr, size_t size, void* buf); struct VMBreakPoint; @@ -121,13 +119,6 @@ void ncai_report_method_exit(jmethodID method, jboolean exc_popped, jvalue ret_v void ncai_step_native_method_entry(Method* m); void ncai_step_native_method_exit(Method* m); - -// Platform-dependant Signal functions -size_t ncai_get_signal_count(); -bool ncai_is_signal_in_range(jint signal); -char* ncai_get_signal_name(jint signal); -size_t ncai_get_signal_name_size(jint signal); - // Allows to get modules without providing NCAI environment ncaiError ncai_get_all_loaded_modules(ncaiEnv *env, jint *count_ptr, ncaiModule **modules_ptr); diff --git a/vm/vmcore/include/ref_enqueue_thread.h b/vm/vmcore/include/ref_enqueue_thread.h index 1103ed2..c250060 100644 --- a/vm/vmcore/include/ref_enqueue_thread.h +++ b/vm/vmcore/include/ref_enqueue_thread.h @@ -38,7 +38,7 @@ typedef struct Ref_Enqueue_Thread_Info { /* Using pair of cond and mutex rather than sem is because the waiting thread num is not constant */ hycond_t end_cond; // ref enqueue end condition variable - hymutex_t end_mutex; // ref enqueue end mutex + osmutex_t end_mutex; // ref enqueue end mutex Boolean shutdown; volatile unsigned int thread_num; diff --git a/vm/vmcore/include/signals.h b/vm/vmcore/include/signals.h new file mode 100644 index 0000000..4c1b32e --- /dev/null +++ b/vm/vmcore/include/signals.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + + +#ifndef __SIGNALS_H__ +#define __SIGNALS_H__ + +#include +#include "open/platform_types.h" +#include "port_crash_handler.h" +#include "vm_threads.h" +#include "interpreter.h" +#include "exceptions_jit.h" +#include "method_lookup.h" + + +int vm_initialize_signals(); +int vm_shutdown_signals(); + +Boolean null_reference_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean stack_overflow_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean abort_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean ctrl_backslash_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean ctrl_break_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean ctrl_c_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean native_breakpoint_handler(port_sigtype signum, Registers* regs, void* fault_addr); +Boolean arithmetic_handler(port_sigtype signum, Registers* regs, void* fault_addr); + + +inline bool is_in_ti_handler(vm_thread_t vmthread, void* ip) +{ + if (!vmthread) + return false; + + POINTER_SIZE_INT break_buf = + (POINTER_SIZE_INT)(vmthread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer); + + return ((POINTER_SIZE_INT)ip >= break_buf && + (POINTER_SIZE_INT)ip < break_buf + TM_JVMTI_MAX_BUFFER_SIZE); +} + +inline bool is_in_java(Registers* regs) +{ + return (vm_identify_eip(regs->get_ip()) == VM_TYPE_JAVA); +} + +inline void signal_throw_exception(Registers* regs, Class* exc_clss) +{ + vm_set_exception_registers(p_TLS_vmthread, *regs); + exn_athrow_regs(regs, exc_clss, is_in_java(regs), false); +} + +inline void signal_throw_java_exception(Registers* regs, Class* exc_clss) +{ + ASSERT_NO_INTERPRETER; + assert(is_in_java(regs)); + + vm_set_exception_registers(p_TLS_vmthread, *regs); + exn_athrow_regs(regs, exc_clss, true, false); +} + + +#endif //!__SIGNALS_H__ diff --git a/vm/vmcore/src/class_support/C_Interface.cpp b/vm/vmcore/src/class_support/C_Interface.cpp index 56ad5d2..afc6329 100644 --- a/vm/vmcore/src/class_support/C_Interface.cpp +++ b/vm/vmcore/src/class_support/C_Interface.cpp @@ -31,6 +31,7 @@ #include "properties.h" #include "open/hythread_ext.h" +#include "port_mutex.h" #include "thread_manager.h" #include "cci.h" @@ -2417,25 +2418,25 @@ unsigned vm_vector_size(Class_Handle vector_class, int length) return vector_class->calculate_array_size(length); } // vm_vector_size -static hymutex_t vm_gc_lock; +static osmutex_t vm_gc_lock; void vm_gc_lock_init() { - IDATA UNUSED status = hymutex_create(&vm_gc_lock, TM_MUTEX_NESTED); + IDATA UNUSED status = port_mutex_create(&vm_gc_lock, APR_THREAD_MUTEX_NESTED); assert(status == TM_ERROR_NONE); } // vm_gc_lock_init void vm_gc_lock_enum() { int disable_count = hythread_reset_suspend_disable(); - IDATA UNUSED status = hymutex_lock(&vm_gc_lock); + IDATA UNUSED status = port_mutex_lock(&vm_gc_lock); assert(status == TM_ERROR_NONE); hythread_set_suspend_disable(disable_count); } // vm_gc_lock_enum void vm_gc_unlock_enum() { - IDATA UNUSED status = hymutex_unlock(&vm_gc_lock); + IDATA UNUSED status = port_mutex_unlock(&vm_gc_lock); assert(status == TM_ERROR_NONE); } // vm_gc_unlock_enum diff --git a/vm/vmcore/src/class_support/Verifier_stub.cpp b/vm/vmcore/src/class_support/Verifier_stub.cpp index f266362..c6d7eab 100644 --- a/vm/vmcore/src/class_support/Verifier_stub.cpp +++ b/vm/vmcore/src/class_support/Verifier_stub.cpp @@ -57,7 +57,7 @@ bool Class::verify(const Global_Env * env) /** * Verify class */ - if (is_enabled == TRUE && !is_interface() + if (is_enabled == 1 && !is_interface() && (is_bootstrap == FALSE || is_forced == TRUE)) { char *error; vf_Result result = diff --git a/vm/vmcore/src/init/finalizer_thread.cpp b/vm/vmcore/src/init/finalizer_thread.cpp index 942192c..446c12e 100644 --- a/vm/vmcore/src/init/finalizer_thread.cpp +++ b/vm/vmcore/src/init/finalizer_thread.cpp @@ -19,6 +19,7 @@ * @author Li-Gang Wang, 2006/11/15 */ +#include "port_mutex.h" #include "finalizer_thread.h" #include "ref_enqueue_thread.h" #include "finalize.h" @@ -95,12 +96,12 @@ void finalizer_threads_init(JavaVM *java_vm, JNIEnv *jni_env) status = hycond_create(&fin_thread_info->end_cond); assert(status == TM_ERROR_NONE); - status = hymutex_create(&fin_thread_info->end_mutex, TM_MUTEX_DEFAULT); + status = port_mutex_create(&fin_thread_info->end_mutex, APR_THREAD_MUTEX_DEFAULT); assert(status == TM_ERROR_NONE); status = hycond_create(&fin_thread_info->mutator_block_cond); assert(status == TM_ERROR_NONE); - status = hymutex_create(&fin_thread_info->mutator_block_mutex, TM_MUTEX_DEFAULT); + status = port_mutex_create(&fin_thread_info->mutator_block_mutex, APR_THREAD_MUTEX_DEFAULT); assert(status == TM_ERROR_NONE); fin_thread_info->thread_ids = @@ -137,14 +138,14 @@ void finalizer_shutdown(Boolean start_finalization_on_exit) void wait_native_fin_threads_detached(void) { - hymutex_lock(&fin_thread_info->end_mutex); + port_mutex_lock(&fin_thread_info->end_mutex); while(fin_thread_info->thread_num){ atomic_inc32(&fin_thread_info->end_waiting_num); IDATA status = hycond_wait_timed(&fin_thread_info->end_cond, &fin_thread_info->end_mutex, (I_64)1000, 0); atomic_dec32(&fin_thread_info->end_waiting_num); if(status != TM_ERROR_NONE) break; } - hymutex_unlock(&fin_thread_info->end_mutex); + port_mutex_unlock(&fin_thread_info->end_mutex); } /* Restrict waiting time; Unit: msec */ @@ -157,7 +158,7 @@ static unsigned int restrict_wait_time(unsigned int wait_time, unsigned int max_ static void wait_finalization_end(Boolean must_wait) { - hymutex_lock(&fin_thread_info->end_mutex); + port_mutex_lock(&fin_thread_info->end_mutex); unsigned int fin_obj_num = vm_get_finalizable_objects_quantity(); while(fin_thread_info->working_thread_num || fin_obj_num){ unsigned int wait_time = restrict_wait_time((fin_obj_num + 100)<<1, FIN_MAX_WAIT_TIME << 7); @@ -173,7 +174,7 @@ static void wait_finalization_end(Boolean must_wait) } fin_obj_num = temp; } - hymutex_unlock(&fin_thread_info->end_mutex); + port_mutex_unlock(&fin_thread_info->end_mutex); } void activate_finalizer_threads(Boolean wait) @@ -268,13 +269,13 @@ void vm_heavy_finalizer_block_mutator(void) if(self_is_finalizer_thread()) return; - hymutex_lock(&fin_thread_info->mutator_block_mutex); + port_mutex_lock(&fin_thread_info->mutator_block_mutex); unsigned int fin_obj_num = vm_get_finalizable_objects_quantity(); fin_obj_num = fin_obj_num >> (MUTATOR_BLOCK_THRESHOLD_BITS + cpu_num_bits); unsigned int wait_time = restrict_wait_time(fin_obj_num, FIN_MAX_WAIT_TIME); if(fin_obj_num) IDATA status = hycond_wait_timed_raw(&fin_thread_info->mutator_block_cond, &fin_thread_info->mutator_block_mutex, wait_time, 0); - hymutex_unlock(&fin_thread_info->mutator_block_mutex); + port_mutex_unlock(&fin_thread_info->mutator_block_mutex); } void vm_heavy_finalizer_resume_mutator(void) diff --git a/vm/vmcore/src/init/ref_enqueue_thread.cpp b/vm/vmcore/src/init/ref_enqueue_thread.cpp index c074b34..6a36b74 100644 --- a/vm/vmcore/src/init/ref_enqueue_thread.cpp +++ b/vm/vmcore/src/init/ref_enqueue_thread.cpp @@ -20,6 +20,7 @@ */ #include +#include "port_mutex.h" #include "ref_enqueue_thread.h" #include "finalize.h" #include "vm_threads.h" @@ -57,7 +58,7 @@ void ref_enqueue_thread_init(JavaVM *java_vm, JNIEnv* jni_env) status = hycond_create(&ref_thread_info->end_cond); assert(status == TM_ERROR_NONE); - status = hymutex_create(&ref_thread_info->end_mutex, TM_MUTEX_DEFAULT); + status = port_mutex_create(&ref_thread_info->end_mutex, APR_THREAD_MUTEX_DEFAULT); assert(status == TM_ERROR_NONE); ref_thread_info->thread_num = REF_ENQUEUE_THREAD_NUM; @@ -89,19 +90,19 @@ static uint32 atomic_dec32(volatile apr_uint32_t *mem) void wait_native_ref_thread_detached(void) { - hymutex_lock(&ref_thread_info->end_mutex); + port_mutex_lock(&ref_thread_info->end_mutex); while(ref_thread_info->thread_num){ atomic_inc32(&ref_thread_info->end_waiting_num); IDATA status = hycond_wait_timed(&ref_thread_info->end_cond, &ref_thread_info->end_mutex, (I_64)1000, 0); atomic_dec32(&ref_thread_info->end_waiting_num); if(status != TM_ERROR_NONE) break; } - hymutex_unlock(&ref_thread_info->end_mutex); + port_mutex_unlock(&ref_thread_info->end_mutex); } static void wait_ref_enqueue_end(void) { - hymutex_lock(&ref_thread_info->end_mutex); + port_mutex_lock(&ref_thread_info->end_mutex); unsigned int ref_num = vm_get_references_quantity(); do { unsigned int wait_time = ref_num + 100; @@ -111,7 +112,7 @@ static void wait_ref_enqueue_end(void) if(status != TM_ERROR_NONE) break; ref_num = vm_get_references_quantity(); } while(ref_num); - hymutex_unlock(&ref_thread_info->end_mutex); + port_mutex_unlock(&ref_thread_info->end_mutex); } void activate_ref_enqueue_thread(Boolean wait) diff --git a/vm/vmcore/src/init/vm_init.cpp b/vm/vmcore/src/init/vm_init.cpp index a9babb1..ba9588c 100644 --- a/vm/vmcore/src/init/vm_init.cpp +++ b/vm/vmcore/src/init/vm_init.cpp @@ -49,6 +49,7 @@ #include "slot.h" #include "classpath_const.h" #include "finalize.h" +#include "signals.h" #ifdef PLATFORM_NT // 20040427 Used to turn on heap checking on every allocation @@ -780,11 +781,6 @@ int vm_init1(JavaVM_Internal * java_vm, JavaVMInitArgs * vm_arguments) { vm_env->pin_interned_strings = (bool)get_boolean_property("vm.pin_interned_strings", FALSE, VM_PROPERTIES); - if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) { - TRACE("disabling assertion dialogs"); - disable_assert_dialogs(); - } - initialize_verify_stack_enumeration(); /* END: Property processing. */ @@ -820,8 +816,8 @@ int vm_init1(JavaVM_Internal * java_vm, JavaVMInitArgs * vm_arguments) { status = natives_init(); if (status != JNI_OK) return status; - extern void initialize_signals(); - initialize_signals(); + if (vm_initialize_signals() != 0) + return JNI_ERR; status = vm_attach(java_vm, &jni_env); if (status != JNI_OK) return status; diff --git a/vm/vmcore/src/init/vm_properties.cpp b/vm/vmcore/src/init/vm_properties.cpp index b3257a0..5b69554 100644 --- a/vm/vmcore/src/init/vm_properties.cpp +++ b/vm/vmcore/src/init/vm_properties.cpp @@ -27,7 +27,7 @@ #include "properties.h" #include "vm_properties.h" #include "init.h" -#include "native_modules.h" +#include "port_modules.h" #if defined(FREEBSD) #include #endif diff --git a/vm/vmcore/src/init/vm_shutdown.cpp b/vm/vmcore/src/init/vm_shutdown.cpp index 6847e2c..847bd36 100644 --- a/vm/vmcore/src/init/vm_shutdown.cpp +++ b/vm/vmcore/src/init/vm_shutdown.cpp @@ -37,6 +37,7 @@ #include "thread_dump.h" #include "interpreter.h" #include "finalize.h" +#include "signals.h" #define LOG_DOMAIN "vm.core.shutdown" #include "cxxlog.h" @@ -286,8 +287,7 @@ jint vm_destroy(JavaVM_Internal * java_vm, jthread java_thread) return JNI_ERR; // Shutdown signals - extern void shutdown_signals(); - shutdown_signals(); + vm_shutdown_signals(); // Block thread creation. // TODO: investigate how to achieve that with ThreadManager @@ -379,7 +379,7 @@ static IDATA vm_dump_entry_point(void * data) { * Current process received an interruption signal (Ctrl+C pressed). * Shutdown all running VMs and terminate the process. */ -void vm_interrupt_handler(int UNREF x) { +void vm_interrupt_handler() { int nVMs; IDATA status = JNI_GetCreatedJavaVMs(NULL, 0, &nVMs); assert(nVMs <= 1); @@ -421,10 +421,10 @@ void vm_interrupt_handler(int UNREF x) { } /** - * Current process received an ??? signal (Ctrl+Break pressed). + * Current process received an SIGQUIT signal (Linux) or Ctrl+Break (Windows). * Prints java stack traces for each VM running in the current process. */ -void vm_dump_handler(int UNREF x) { +void vm_dump_handler() { int nVMs; jint status = JNI_GetCreatedJavaVMs(NULL, 0, &nVMs); assert(nVMs <= 1); diff --git a/vm/vmcore/src/jvmti/jvmti.cpp b/vm/vmcore/src/jvmti/jvmti.cpp index 65be587..a0f350f 100644 --- a/vm/vmcore/src/jvmti/jvmti.cpp +++ b/vm/vmcore/src/jvmti/jvmti.cpp @@ -39,6 +39,7 @@ #include "port_filepath.h" #include "port_dso.h" +#include "port_mutex.h" #include #include @@ -261,7 +262,7 @@ jint JNICALL create_jvmti_environment(JavaVM *vm_ext, void **env, jint version) memset(newenv, 0, sizeof(TIEnv)); - IDATA error_code1 = hymutex_create(&newenv->environment_data_lock, + IDATA error_code1 = port_mutex_create(&newenv->environment_data_lock, APR_THREAD_MUTEX_NESTED); if (error_code1 != APR_SUCCESS) { @@ -273,7 +274,7 @@ jint JNICALL create_jvmti_environment(JavaVM *vm_ext, void **env, jint version) error_code = newenv->allocate_extension_event_callbacks_table(); if (error_code != JVMTI_ERROR_NONE) { - hymutex_destroy(&newenv->environment_data_lock); + port_mutex_destroy(&newenv->environment_data_lock); _deallocate((unsigned char *)newenv); *env = NULL; return error_code; diff --git a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp index 240e8f9..284dce4 100644 --- a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp @@ -39,6 +39,7 @@ #include "jvmti_break_intf.h" #include "cci.h" #include "port_thread.h" +#include "port_crash_handler.h" #if (defined _IA32_) || (defined _EM64T_) @@ -609,7 +610,7 @@ VMBreakPoints::process_native_breakpoint(Registers* regs) VMBreakPoint* bp = find_breakpoint(addr); if (NULL == bp) { // breakpoint could be deleted by another thread - assert(*((unsigned char *)addr) != INSTRUMENTATION_BYTE); + assert(!port_is_breakpoint_set(addr)); unlock(); // Transfer execution back to the original register // context. In case the target location happens to be @@ -1300,11 +1301,7 @@ static bool set_native_breakpoint(VMBreakPoint* bp) assert(bp->disasm); // code instrumentation - if (ncai_read_memory(bp->addr, 1, &bp->saved_byte) != NCAI_ERROR_NONE) - return false; - - unsigned char b = (unsigned char)INSTRUMENTATION_BYTE; - if (ncai_write_memory(bp->addr, 1, &b) != NCAI_ERROR_NONE) + if (port_set_breakpoint(bp->addr, (unsigned char*)&bp->saved_byte) != 0) return false; } @@ -1332,7 +1329,7 @@ static bool clear_native_breakpoint(VMBreakPoint* bp) << (bp->method ? method_get_descriptor((Method*)bp->method) : "" ) << " :" << bp->location << " :" << bp->addr); - if (ncai_write_memory(bp->addr, 1, &bp->saved_byte) != NCAI_ERROR_NONE) + if (port_clear_breakpoint(bp->addr, bp->saved_byte) != 0) return false; } @@ -1346,13 +1343,6 @@ static bool clear_native_breakpoint(VMBreakPoint* bp) ////////////////////////////////////////////////////////////////////////////// -void __cdecl process_native_breakpoint_event(Registers* regs) -{ - DebugUtilsTI *ti = VM_Global_State::loader_env->TI; - ti->vm_brpt->process_native_breakpoint(regs); -} - - bool jvmti_jit_breakpoint_handler(Registers *regs) { NativeCodePtr native_location = (NativeCodePtr)regs->get_ip(); @@ -1398,9 +1388,7 @@ bool jvmti_jit_breakpoint_handler(Registers *regs) } #endif - NativeCodePtr callback = (NativeCodePtr)process_native_breakpoint_event; - port_set_longjump_regs(callback, regs, 1, regs); - + ti->vm_brpt->process_native_breakpoint(regs); return true; } diff --git a/vm/vmcore/src/jvmti/jvmti_capability.cpp b/vm/vmcore/src/jvmti/jvmti_capability.cpp index 63423cb..253a334 100644 --- a/vm/vmcore/src/jvmti/jvmti_capability.cpp +++ b/vm/vmcore/src/jvmti/jvmti_capability.cpp @@ -22,6 +22,7 @@ * JVMTI capability API */ +#include "port_mutex.h" #include "jvmti_direct.h" #include "jvmti_utils.h" #include "jvmti_tags.h" @@ -446,13 +447,13 @@ jvmtiRelinquishCapabilities(jvmtiEnv* env, if (removed_caps.can_tag_objects) { // clear tags on relinquishing can_tag_objects capability ti_env = reinterpret_cast(env); - hymutex_lock(&ti_env->environment_data_lock); + port_mutex_lock(&ti_env->environment_data_lock); if (ti_env->tags) { ti_env->tags->clear(); delete ti_env->tags; ti_env->tags = NULL; } - hymutex_unlock(&ti_env->environment_data_lock); + port_mutex_unlock(&ti_env->environment_data_lock); ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_TAG_OBJECTS); } diff --git a/vm/vmcore/src/jvmti/jvmti_event.cpp b/vm/vmcore/src/jvmti/jvmti_event.cpp index 36820a5..f03d635 100644 --- a/vm/vmcore/src/jvmti/jvmti_event.cpp +++ b/vm/vmcore/src/jvmti/jvmti_event.cpp @@ -24,6 +24,7 @@ #define LOG_DOMAIN "jvmti" #include "cxxlog.h" +#include "port_mutex.h" #include "open/gc.h" #include "jvmti_direct.h" @@ -87,14 +88,14 @@ jvmtiError add_event_to_thread(jvmtiEnv *env, jvmtiEvent event_type, jthread eve TIEventThread *et = p_env->event_threads[event_type - JVMTI_MIN_EVENT_TYPE_VAL]; // protect event_threads collection - hymutex_lock(&(p_env->environment_data_lock)); + port_mutex_lock(&(p_env->environment_data_lock)); // Find out if this environment is already registered on this thread on this event type while (NULL != et) { if (et->thread == p_thread) { - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); return JVMTI_ERROR_NONE; } et = et->next; @@ -104,7 +105,7 @@ jvmtiError add_event_to_thread(jvmtiEnv *env, jvmtiEvent event_type, jthread eve jvmtiError errorCode = _allocate(sizeof(TIEventThread), (unsigned char **)&newet); if (JVMTI_ERROR_NONE != errorCode) { - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); return errorCode; } newet->thread = p_thread; @@ -116,7 +117,7 @@ jvmtiError add_event_to_thread(jvmtiEnv *env, jvmtiEvent event_type, jthread eve p_env->event_threads[event_type - JVMTI_MIN_EVENT_TYPE_VAL] = newet; // free environment lock - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); return JVMTI_ERROR_NONE; } @@ -130,14 +131,14 @@ void remove_event_from_thread(jvmtiEnv *env, jvmtiEvent event_type, jthread even return; // protect event_threads collection - hymutex_lock(&(p_env->environment_data_lock)); + port_mutex_lock(&(p_env->environment_data_lock)); if (et->thread == p_thread) { VM_Global_State::loader_env->TI->removeEventSubscriber(event_type); p_env->event_threads[event_type - JVMTI_MIN_EVENT_TYPE_VAL] = et->next; _deallocate((unsigned char *)et); - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); return; } @@ -150,36 +151,36 @@ void remove_event_from_thread(jvmtiEnv *env, jvmtiEvent event_type, jthread even TIEventThread *oldet = et->next; et->next = oldet->next; _deallocate((unsigned char *)oldet); - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); return; } et = et->next; } // release protection - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); } void add_event_to_global(jvmtiEnv *env, jvmtiEvent event_type) { TIEnv *p_env = (TIEnv *)env; - hymutex_lock(&(p_env->environment_data_lock)); + port_mutex_lock(&(p_env->environment_data_lock)); if(!p_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL]) { VM_Global_State::loader_env->TI->addEventSubscriber(event_type); } p_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL] = true; - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); } void remove_event_from_global(jvmtiEnv *env, jvmtiEvent event_type) { TIEnv *p_env = (TIEnv *)env; - hymutex_lock(&(p_env->environment_data_lock)); + port_mutex_lock(&(p_env->environment_data_lock)); if(p_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL]) { VM_Global_State::loader_env->TI->removeEventSubscriber(event_type); } p_env->global_events[event_type - JVMTI_MIN_EVENT_TYPE_VAL] = false; - hymutex_unlock(&(p_env->environment_data_lock)); + port_mutex_unlock(&(p_env->environment_data_lock)); } // disable all events except VM_DEATH @@ -2363,17 +2364,17 @@ jvmti_event_thread_function(void *args) assert(hythread_is_suspend_enabled()); // create wait loop environment - hymutex_t event_mutex; - UNREF IDATA stat = hymutex_create(&event_mutex, TM_MUTEX_NESTED); + osmutex_t event_mutex; + UNREF IDATA stat = port_mutex_create(&event_mutex, APR_THREAD_MUTEX_NESTED); assert(stat == TM_ERROR_NONE); stat = hycond_create(&ti->event_cond); assert(stat == TM_ERROR_NONE); // event thread loop while(true) { - hymutex_lock(&event_mutex); + port_mutex_lock(&event_mutex); hycond_wait(&ti->event_cond, &event_mutex); - hymutex_unlock(&event_mutex); + port_mutex_unlock(&event_mutex); if(!ti->event_thread) { // event thread is NULL, @@ -2386,7 +2387,7 @@ jvmti_event_thread_function(void *args) } // release wait loop environment - stat = hymutex_destroy(&event_mutex); + stat = port_mutex_destroy(&event_mutex); assert(stat == TM_ERROR_NONE); stat = hycond_destroy(&ti->event_cond); assert(stat == TM_ERROR_NONE); diff --git a/vm/vmcore/src/jvmti/jvmti_heap.cpp b/vm/vmcore/src/jvmti/jvmti_heap.cpp index f4cb3a3..6a46c41 100644 --- a/vm/vmcore/src/jvmti/jvmti_heap.cpp +++ b/vm/vmcore/src/jvmti/jvmti_heap.cpp @@ -23,6 +23,7 @@ */ #include "cxxlog.h" +#include "port_mutex.h" #include "jvmti_direct.h" #include "jvmti_utils.h" @@ -124,11 +125,11 @@ jvmtiSetTag(jvmtiEnv* env, return JVMTI_ERROR_INVALID_OBJECT; if (ti_env->tags == NULL) { - hymutex_lock(&ti_env->environment_data_lock); + port_mutex_lock(&ti_env->environment_data_lock); if (ti_env->tags == NULL) { ti_env->tags = new TITags; } - hymutex_unlock(&ti_env->environment_data_lock); + port_mutex_unlock(&ti_env->environment_data_lock); } if (ti_env->tags == NULL) { diff --git a/vm/vmcore/src/jvmti/jvmti_step.cpp b/vm/vmcore/src/jvmti/jvmti_step.cpp index 9d334c8..1c73f3b 100644 --- a/vm/vmcore/src/jvmti/jvmti_step.cpp +++ b/vm/vmcore/src/jvmti/jvmti_step.cpp @@ -19,6 +19,7 @@ * @version $Revision: $ */ +#include "port_crash_handler.h" #include "jvmti.h" #include "Class.h" #include "cxxlog.h" @@ -105,8 +106,7 @@ NativeCodePtr static get_ip_for_invoke_call_ip(VM_thread* thread, // Another thread could have instrumented this location for // prediction of invokevirtual or invokeinterface, so it is // necessary to check that location may be instrumented - uint8 b = *((uint8 *)ip); - if (b == INSTRUMENTATION_BYTE) + if (port_is_breakpoint_set(ip)) { bp = vm_brpt->find_breakpoint(ip); assert(bp); diff --git a/vm/vmcore/src/ncai/ncai_memory.cpp b/vm/vmcore/src/ncai/ncai_memory.cpp index 3b2592f..e141130 100644 --- a/vm/vmcore/src/ncai/ncai_memory.cpp +++ b/vm/vmcore/src/ncai/ncai_memory.cpp @@ -4,6 +4,7 @@ */ #define LOG_DOMAIN "ncai.memory" #include "cxxlog.h" +#include "port_memaccess.h" #include "jvmti_break_intf.h" #include "environment.h" #include "jvmti_internal.h" @@ -36,10 +37,10 @@ ncaiError JNICALL ncaiReadMemory(ncaiEnv* env, if (!env) return NCAI_ERROR_INVALID_ENVIRONMENT; - ncaiError err = ncai_read_memory(addr, size, buf); + int err = port_read_memory(addr, size, buf); - if (err != NCAI_ERROR_NONE) - return err; + if (err != 0) + return NCAI_ERROR_ACCESS_DENIED; // Restore bytes changed by JVMTI/NCAI breakpoints VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; @@ -86,7 +87,12 @@ ncaiError JNICALL ncaiWriteMemory(ncaiEnv* env, // Simple case: there are no breakpoints in specified address range if (rewrite_count == 0) - return ncai_write_memory(addr, size, buf); + { + if (port_write_memory(addr, size, buf) == 0) + return NCAI_ERROR_NONE; + else + return NCAI_ERROR_ACCESS_DENIED; + } // Allocate array for address sorting RewriteArray rwa; @@ -114,7 +120,7 @@ ncaiError JNICALL ncaiWriteMemory(ncaiEnv* env, assert(cur_bla); jbyte* cbuf = (jbyte*)buf; jbyte* cur_addr = (jbyte*)addr; - ncaiError err = NCAI_ERROR_NONE; + int err = 0; while (remain) { @@ -123,9 +129,9 @@ ncaiError JNICALL ncaiWriteMemory(ncaiEnv* env, size_t offset = (size_t)cur_addr - (size_t)addr; size_t chunk_size = cur_bla ? ((jbyte*)cur_bla->bp->addr - cur_addr) : (end_addr - cur_addr); - err = ncai_write_memory(cur_addr, chunk_size, cbuf + offset); + err = port_write_memory(cur_addr, chunk_size, cbuf + offset); - if (err != NCAI_ERROR_NONE) + if (err != 0) break; cur_addr += chunk_size; @@ -145,7 +151,7 @@ ncaiError JNICALL ncaiWriteMemory(ncaiEnv* env, } STD_FREE(rwa.array); - return err; + return (err == 0) ? NCAI_ERROR_NONE : NCAI_ERROR_ACCESS_DENIED; } // Adding sorted item into rewrite list diff --git a/vm/vmcore/src/ncai/ncai_modules.cpp b/vm/vmcore/src/ncai/ncai_modules.cpp index 990c43e..a4ac84e 100644 --- a/vm/vmcore/src/ncai/ncai_modules.cpp +++ b/vm/vmcore/src/ncai/ncai_modules.cpp @@ -11,7 +11,7 @@ #include "cxxlog.h" #include "environment.h" #include "natives_support.h" -#include "native_modules.h" +#include "port_modules.h" #include "open/hythread_ext.h" #include "ncai_utils.h" #include "ncai_direct.h" @@ -459,7 +459,7 @@ char* short_name(const char* name, char* buf); static bool compare_modules_by_short_name(ncaiModule module, const char* sh_name) { - char buf[_MAX_PATH + 1]; + char buf[PORT_PATH_MAX + 1]; if (short_name(module->info->filename, buf) == NULL) return false; // Error case @@ -471,7 +471,7 @@ compare_modules_by_short_name(ncaiModule module, const char* sh_name) // Must be called under modules lock static ncaiModule find_module_by_name(ncaiModule modules, const char* name) { - char name_buf[_MAX_PATH + 1]; + char name_buf[PORT_PATH_MAX + 1]; if (short_name(name, name_buf) == NULL) return NULL; diff --git a/vm/vmcore/src/ncai/ncai_signals.cpp b/vm/vmcore/src/ncai/ncai_signals.cpp index c55f336..69aaf96 100644 --- a/vm/vmcore/src/ncai/ncai_signals.cpp +++ b/vm/vmcore/src/ncai/ncai_signals.cpp @@ -8,12 +8,29 @@ #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; + 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 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) { @@ -131,3 +148,88 @@ void ncai_process_signal_event(NativeCodePtr addr, } } } + + + +#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 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()); +} diff --git a/vm/vmcore/src/ncai/ncai_stack.cpp b/vm/vmcore/src/ncai/ncai_stack.cpp index 1e932f7..bfefb6e 100644 --- a/vm/vmcore/src/ncai/ncai_stack.cpp +++ b/vm/vmcore/src/ncai/ncai_stack.cpp @@ -153,14 +153,14 @@ static ncaiError walk_native_stack(hythread_t thread, vm_thread = jthread_get_vm_thread(thread); } - WalkContext context; - if (!native_init_walk_context(&context, NULL, ®s)) + UnwindContext context; + if (!port_init_unwind_context(&context, NULL, ®s)) return NCAI_ERROR_INTERNAL; *pcount = walk_native_stack_registers(&context, ®s, vm_thread, max_depth, frame_array); - native_clean_walk_context(&context); + port_clean_unwind_context(&context); return NCAI_ERROR_NONE; } diff --git a/vm/vmcore/src/ncai/utils/ncai_signals_linux.cpp b/vm/vmcore/src/ncai/utils/ncai_signals_linux.cpp deleted file mode 100644 index 550d03d..0000000 --- a/vm/vmcore/src/ncai/utils/ncai_signals_linux.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @author Ilya Berezhniuk - * @version $Revision$ - */ - -#include "ncai_utils.h" -#include "ncai_direct.h" -#include "ncai_internal.h" - -#define STR_AND_SIZE(_x_) _x_, (strlen(_x_) + 1) - -struct st_signal_info -{ - jint signal; - char* name; - size_t name_size; -}; - -static st_signal_info sig_table[] = { - {SIGHUP, STR_AND_SIZE("SIGHUP")}, - {SIGINT, STR_AND_SIZE("SIGINT")}, - {SIGQUIT, STR_AND_SIZE("SIGQUIT")}, - {SIGILL, STR_AND_SIZE("SIGILL")}, - {SIGTRAP, STR_AND_SIZE("SIGTRAP")}, - {SIGABRT, STR_AND_SIZE("SIGABRT")}, - {SIGFPE, STR_AND_SIZE("SIGFPE")}, - {SIGKILL, STR_AND_SIZE("SIGKILL")}, - {SIGSEGV, STR_AND_SIZE("SIGSEGV")}, - {SIGPIPE, STR_AND_SIZE("SIGPIPE")}, - {SIGALRM, STR_AND_SIZE("SIGALRM")}, - {SIGTERM, STR_AND_SIZE("SIGTERM")}, - {SIGUSR1, STR_AND_SIZE("SIGUSR1")}, - {SIGUSR2, STR_AND_SIZE("SIGUSR2")}, - {SIGCHLD, STR_AND_SIZE("SIGCHLD")}, - {SIGCONT, STR_AND_SIZE("SIGCONT")}, - {SIGSTOP, STR_AND_SIZE("SIGSTOP")}, - {SIGTSTP, STR_AND_SIZE("SIGTSTP")}, - {SIGTTIN, STR_AND_SIZE("SIGTTIN")}, - {SIGTTOU, STR_AND_SIZE("SIGTTOU")}, -}; - -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; -} - -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; -} - -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; -} - -char* ncai_get_signal_name(jint signal) -{ - st_signal_info* psig = find_signal(signal); - return psig ? psig->name : NULL; -} - -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()); -} diff --git a/vm/vmcore/src/ncai/utils/ncai_signals_win.cpp b/vm/vmcore/src/ncai/utils/ncai_signals_win.cpp deleted file mode 100644 index 3c03727..0000000 --- a/vm/vmcore/src/ncai/utils/ncai_signals_win.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @author Ilya Berezhniuk - * @version $Revision$ - */ - -#include "ncai_utils.h" -#include "ncai_direct.h" -#include "ncai_internal.h" - -#define STR_AND_SIZE(_x_) _x_, (strlen(_x_) + 1) - -struct st_signal_info -{ - uint32 signal; - char* name; - size_t name_size; -}; - -static st_signal_info sig_table[] = { - {0x40010005, STR_AND_SIZE("DBG_CONTROL_C")}, - {0x40010008, STR_AND_SIZE("DBG_CONTROL_BREAK")}, - {0x80000002, STR_AND_SIZE("EXCEPTION_DATATYPE_MISALIGNMENT")}, - {0xC0000005, STR_AND_SIZE("EXCEPTION_ACCESS_VIOLATION")}, - {0xC0000006, STR_AND_SIZE("EXCEPTION_IN_PAGE_ERROR")}, - {0xC0000017, STR_AND_SIZE("STATUS_NO_MEMORY")}, - {0xC000001D, STR_AND_SIZE("EXCEPTION_ILLEGAL_INSTRUCTION")}, - {0xC0000025, STR_AND_SIZE("EXCEPTION_NONCONTINUABLE_EXCEPTION")}, - {0xC0000026, STR_AND_SIZE("EXCEPTION_INVALID_DISPOSITION")}, - {0xC000008C, STR_AND_SIZE("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")}, - {0xC000008D, STR_AND_SIZE("EXCEPTION_FLT_DENORMAL_OPERAND")}, - {0xC000008E, STR_AND_SIZE("EXCEPTION_FLT_DIVIDE_BY_ZERO")}, - {0xC000008F, STR_AND_SIZE("EXCEPTION_FLT_INEXACT_RESULT")}, - {0xC0000090, STR_AND_SIZE("EXCEPTION_FLT_INVALID_OPERATION")}, - {0xC0000091, STR_AND_SIZE("EXCEPTION_FLT_OVERFLOW")}, - {0xC0000092, STR_AND_SIZE("EXCEPTION_FLT_STACK_CHECK")}, - {0xC0000093, STR_AND_SIZE("EXCEPTION_FLT_UNDERFLOW")}, - {0xC0000094, STR_AND_SIZE("EXCEPTION_INT_DIVIDE_BY_ZERO")}, - {0xC0000095, STR_AND_SIZE("EXCEPTION_INT_OVERFLOW")}, - {0xC0000096, STR_AND_SIZE("EXCEPTION_PRIV_INSTRUCTION")}, - {0xC00000FD, STR_AND_SIZE("EXCEPTION_STACK_OVERFLOW")}, - {0xC0000135, STR_AND_SIZE("STATUS_DLL_NOT_FOUND")}, - {0xC0000138, STR_AND_SIZE("STATUS_ORDINAL_NOT_FOUND")}, - {0xC0000139, STR_AND_SIZE("STATUS_ENTRYPOINT_NOT_FOUND")}, - {0xC0000142, STR_AND_SIZE("STATUS_DLL_INIT_FAILED")}, - {0xC06D007E, STR_AND_SIZE("MODULE_NOT_FOUND")}, - {0xC06D007F, STR_AND_SIZE("PROCEDURE_NOT_FOUND")}, - {0xE06D7363, STR_AND_SIZE("CPP_EXCEPTION")}, -}; - -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 ((jint)sig_table[i].signal == sig) - return &sig_table[i]; - } - - return NULL; -} - -uint32 ncai_get_min_signal() -{ - return sig_table[0].signal; -} - -uint32 ncai_get_max_signal() -{ - return sig_table[ncai_get_signal_count() - 1].signal; -} - -char* ncai_get_signal_name(jint signal) -{ - st_signal_info* psig = find_signal(signal); - return psig ? psig->name : NULL; -} - -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 ((uint32)signal >= ncai_get_min_signal() || - (uint32)signal <= ncai_get_max_signal()); -} diff --git a/vm/vmcore/src/ncai/utils/ncai_step_ia32.cpp b/vm/vmcore/src/ncai/utils/ncai_step_ia32.cpp index a169cdb..2d5d49d 100644 --- a/vm/vmcore/src/ncai/utils/ncai_step_ia32.cpp +++ b/vm/vmcore/src/ncai/utils/ncai_step_ia32.cpp @@ -5,6 +5,7 @@ #define LOG_DOMAIN "ncai.step" #include "cxxlog.h" +#include "port_crash_handler.h" #include "jvmti_break_intf.h" #include "ncai_utils.h" @@ -301,10 +302,9 @@ static bool ncai_fill_jump_targets(void* cur, InstructionDisassembler* pdasm, static InstructionDisassembler* get_local_disasm(void* addr) { VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - uint8* bptr = (uint8*)addr; InstructionDisassembler* pdasm; - if (*bptr == INSTRUMENTATION_BYTE) + if (port_is_breakpoint_set(addr)) { // Address was instrumented by another thread or by breakpoint VMBreakPoint* bp = vm_brpt->find_breakpoint(addr); assert(bp && bp->disasm); diff --git a/vm/vmcore/src/stack/native_stack.cpp b/vm/vmcore/src/stack/native_stack.cpp index 25ee12e..9249d18 100644 --- a/vm/vmcore/src/stack/native_stack.cpp +++ b/vm/vmcore/src/stack/native_stack.cpp @@ -19,17 +19,19 @@ * @version $Revision: 1.1.2.1 $ */ -#include +//#include #include "lock_manager.h" #include "method_lookup.h" +#include "method_lookup.h" #include "m2n.h" -#include "stack_trace.h" +#include "compile.h" +//#include "stack_trace.h" #include "interpreter.h" #include "interpreter_exports.h" -#include "compile.h" -#include "jvmti_break_intf.h" +//#include "jvmti_break_intf.h" #include "environment.h" -#include "native_modules.h" +#include "port_modules.h" +#include "port_unwind.h" #include "native_stack.h" @@ -68,12 +70,6 @@ char* native_get_stub_name(void* ip, char* buf, size_t buflen) return buf; } -bool native_is_in_stack(WalkContext* context, void* sp) -{ - return (sp >= context->stack.base && - sp < (char*)context->stack.base + context->stack.size); -} - bool native_is_ip_stub(void* ip) { // Synchronizing access to dynamic code list @@ -82,6 +78,41 @@ bool native_is_ip_stub(void* ip) return (native_find_stub(ip) != NULL); } +static void native_fill_frame_info(Registers* UNREF regs, native_frame_t* UNREF frame, jint UNREF jdepth) +{ + frame->java_depth = jdepth; + + if (!regs) + return; + +#if defined(_IPF_) + // Nothing +#elif defined(_EM64T_) + frame->ip = (void*)regs->rip; + frame->frame = (void*)regs->rbp; + frame->stack = (void*)regs->rsp; +#else // IA-32 + frame->ip = (void*)regs->eip; + frame->frame = (void*)regs->ebp; + frame->stack = (void*)regs->esp; +#endif +} + +static void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) +{ +#if defined(_IPF_) + // Nothing +#elif defined(_EM64T_) + regs->rip = *jfc->p_rip; + regs->rbp = *jfc->p_rbp; + regs->rsp = jfc->rsp; +#else // IA-32 + regs->eip = *jfc->p_eip; + regs->ebp = *jfc->p_ebp; + regs->esp = jfc->esp; +#endif +} + /* Now the technique for calling C handler from a signal/exception context guarantees that all needed return addresses are present in stack, so @@ -98,65 +129,20 @@ static bool native_is_ip_in_breakpoint_handler(void* ip) ////////////////////////////////////////////////////////////////////////////// // -bool native_init_walk_context(WalkContext* context, native_module_t* modules, Registers* regs) -{ - if (!context) - return false; - - if (!modules) - { - int mod_count; - native_module_t* mod_list = NULL; - - if (!port_get_all_modules(&mod_list, &mod_count)) - return false; - - context->clean_modules = true; - context->modules = mod_list; - } - else - { - context->clean_modules = false; - context->modules = modules; - } - - if (!native_get_stack_range(context, regs, &context->stack)) - { - if (context->clean_modules) - port_clear_modules(&context->modules); - return false; - } - - return true; -} - -void native_clean_walk_context(WalkContext* context) -{ - if (!context) - return; - - if (context->modules && context->clean_modules) - { - port_clear_modules(&context->modules); - } - - context->modules = NULL; -} - static int walk_native_stack_jit( - WalkContext* context, + UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array); static int walk_native_stack_pure( - WalkContext* context, Registers* pregs, + UnwindContext* context, Registers* pregs, int max_depth, native_frame_t* frame_array); static int walk_native_stack_interpreter( - WalkContext* context, + UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array); -int walk_native_stack_registers(WalkContext* context, Registers* pregs, +int walk_native_stack_registers(UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array) { if (pthread == NULL) // Pure native thread @@ -172,7 +158,7 @@ int walk_native_stack_registers(WalkContext* context, Registers* pregs, static int walk_native_stack_jit( - WalkContext* context, + UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array) { @@ -302,20 +288,12 @@ static int walk_native_stack_jit( { Registers tmp_regs = regs; - if (native_is_frame_exists(context, &tmp_regs)) - { // Stack frame (x86) - if (!native_unwind_stack_frame(context, &tmp_regs)) - break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, &tmp_regs)) + if (!port_unwind_frame(context, &tmp_regs)) break; - } - +/* VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; vm_breaks->lock(); -/* + Now the technique for calling C handler from a signal/exception context guarantees that all needed return addresses are present in stack, so there is no need in special processing @@ -327,7 +305,7 @@ there is no need in special processing else*/ regs = tmp_regs; - vm_breaks->unlock(); +// vm_breaks->unlock(); } code_type = vm_identify_eip(regs.get_ip()); @@ -355,7 +333,7 @@ there is no need in special processing static int walk_native_stack_pure( - WalkContext* context, Registers* pregs, + UnwindContext* context, Registers* pregs, int max_depth, native_frame_t* frame_array) { // Register context for current frame @@ -377,19 +355,8 @@ static int walk_native_stack_pure( ++frame_count; - if (native_is_frame_exists(context, ®s)) - { // Stack frame (x86) - // Here must be special processing for breakpoint handler frames - // But it requires VM_thread structure attached to thread - // TODO: Investigate possibility - if (!native_unwind_stack_frame(context, ®s)) + if (port_unwind_frame(context, ®s)) break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, ®s)) - break; - } } return frame_count; @@ -397,7 +364,7 @@ static int walk_native_stack_pure( static int walk_native_stack_interpreter( - WalkContext* context, + UnwindContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array) { @@ -427,20 +394,12 @@ static int walk_native_stack_interpreter( void* prev_sp = regs.get_sp(); Registers tmp_regs = regs; - if (native_is_frame_exists(context, &tmp_regs)) - { // Stack frame (x86) - if (!native_unwind_stack_frame(context, &tmp_regs)) - break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, &tmp_regs)) + if (port_unwind_frame(context, &tmp_regs)) break; - } - +/* VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; vm_breaks->lock(); -/* + Now the technique for calling C handler from a signal/exception context guarantees that all needed return addresses are present in stack, so there is no need in special processing @@ -449,7 +408,7 @@ there is no need in special processing else*/ regs = tmp_regs; - vm_breaks->unlock(); +// vm_breaks->unlock(); bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, regs.get_sp()); diff --git a/vm/vmcore/src/thread/lock_manager.cpp b/vm/vmcore/src/thread/lock_manager.cpp index bd91ef6..c86cf42 100644 --- a/vm/vmcore/src/thread/lock_manager.cpp +++ b/vm/vmcore/src/thread/lock_manager.cpp @@ -20,37 +20,38 @@ */ +#include "port_mutex.h" #include "lock_manager.h" #include "vm_threads.h" #include "exceptions.h" Lock_Manager::Lock_Manager() { - UNREF IDATA stat = hymutex_create (&lock, TM_MUTEX_NESTED); + UNREF IDATA stat = port_mutex_create (&lock, APR_THREAD_MUTEX_NESTED); assert(stat==TM_ERROR_NONE); } Lock_Manager::~Lock_Manager() { - UNREF IDATA stat = hymutex_destroy (&lock); + UNREF IDATA stat = port_mutex_destroy (&lock); assert(stat==TM_ERROR_NONE); } void Lock_Manager::_lock() { - UNREF IDATA stat = hymutex_lock(&lock); + UNREF IDATA stat = port_mutex_lock(&lock); assert(stat==TM_ERROR_NONE); } bool Lock_Manager::_tryLock() { - IDATA stat = hymutex_trylock(&lock); + IDATA stat = port_mutex_trylock(&lock); return stat==TM_ERROR_NONE; } void Lock_Manager::_unlock() { - UNREF IDATA stat = hymutex_unlock(&lock); + UNREF IDATA stat = port_mutex_unlock(&lock); assert(stat==TM_ERROR_NONE); } @@ -93,6 +94,6 @@ void Lock_Manager::_unlock_enum_or_null() bool Lock_Manager::_lock_enum_or_null(bool UNREF return_null_on_fail) { - IDATA stat = hymutex_lock(&lock); + IDATA stat = port_mutex_lock(&lock); return stat==TM_ERROR_NONE; } diff --git a/vm/vmcore/src/thread/thread_generic.cpp b/vm/vmcore/src/thread/thread_generic.cpp index a96f2a8..4372e28 100644 --- a/vm/vmcore/src/thread/thread_generic.cpp +++ b/vm/vmcore/src/thread/thread_generic.cpp @@ -62,7 +62,6 @@ using namespace std; #include "m2n.h" #include "exceptions.h" #include "jit_intf.h" -#include "exception_filter.h" #include "vm_threads.h" #include "jni_utils.h" #include "object.h" diff --git a/vm/vmcore/src/thread/thread_manager.cpp b/vm/vmcore/src/thread/thread_manager.cpp index f459eb0..8750dbb 100644 --- a/vm/vmcore/src/thread/thread_manager.cpp +++ b/vm/vmcore/src/thread/thread_manager.cpp @@ -192,7 +192,7 @@ void vm_set_exception_registers(vm_thread_t vm_thread, Registers & regs) } // vm_set_exception_registers /** - * Gets IP from exception registers + * Gets IP from exception registers for current thread */ void *vm_get_ip_from_regs(vm_thread_t vm_thread) { diff --git a/vm/vmcore/src/thread/thread_ti_monitors.cpp b/vm/vmcore/src/thread/thread_ti_monitors.cpp index ab4b482..1252ef3 100644 --- a/vm/vmcore/src/thread/thread_ti_monitors.cpp +++ b/vm/vmcore/src/thread/thread_ti_monitors.cpp @@ -21,6 +21,7 @@ */ #include +#include "port_mutex.h" #include "vm_threads.h" typedef struct ResizableArrayEntry *array_entry_t; @@ -120,7 +121,7 @@ static void * array_get(array_t arr, UDATA index) } // array_get static array_t jvmti_monitor_table = 0; -static hymutex_t jvmti_monitor_table_lock; +static osmutex_t jvmti_monitor_table_lock; static IDATA jthread_init_jvmti_monitor_table() { @@ -133,7 +134,7 @@ static IDATA jthread_init_jvmti_monitor_table() hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } - status = hymutex_create(&jvmti_monitor_table_lock, TM_MUTEX_NESTED); + status = port_mutex_create(&jvmti_monitor_table_lock, APR_THREAD_MUTEX_NESTED); if (status != TM_ERROR_NONE) { hythread_global_unlock(); return status; @@ -171,17 +172,17 @@ IDATA VMCALL jthread_raw_monitor_create(jrawMonitorID * mon_ptr) } } - status = hymutex_lock(&jvmti_monitor_table_lock); + status = port_mutex_lock(&jvmti_monitor_table_lock); if (status != TM_ERROR_NONE) { return status; } *mon_ptr = (jrawMonitorID)array_add(jvmti_monitor_table, monitor); if (!(*mon_ptr)) { - hymutex_unlock(&jvmti_monitor_table_lock); + port_mutex_unlock(&jvmti_monitor_table_lock); return TM_ERROR_OUT_OF_MEMORY; } - status = hymutex_unlock(&jvmti_monitor_table_lock); + status = port_mutex_unlock(&jvmti_monitor_table_lock); return status; } // jthread_raw_monitor_create @@ -206,12 +207,12 @@ IDATA VMCALL jthread_raw_monitor_destroy(jrawMonitorID mon_ptr) } } - IDATA status = hymutex_lock(&jvmti_monitor_table_lock); + IDATA status = port_mutex_lock(&jvmti_monitor_table_lock); if (status != TM_ERROR_NONE) { return status; } array_delete(jvmti_monitor_table, (UDATA) mon_ptr); - status = hymutex_unlock(&jvmti_monitor_table_lock); + status = port_mutex_unlock(&jvmti_monitor_table_lock); return status; } // jthread_raw_monitor_destroy diff --git a/vm/vmcore/src/util/crash_dump.cpp b/vm/vmcore/src/util/crash_dump.cpp new file mode 100644 index 0000000..4d0e605 --- /dev/null +++ b/vm/vmcore/src/util/crash_dump.cpp @@ -0,0 +1,315 @@ +/* + * 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. + */ + +//#include + +#include "port_dso.h" +#include "port_modules.h" +#include "port_crash_handler.h" +#include "port_frame_info.h" +#include "jni.h" +#include "stack_iterator.h" +#include "environment.h" +#include "vm_threads.h" +#include "properties.h" +#include "exceptions.h" +#include "Class.h" +#include "class_member.h" +#include "open/jthread.h" +#include "natives_support.h" +#include "stack_trace.h" +#include "signals.h" +#include "crash_dump.h" + + +#ifdef PLATFORM_POSIX +#include +#define strcmp_case strcasecmp +#else /* Windows */ +#include +#define strcmp_case _stricmp +#endif + + +static void cd_init_crash_sequence(); +static void cd_cleanup_crash_sequence(); +static void cd_fill_java_method_info(Registers* regs, Method* m, port_stack_frame_info* jmi); +static void cd_print_module_info(Registers* regs); +static void cd_print_threads_info(); + + +static int unwind_compiled_frame(Registers *regs, port_stack_frame_info *sfi) +{ + // Suppose this callback is called by PORT for crash reasons only + cd_init_crash_sequence(); + + if (!sfi->iteration_state) + return (int)si_size(); + + // + return -1; +} + + +static void crash_action(port_sigtype UNREF signum, Registers* regs, void* UNREF fault_addr) +{ + if (!regs) // No regs info - do not print anything + return; + + // For the case when unwind callback was not called before + cd_init_crash_sequence(); + + // Print crashed modile info + cd_print_module_info(regs); + // Print threads info + cd_print_threads_info(); + + cd_cleanup_crash_sequence(); +} + + +static port_signal_handler_registration registrations[] = +{ + {PORT_SIGNAL_GPF, null_reference_handler}, + {PORT_SIGNAL_STACK_OVERFLOW, stack_overflow_handler}, + {PORT_SIGNAL_ABORT, abort_handler}, + {PORT_SIGNAL_QUIT, ctrl_backslash_handler}, + {PORT_SIGNAL_CTRL_BREAK, ctrl_break_handler}, + {PORT_SIGNAL_CTRL_C, ctrl_c_handler}, + {PORT_SIGNAL_BREAKPOINT, native_breakpoint_handler}, + {PORT_SIGNAL_ARITHMETIC, arithmetic_handler} +}; + +int vm_initialize_signals() +{ + Boolean result = port_init_crash_handler( + registrations, + sizeof(registrations)/sizeof(registrations[0]), + unwind_compiled_frame); + + if (!result) + return -1; + + result = port_crash_handler_add_action(crash_action); + + if (!result) + return -1; + + unsigned flags = port_crash_handler_get_capabilities(); + +#ifdef PLATFORM_POSIX + bool call_dbg = (VM_Global_State::loader_env == NULL) || + get_boolean_property("vm.crash_handler", FALSE, VM_PROPERTIES); +#else // WIN + bool call_dbg = (VM_Global_State::loader_env == NULL) || + get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES); +#endif + if (!call_dbg) + flags &= ~PORT_CRASH_CALL_DEBUGGER; + + port_crash_handler_set_flags(flags); + + return 0; +} + + +int vm_shutdown_signals() +{ + Boolean result = port_shutdown_crash_handler(); + if (!result) + return -1; + + return 0; +} + + + +// Crash sequence is single-threaded, it's provided by the PORT +static bool g_crash_initialized = false; +static int g_disable_count; +static bool g_unwindable; +static native_module_t* g_modules = NULL; + +static void cd_init_crash_sequence() +{ + if (g_crash_initialized) + return; + + VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread + + if (thread) + { + // Enable suspend to allow working with threads + g_disable_count = hythread_reset_suspend_disable(); + // Acquire global lock to print threads list +// hythread_global_lock(); + g_unwindable = set_unwindable(false); // To call Java code + } + + g_crash_initialized = true; +} + +static void cd_cleanup_crash_sequence() +{ + if (!g_crash_initialized) + return; + + VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread + + if (thread) + { + set_unwindable(g_unwindable); +// hythread_global_unlock(); + hythread_set_suspend_disable(g_disable_count); + } + + g_crash_initialized = false; +} + + +static void cd_fill_java_method_info(Registers* regs, Method* m, port_stack_frame_info* sfi) +{ + if (!m || !sfi) + return; + + sfi->method_class_name = m->get_class()->get_name()->bytes; + sfi->method_name = m->get_name()->bytes; + sfi->method_signature = m->get_descriptor()->bytes; + sfi->source_file_name = NULL; + sfi->source_line_number = -1; + + if (!regs) + return; + + bool is_ip_past = true; + int inl_depth = 0; + // extract is_ip_past and inl_depth from sfi->iteration_state + + const char* fname = NULL; + int line = -1; + + get_file_and_line(m, regs->get_ip(), + is_ip_past, inl_depth, &fname, &line); + + if (fname) + { + sfi->source_file_name = fname; + sfi->source_line_number = line; + } +} + + +const char* cd_get_module_type(const char* short_name) +{ + char name[256]; + + if (strlen(short_name) > 255) + return "Too long short name"; + + strcpy(name, short_name); + char* dot = strchr(name, '.'); + + // Strip suffix/extension + if (dot) + *dot = 0; + + // Strip prefix + char* nameptr = name; + + if (!memcmp(short_name, PORT_DSO_PREFIX, strlen(PORT_DSO_PREFIX))) + nameptr += strlen(PORT_DSO_PREFIX); + + char* vm_modules[] = {"java", "em", "encoder", "gc_gen", "gc_gen_uncomp", "gc_cc", + "harmonyvm", "hythr", "interpreter", "jitrino", "vmi"}; + + for (size_t i = 0; i < sizeof(vm_modules)/sizeof(vm_modules[0]); i++) + { + if (!strcmp_case(name, vm_modules[i])) + return "VM native code"; + } + + if (natives_is_library_loaded_slow(short_name)) + return "JNI native library"; + + return "Unknown/system native module"; +} + +static void cd_fill_modules() +{ + if (g_modules) + return; + + int count; + bool res = port_get_all_modules(&g_modules, &count); + assert(res && g_modules && count); +} + +static void cd_print_module_info(Registers* regs) +{ + cd_fill_modules(); + + native_module_t* module = port_find_module(g_modules, (void*)regs->get_ip()); + cd_parse_module_info(module, regs->get_ip()); +} + + +static void cd_print_threads_info() +{ + VM_thread* cur_thread = get_thread_ptr(); + + if (!cur_thread) + fprintf(stderr, "\nCurrent thread is not attached to VM, ID: %d\n", port_gettid()); + + fprintf(stderr, "\nVM attached threads:\n\n"); + + hythread_iterator_t it = hythread_iterator_create(NULL); + int count = (int)hythread_iterator_size(it); + + for (int i = 0; i < count; i++) + { + hythread_t thread = hythread_iterator_next(&it); + VM_thread* vm_thread = jthread_get_vm_thread(thread); + + if (!vm_thread) + continue; + + jthread java_thread = jthread_get_java_thread(thread); + JNIEnv* jni_env = vm_thread->jni_env; + + if (cur_thread && java_thread) + { + jclass cl = GetObjectClass(jni_env, java_thread); + jmethodID id = jni_env->GetMethodID(cl, "getName","()Ljava/lang/String;"); + jstring name = jni_env->CallObjectMethod(java_thread, id); + char* java_name = (char*)jni_env->GetStringUTFChars(name, NULL); + + fprintf(stderr, "%s[%p] '%s'\n", + (cur_thread && vm_thread == cur_thread) ? "--->" : " ", + thread->os_handle, java_name); + + jni_env->ReleaseStringUTFChars(name, java_name); + } + else + { + fprintf(stderr, "%s[%p]\n", + (cur_thread && vm_thread == cur_thread) ? "--->" : " ", + thread->os_handle); + } + } + + hythread_iterator_release(&it); +} diff --git a/vm/vmcore/src/util/linux/crash_dump_os.cpp b/vm/vmcore/src/util/linux/crash_dump_os.cpp new file mode 100644 index 0000000..6a1218d --- /dev/null +++ b/vm/vmcore/src/util/linux/crash_dump_os.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include +#include + +#include "open/platform_types.h" +#include "open/hythread_ext.h" +#include "port_filepath.h" +#include "port_dso.h" +#include "port_modules.h" +#include "crash_dump.h" + + +static inline bool cd_is_predefined_name(const char* name) +{ + if (*name != '[') + return false; + + return true; +// return (!strcmp(name, "[heap]") || +// !strcmp(name, "[stack]") || +// !strcmp(name, "[vdso]")); +} + +static inline native_segment_t* cd_find_segment(native_module_t* module, void* ip) +{ + for (size_t i = 0; i < module->seg_count; i++) + { + if (module->segments[i].base <= ip && + (char*)module->segments[i].base + module->segments[i].size > ip) + return &module->segments[i]; + } + + assert(0); + return NULL; +} + +void cd_parse_module_info(native_module_t* module, void* ip) +{ + fprintf(stderr, "\nCrashed module:\n"); + + if (!module) + { // Unknown address + fprintf(stderr, "Unknown address 0x%"W_PI_FMT"\n", + (POINTER_SIZE_INT)ip); + return; + } + + native_segment_t* segment = cd_find_segment(module, ip); + + if (!module->filename) + { + fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + if (cd_is_predefined_name(module->filename)) + { // Special memory region + fprintf(stderr, "%s memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + module->filename, + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + // Common shared module + const char* short_name = port_filepath_basename(module->filename); + const char* module_type = cd_get_module_type(short_name); + + fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); +} diff --git a/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp b/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp index a9c6ffa..017b91b 100644 --- a/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp +++ b/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp @@ -15,25 +15,8 @@ * limitations under the License. */ -#define LOG_DOMAIN "signals" -#include "cxxlog.h" - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include - - #undef __USE_XOPEN #include @@ -42,80 +25,20 @@ #include #endif #include -#include "port_thread.h" -#include "method_lookup.h" +#define LOG_DOMAIN "signals" +#include "cxxlog.h" +#include "open/platform_types.h" #include "Class.h" +#include "interpreter.h" +#include "method_lookup.h" #include "environment.h" - -#include "open/gc.h" - -#include "init.h" #include "exceptions.h" #include "exceptions_jit.h" -#include "vm_threads.h" -#include "open/vm_util.h" -#include "compile.h" -#include "vm_stats.h" -#include "sync_bits.h" - -#include "object_generic.h" -#include "thread_manager.h" - -#include "exception_filter.h" -#include "interpreter.h" -#include "crash_handler.h" -#include "stack_dump.h" -#include "jvmti_break_intf.h" - #include "signals_common.h" +#include "signals.h" -static void general_crash_handler(int signum, Registers* regs); - - -extern "C" { -static void DECL_CHANDLER c_exception_handler(Registers* regs, Class* exn_class, bool java_code) { - // this exception handler is executed *after* NT exception handler returned - DebugUtilsTI* ti = VM_Global_State::loader_env->TI; - // Create local copy for registers because registers in TLS can be changed - VM_thread *thread = p_TLS_vmthread; - assert(thread); - assert(exn_class); - - exn_athrow_regs(regs, exn_class, java_code, true); -} -} - -static void throw_from_sigcontext(Registers* regs, Class* exc_clss) -{ - DebugUtilsTI* ti = VM_Global_State::loader_env->TI; - bool java_code = (vm_identify_eip((void*)regs->get_ip()) == VM_TYPE_JAVA); - VM_thread* vmthread = p_TLS_vmthread; - - vm_set_exception_registers(vmthread, *regs); - - assert(exc_clss); - - NativeCodePtr callback = (NativeCodePtr) c_exception_handler; - // Set up parameters and registers - port_set_longjump_regs(callback, regs, - 3, regs, exc_clss, (POINTER_SIZE_INT)java_code); -} - -static bool java_throw_from_sigcontext(Registers* regs, Class* exc_clss) -{ - ASSERT_NO_INTERPRETER; - void* ip = regs->get_ip(); - VM_Code_Type vmct = vm_identify_eip(ip); - if(vmct != VM_TYPE_JAVA) { - return false; - } - - throw_from_sigcontext(regs, exc_clss); - return true; -} - /* * Information about stack */ @@ -154,11 +77,11 @@ inline size_t find_stack_size() { } #endif -inline size_t find_guard_stack_size() { +static inline size_t find_guard_stack_size() { return 64*1024; } -inline size_t find_guard_page_size() { +static inline size_t find_guard_page_size() { int err; size_t guard_size; pthread_attr_t pthread_attr; @@ -173,19 +96,19 @@ inline size_t find_guard_page_size() { static size_t common_guard_stack_size; static size_t common_guard_page_size; -inline void* get_stack_addr() { +static inline void* get_stack_addr() { return jthread_self_vm_thread_unsafe()->stack_addr; } -inline size_t get_stack_size() { +static inline size_t get_stack_size() { return jthread_self_vm_thread_unsafe()->stack_size; } -inline size_t get_guard_stack_size() { +static inline size_t get_guard_stack_size() { return common_guard_stack_size; } -inline size_t get_guard_page_size() { +static inline size_t get_guard_page_size() { return common_guard_page_size; } @@ -362,288 +285,104 @@ static bool check_stack_overflow(Registers* regs, void* fault_addr) { } - -static void stack_overflow_handler(Registers* regs) +Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) { - Global_Env *env = VM_Global_State::loader_env; - - vm_thread_t vm_thread = p_TLS_vmthread; - remove_guard_stack(vm_thread); - vm_thread->restore_guard_page = true; + TRACE2("signals", ("SOE detected at ip=%p, sp=%p", + regs->get_ip(), regs->get_sp())); - if (java_throw_from_sigcontext( - regs, env->java_lang_StackOverflowError_Class)) { - return; - } else { - if (is_unwindable()) { - if (hythread_is_suspend_enabled()) { - tmn_suspend_disable(); - } - throw_from_sigcontext( - regs, env->java_lang_StackOverflowError_Class); - } else { - exn_raise_by_class(env->java_lang_StackOverflowError_Class); - } - } -} - - -static void null_java_reference_handler(int signum, Registers* regs, void* fault_addr) -{ - VM_thread *vm_thread = p_TLS_vmthread; + 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 (vm_thread && vm_thread->jvmti_thread.violation_flag) + if (is_in_ti_handler(vmthread, saved_ip)) { - vm_thread->jvmti_thread.violation_flag = 0; - regs->set_ip(vm_thread->jvmti_thread.violation_restart_address); - return; + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); } - Global_Env *env = VM_Global_State::loader_env; - - TRACE2("signals", "NPE or SOE detected at " << regs->get_ip()); + if (!vmthread || env == NULL) + return FALSE; // Crash - if (check_stack_overflow(regs, fault_addr)) { - stack_overflow_handler(regs); - return; - } + remove_guard_stack(vmthread); + vmthread->restore_guard_page = true; - if (!interpreter_enabled()) { - if (java_throw_from_sigcontext( - regs, env->java_lang_NullPointerException_Class)) { - return; - } + // 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; } - general_crash_handler(signum, regs); -} - + Class* exn_class = env->java_lang_StackOverflowError_Class; -static void null_java_divide_by_zero_handler(int signum, Registers* regs, void* UNREF fault_addr) -{ - Global_Env *env = VM_Global_State::loader_env; - - TRACE2("signals", - "ArithmeticException detected at " << regs->get_ip()); - - if (!interpreter_enabled()) { - if (java_throw_from_sigcontext( - regs, env->java_lang_ArithmeticException_Class)) { - return; - } + if (is_in_java(regs)) + { + signal_throw_java_exception(regs, exn_class); } - - general_crash_handler(signum, regs); -} - -static void jvmti_jit_breakpoint_handler(int signum, Registers* regs, void* UNREF fault_addr) -{ - TRACE2("signals", "JVMTI breakpoint detected at " << (void*)regs->get_ip()); - - if (!interpreter_enabled()) + else if (is_unwindable()) { - regs->set_ip((void*)((POINTER_SIZE_INT)regs->get_ip() - 1)); - bool handled = jvmti_jit_breakpoint_handler(regs); - if (handled) - return; + if (hythread_is_suspend_enabled()) + hythread_suspend_disable(); + signal_throw_exception(regs, exn_class); + } else { + exn_raise_by_class(exn_class); } - general_crash_handler(signum, regs); -} + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); -/** - * Print out the call stack of the aborted thread. - * @note call stacks may be used for debugging - */ -static void abort_handler(int signum, Registers* regs, void* UNREF fault_addr) -{ - general_crash_handler(signum, regs); + return TRUE; } -static void process_crash(Registers* regs) +Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) { - // print stack trace - sd_print_stack(regs); -} + TRACE2("signals", "NPE detected at " << regs->get_ip()); -struct sig_name_t -{ - int num; - char* name; -}; + 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; -static sig_name_t sig_names[] = -{ - {SIGTRAP, "SIGTRAP"}, - {SIGSEGV, "SIGSEGV"}, - {SIGFPE, "SIGFPE" }, - {SIGABRT, "SIGABRT"}, - {SIGINT, "SIGINT" }, - {SIGQUIT, "SIGQUIT"} -}; - -static const char* get_sig_name(int signum) -{ - for (int i = 0; i < sizeof(sig_names)/sizeof(sig_names[0]); i++) + if (is_in_ti_handler(vmthread, saved_ip)) { - if (signum == sig_names[i].num) - return sig_names[i].name; + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); } - return "unregistered"; -} - -static void general_crash_handler(int signum, Registers* regs) -{ - // setup default handler - signal(signum, SIG_DFL); - // Print message - fprintf(stderr, "Signal %d is reported: %s\n", signum, get_sig_name(signum)); - - if (!is_gdb_crash_handler_enabled() || - !gdb_crash_handler(regs)) + if (check_stack_overflow(regs, fault_addr)) { - NativeCodePtr callback = (NativeCodePtr)process_crash; - port_set_longjump_regs(callback, regs, 1, regs); - } -} + Boolean result = stack_overflow_handler(signum, regs, fault_addr); -static void general_signal_handler(int signum, siginfo_t* info, void* context) -{ - bool replaced = false; - ucontext_t* uc = (ucontext_t *)context; - void* fault_addr = info->si_addr; - VM_thread* vm_thread = p_TLS_vmthread; - bool violation = - (signum == SIGSEGV) && vm_thread && vm_thread->jvmti_thread.violation_flag; - - Registers regs; - port_thread_context_to_regs(®s, uc); - void* saved_ip = regs.get_ip(); - void* new_ip = saved_ip; - bool in_java = false; - - if (vm_thread) - { - // If exception is occured in processor instruction previously - // instrumented by breakpoint, the actual exception address will reside - // in jvmti_jit_breakpoints_handling_buffer - // We should replace exception address with saved address of instruction - POINTER_SIZE_INT break_buf = - (POINTER_SIZE_INT)vm_thread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer; - if ((POINTER_SIZE_INT)saved_ip >= break_buf && - (POINTER_SIZE_INT)saved_ip < break_buf + TM_JVMTI_MAX_BUFFER_SIZE) - { - // Breakpoints should not occur in breakpoint buffer - assert(signum != SIGTRAP); - - replaced = true; - new_ip = vm_get_ip_from_regs(vm_thread); - regs.set_ip(new_ip); - port_thread_regs_to_context(uc, ®s); - } + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); - in_java = (vm_identify_eip(regs.get_ip()) == VM_TYPE_JAVA); + return result; } + if (!vmthread || env == NULL || + !is_in_java(regs) || interpreter_enabled()) + return FALSE; // Crash + // Pass exception to NCAI exception handler bool is_handled = 0; - bool is_internal = (signum == SIGTRAP) || violation; - ncai_process_signal_event((NativeCodePtr)regs.get_ip(), - (jint)signum, is_internal, &is_handled); + ncai_process_signal_event((NativeCodePtr)regs->get_ip(), + (jint)signum, false, &is_handled); if (is_handled) - return; - - // delegate evident cases to crash handler - if ((!vm_thread || - (!in_java && signum != SIGSEGV)) && - signum != SIGTRAP && signum != SIGINT && signum != SIGQUIT) { - regs.set_ip(saved_ip); - general_crash_handler(signum, ®s); - port_thread_regs_to_context(uc, ®s); - return; + if (new_ip) + regs->set_ip(saved_ip); + return TRUE; } - switch (signum) - { - case SIGTRAP: - jvmti_jit_breakpoint_handler(signum, ®s, fault_addr); - break; - case SIGSEGV: - null_java_reference_handler(signum, ®s, fault_addr); - break; - case SIGFPE: - null_java_divide_by_zero_handler(signum, ®s, fault_addr); - break; - case SIGABRT: - abort_handler(signum, ®s, fault_addr); - break; - case SIGINT: - vm_interrupt_handler(signum); - break; - case SIGQUIT: - vm_dump_handler(signum); - break; - default: - // Unknown signal - assert(0); - break; - } + signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); - // If IP was not changed in specific handler to start another handler, - // we should restore original IP, if it's nesessary - if (replaced && regs.get_ip() == new_ip) - regs.set_ip((void*)saved_ip); + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); - // Update OS context - port_thread_regs_to_context(uc, ®s); + return TRUE; } - -void initialize_signals() -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &general_signal_handler; - sigaction(SIGTRAP, &sa, NULL); - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO | SA_ONSTACK;; - sa.sa_sigaction = &general_signal_handler; - sigaction(SIGSEGV, &sa, NULL); - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &general_signal_handler; - sigaction(SIGFPE, &sa, NULL); - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &general_signal_handler; - sigaction(SIGINT, &sa, NULL); - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &general_signal_handler; - sigaction(SIGQUIT, &sa, NULL); - - /* install abort_handler to print out call stack on assertion failures */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &general_signal_handler; - sigaction( SIGABRT, &sa, NULL); - /* abort_handler installed */ - - // Prepare gdb crash handler - init_gdb_crash_handler(); - - // Prepare general crash handler - sd_init_crash_handler(); - -} //initialize_signals - -void shutdown_signals() { - //FIXME: should be defined in future -} //shutdown_signals diff --git a/vm/vmcore/src/util/linux/include/exception_filter.h b/vm/vmcore/src/util/linux/include/exception_filter.h deleted file mode 100644 index 299a7bf..0000000 --- a/vm/vmcore/src/util/linux/include/exception_filter.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.3 $ - */ - -#include "vm_core_types.h" - -/** - * For using in crash handlers - */ -void print_reg_state(Registers* regs); diff --git a/vm/vmcore/src/util/linux/include/platform_lowlevel.h b/vm/vmcore/src/util/linux/include/platform_lowlevel.h index ea463a4..78bf43e 100644 --- a/vm/vmcore/src/util/linux/include/platform_lowlevel.h +++ b/vm/vmcore/src/util/linux/include/platform_lowlevel.h @@ -25,13 +25,6 @@ #include //#include -inline void disable_assert_dialogs() { - /* NOP on Linux */ -} - -inline void debug_break() { - abort(); -} #ifdef __cplusplus extern "C" { #endif @@ -47,8 +40,6 @@ extern "C" { #define dllexport #define __declspec(junk) -#define _MAX_PATH PATH_MAX - #ifdef __cplusplus } diff --git a/vm/vmcore/src/util/linux/include/signals_common.h b/vm/vmcore/src/util/linux/include/signals_common.h index 521d031..39cd623 100644 --- a/vm/vmcore/src/util/linux/include/signals_common.h +++ b/vm/vmcore/src/util/linux/include/signals_common.h @@ -18,9 +18,6 @@ #ifndef _SIGNALS_COMMON_H_ #define _SIGNALS_COMMON_H_ -#include -#include "vm_core_types.h" - #ifdef _IPF_ #error IPF architecture is not adopted for unified signal handling diff --git a/vm/vmcore/src/util/linux/signals_ipf.cpp b/vm/vmcore/src/util/linux/signals_ipf.cpp index 7585124..26a47fb 100644 --- a/vm/vmcore/src/util/linux/signals_ipf.cpp +++ b/vm/vmcore/src/util/linux/signals_ipf.cpp @@ -14,146 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.2.4.4 $ - */ - -// We use signal handlers to detect null pointer and divide by zero -// exceptions. -// There must be an easier way of locating the context in the signal -// handler than what we do here. - -#define LOG_DOMAIN "port.old" -#include "cxxlog.h" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include - #undef __USE_XOPEN #include #include -#include -#include "method_lookup.h" +#if defined(FREEBSD) +#include +#endif +#define LOG_DOMAIN "signals" +#include "cxxlog.h" +#include "open/platform_types.h" #include "Class.h" +#include "interpreter.h" +#include "method_lookup.h" #include "environment.h" - -#include "open/gc.h" - -#include "init.h" #include "exceptions.h" #include "exceptions_jit.h" -#include "vm_threads.h" -#include "open/vm_util.h" -#include "compile.h" -#include "vm_stats.h" -#include "sync_bits.h" - -#include "object_generic.h" -#include "thread_manager.h" - -#include "exception_filter.h" -#include "interpreter.h" -#include "crash_handler.h" -#include "stack_dump.h" -#include "jvmti_break_intf.h" - - -#include - -void asm_exception_catch_callback() { - // FIXME: not implemented - fprintf(stderr, "FIXME: asm_jvmti_exception_catch_callback: not implemented\n"); - assert(0); - abort(); -} - -void asm_jvmti_exception_catch_callback() { - // FIXME: not implemented - fprintf(stderr, "FIXME: asm_jvmti_exception_catch_callback: not implemented\n"); - assert(0); - abort(); -} - -static bool java_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) -{ - // FIXME: not implemented - fprintf(stderr, "FIXME: java_throw_from_sigcontext: not implemented\n"); - assert(0); - abort(); - return false; -} - -void abort_handler (int signum, siginfo_t* info, void* context) { - fprintf(stderr, "SIGABRT in VM code.\n"); - Registers regs; - ucontext_t *uc = (ucontext_t *)context; - port_thread_context_to_regs(®s, uc); - - // setup default handler - signal(signum, SIG_DFL); - - if (!is_gdb_crash_handler_enabled() || - !gdb_crash_handler(®s)) - { - // print stack trace - sd_print_stack(®s); - } -} - - -static void throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) { - // FIXME: not implemented - fprintf(stderr, "FIXME: throw_from_sigcontext: not implemented\n"); - assert(0); - abort(); -} - -void null_java_divide_by_zero_handler(int signum, siginfo_t* UNREF info, void* context) -{ - ucontext_t *uc = (ucontext_t *)context; - Global_Env *env = VM_Global_State::loader_env; - - /* Will not compile on IPF: - * TRACE2("signals", "ArithmeticException detected at " << - (void *)uc->uc_mcontext.gregs[REG_EIP]); - */ - - if (!interpreter_enabled()) { - if (java_throw_from_sigcontext( - uc, env->java_lang_ArithmeticException_Class)) { - return; - } - } - - fprintf(stderr, "SIGFPE in VM code.\n"); - Registers regs; - port_thread_context_to_regs(®s, uc); - - // setup default handler - signal(signum, SIG_DFL); - - if (!is_gdb_crash_handler_enabled() || - !gdb_crash_handler(®s)) - { - // print stack trace - sd_print_stack(®s); - } -} +#include "signals.h" /* @@ -187,12 +68,12 @@ inline size_t find_stack_size() { } #endif -inline size_t find_guard_stack_size() { +static inline size_t find_guard_stack_size() { return 64*1024; } -inline size_t find_guard_page_size() { +static inline size_t find_guard_page_size() { int err; size_t guard_size; pthread_attr_t pthread_attr; @@ -206,19 +87,19 @@ inline size_t find_guard_page_size() { static size_t common_guard_stack_size; static size_t common_guard_page_size; -inline void* get_stack_addr() { +static inline void* get_stack_addr() { return jthread_self_vm_thread_unsafe()->stack_addr; } -inline size_t get_stack_size() { +static inline size_t get_stack_size() { return jthread_self_vm_thread_unsafe()->stack_size; } -inline size_t get_guard_stack_size() { +static inline size_t get_guard_stack_size() { return common_guard_stack_size; } -inline size_t get_guard_page_size() { +static inline size_t get_guard_page_size() { return common_guard_page_size; } @@ -298,11 +179,6 @@ size_t get_available_stack_size() { } } -size_t get_default_stack_size() { - size_t default_stack_size = get_stack_size(); - return default_stack_size; -} - bool check_available_stack_size(size_t required_size) { size_t available_stack_size = get_available_stack_size(); @@ -330,12 +206,6 @@ bool check_stack_size_enough_for_exception_catch(void* sp) { return get_restore_stack_size() < available_stack_size; } -void remove_guard_stack() { - vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); - assert(vm_thread); - remove_guard_stack(vm_thread); -} - void remove_guard_stack(vm_thread_t vm_thread) { int err; char* stack_addr = (char*) get_stack_addr(); @@ -357,7 +227,7 @@ void remove_guard_stack(vm_thread_t vm_thread) { } -bool check_stack_overflow(siginfo_t *info, ucontext_t *uc) { +static bool check_stack_overflow(Registers* regs, void* fault_addr) { char* stack_addr = (char*) get_stack_addr(); size_t stack_size = get_stack_size(); size_t guard_stack_size = get_guard_stack_size(); @@ -366,264 +236,113 @@ bool check_stack_overflow(siginfo_t *info, ucontext_t *uc) { char* guard_page_begin = stack_addr - stack_size + guard_page_size + guard_stack_size; char* guard_page_end = guard_page_begin + guard_page_size; - char* fault_addr = (char*)(info->si_addr); - //char* esp_value = (char*)(uc->uc_mcontext.gregs[REG_ESP]); - return((guard_page_begin <= fault_addr) && (fault_addr < guard_page_end)); } -/* - * We find the true signal stack frame set-up by kernel,which is located - * by locate_sigcontext() below; then change its content according to - * exception handling semantics, so that when the signal handler is - * returned, application can continue its execution in Java exception handler. - */ -void stack_overflow_handler(int signum, siginfo_t* UNREF info, void* context) +Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) { - ucontext_t *uc = (ucontext_t *)context; - Global_Env *env = VM_Global_State::loader_env; + TRACE2("signals", ("SOE detected at ip=%p, sp=%p", + regs->get_ip(), regs->get_sp())); - if (java_throw_from_sigcontext( - uc, env->java_lang_StackOverflowError_Class)) { - return; - } else { - if (is_unwindable()) { - if (hythread_is_suspend_enabled()) { - tmn_suspend_disable(); - } - throw_from_sigcontext( - uc, env->java_lang_StackOverflowError_Class); - } else { - vm_thread_t vm_thread = p_TLS_vmthread; - remove_guard_stack(vm_thread); - exn_raise_by_name("java/lang/StackOverflowError"); - vm_thread->restore_guard_page = true; - } - } -} + assert(0); // Not implemented + abort(); -void null_java_reference_handler(int signum, siginfo_t* UNREF info, void* context) -{ - ucontext_t *uc = (ucontext_t *)context; - Global_Env *env = VM_Global_State::loader_env; - Registers regs; - port_thread_context_to_regs(®s, uc); + 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 (!p_TLS_vmthread) + if (is_in_ti_handler(vmthread, saved_ip)) { - if (!is_gdb_crash_handler_enabled() || - !gdb_crash_handler(®s)) - { - // print stack trace - sd_print_stack(®s); - } + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); } - /* Will not compile on IPF: - TRACE2("signals", "NPE or SOE detected at " << - (void *)uc->uc_mcontext.gregs[REG_EIP]); */ + if (!vmthread || env == NULL) + return FALSE; // Crash - if (check_stack_overflow(info, uc)) { - stack_overflow_handler(signum, info, context); - return; - } - - if (!interpreter_enabled()) { - if (java_throw_from_sigcontext( - uc, env->java_lang_NullPointerException_Class)) { - return; - } + // 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; } - fprintf(stderr, "SIGSEGV in VM code.\n"); - // setup default handler - signal(signum, SIG_DFL); + Class* exn_class = env->java_lang_StackOverflowError_Class; - if (!is_gdb_crash_handler_enabled() || - !gdb_crash_handler(®s)) + if (is_in_java(regs)) { - // print stack trace - sd_print_stack(®s); + 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 { + remove_guard_stack(vmthread); + vmthread->restore_guard_page = true; + exn_raise_by_class(exn_class); } -} - -void initialize_signals() { - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO | SA_ONSTACK;; - sa.sa_sigaction = &null_java_reference_handler; - sigaction(SIGSEGV, &sa, NULL); - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &null_java_divide_by_zero_handler; - sigaction(SIGFPE, &sa, NULL); - - signal(SIGINT, (void (*)(int)) vm_interrupt_handler); - signal(SIGQUIT, (void (*)(int)) vm_dump_handler); - - /* install abort_handler to print out call stack on assertion failures */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &abort_handler; - sigaction( SIGABRT, &sa, NULL); - /* abort_handler installed */ - - // Prepare gdb crash handler - init_gdb_crash_handler(); - - // Prepare general crash handler - sd_init_crash_handler(); - -} //initialize_signals - -void shutdown_signals() { - //FIXME: should be defined in future -} //shutdown_signals - -#if 0 - -static sigset_t signal_set; - -extern "C" void get_rnat_and_bspstore(uint64* res); -extern "C" void do_flushrs(); -// Variables used to locate the context from the signal handler -static int sc_nest = -1; -static bool use_ucontext = false; -static uint32 exam_point; + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); -bool SuspendThread(unsigned xx){ return 0; } -bool ResumeThread(unsigned xx){ return 1; } + return TRUE; +} -static bool linux_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) +Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) { - // FIXME: not implemented - assert(0); - abort(); - return false; -} + TRACE2("signals", "NPE detected at " << regs->get_ip()); -static void throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) { - // FIXME: not implemented - assert(0); + assert(0); // Not implemented abort(); - return false; -} + 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; -/* - * We find the true signal stack frame set-up by kernel,which is located - * by locate_sigcontext() below; then change its content according to - * exception handling semantics, so that when the signal handler is - * returned, application can continue its execution in Java exception handler. - */ - -void null_java_reference_handler(int signum) -{ - uint32* top_ebp = NULL; -//TODO: ADD correct stack handling here!! - Global_Env *env = VM_Global_State::loader_env; - linux_throw_from_sigcontext(top_ebp, env->java_lang_NullPointerException_Class); -} - + if (is_in_ti_handler(vmthread, saved_ip)) + { + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); + } -void null_java_divide_by_zero_handler(int signum) -{ - uint32* top_ebp = NULL; -//TODO: ADD correct stack handling here!! - Global_Env *env = VM_Global_State::loader_env; - linux_throw_from_sigcontext(top_ebp, env->java_lang_ArithmeticException_Class); -} + if (check_stack_overflow(regs, fault_addr)) + { + Boolean result = stack_overflow_handler(signum, regs, fault_addr); -/* -See function initialize_signals() below first please. - -Two kinds of signal contexts (and stack frames) are tried in -locate_sigcontext(), one is sigcontext, which is the way of -Linux kernel implements( see Linux kernel source -arch/i386/kernel/signal.c for detail); the other is ucontext, -used in some other other platforms. - -The sigcontext locating in Linux is not so simple as expected, -because it involves not only the kernel, but also glibc/linuxthreads, -which VM is linked against. In glibc/linuxthreads, user-provided -signal handler is wrapped by linuxthreads signal handler, i.e. -the signal handler really registered in system is not the one -provided by user. So when Linux kernel finishes setting up signal -stack frame and returns to user mode for singal handler execution, -locate_sigcontext() is not the one being invoked immediately. It's -called by linuxthreads function. That means the user stack viewed by -locate_sigcontext() is NOT NECESSARILY the signal frame set-up by -kernel, we need find the true one according to glibc/linuxthreads -specific signal implementation in different versions. - -Because locate_sigcontext() uses IA32 physical register epb for -call stack frame, compilation option `-fomit-frame-pointer' MUST -not be used when gcc compiles it; and as gcc info, `-O2' will do -`-fomit-frame-pointer' by default, although we haven't seen that -in our experiments. -*/ - -volatile void locate_sigcontext(int signum) -{ - sigcontext *sc, *found_sc; - uint32 *ebp = NULL; - int i; - -//TODO: ADD correct stack handling here!! - -#define SC_SEARCH_WIDTH 3 - for (i = 0; i < SC_SEARCH_WIDTH; i++) { - sc = (sigcontext *)(ebp + 3 ); - if (sc->sc_ip == ((uint32)exam_point)) { // found - sc_nest = i; - use_ucontext = false; - found_sc = sc; - // we will try to find the real sigcontext setup by Linux kernel, - // because if we want to change the execution path after the signal - // handling, we must modify the sigcontext used by kernel. - // LinuxThreads in glibc 2.1.2 setups a sigcontext for our singal - // handler, but we should not modify it, because kernel doesn't use - // it when resumes the application. Then we must find the sigcontext - // setup by kernel, and modify it in singal handler. - // but, with glibc 2.2.3, it's useless to modify only the sigcontext - // setup by Linux kernel, because LinuxThreads does a interesting - // copy after our signal handler returns, which destroys the - // modification we have just done in the handler. So with glibc 2.2.3, - // what we need do is simply to modify the sigcontext setup by - // LinuxThreads, which will be copied to overwrite the one setup by - // kernel. Really complicated..., not really. We use a simple trick - // to overcome the changes in glibc from version to version, that is, - // we modify both sigcontexts setup by kernel and LinuxThreads. Then - // it will always work. - - } else { // not found - struct ucontext *uc; - uc = (struct ucontext *)((uint64)ebp[4]); - if ((ebp < (uint32 *)uc) && ((uint32 *)uc < ebp + 0x100)) { - sc = (sigcontext *)&uc->uc_mcontext; - if (sc->sc_ip == ((uint32)exam_point)) { // found - sc_nest = i; - use_ucontext = true; - found_sc = sc; - break; - } - } - } + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); - ebp = (uint32 *)((uint64)ebp[0]); + return result; } - if (sc_nest < 0) { - printf("cannot locate sigcontext.\n"); - printf("Please add or remove any irrelevant statement(e.g. add a null printf) in VM source code, then rebuild it. If problem remains, please submit a bug report. Thank you very much\n"); - exit(1); + if (!vmthread || env == NULL || + !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); -#endif + return TRUE; +} diff --git a/vm/vmcore/src/util/natives_support.cpp b/vm/vmcore/src/util/natives_support.cpp index f4327cd..61b6a7a 100644 --- a/vm/vmcore/src/util/natives_support.cpp +++ b/vm/vmcore/src/util/natives_support.cpp @@ -39,8 +39,6 @@ #include "jni_types.h" #include "jni_utils.h" -#include "stack_dump.h" // To update modules list on library load (in debug) - #define LOG_DOMAIN "natives" #include "cxxlog.h" @@ -298,8 +296,6 @@ natives_load_library(const char* library_name, bool* just_loaded, returnCode = pinfo->handle; - sd_update_modules(); // Updates modules list for crash handling (in debug) - NATIVES_LOAD_LIBRARY_EXIT : #ifdef PLATFORM_NT @@ -747,7 +743,7 @@ char* short_name(const char* name, char* buf) if (!filepointer) return NULL; - if (strlen(filepointer) > _MAX_PATH) + if (strlen(filepointer) > PORT_PATH_MAX) return NULL; strcpy(buf, filepointer); @@ -762,7 +758,7 @@ char* short_name(const char* name, char* buf) // Method is stupid and slow but it works for full and partial names bool natives_is_library_loaded_slow(const char* libname) { - char src_buf[_MAX_PATH + 1], cmp_buf[_MAX_PATH + 1]; + char src_buf[PORT_PATH_MAX + 1], cmp_buf[PORT_PATH_MAX + 1]; if (short_name(libname, src_buf) == NULL) return false; // Error case diff --git a/vm/vmcore/src/util/signals.cpp b/vm/vmcore/src/util/signals.cpp new file mode 100644 index 0000000..637486a --- /dev/null +++ b/vm/vmcore/src/util/signals.cpp @@ -0,0 +1,125 @@ +/* + * 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 "signals.h" + + +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_ + assert(0); // Not implemented + abort(); +#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_ + assert(0); // Not implemented + abort(); +#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; +} diff --git a/vm/vmcore/src/util/win/crash_dump_os.cpp b/vm/vmcore/src/util/win/crash_dump_os.cpp new file mode 100644 index 0000000..659afe9 --- /dev/null +++ b/vm/vmcore/src/util/win/crash_dump_os.cpp @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include + +#include "open/platform_types.h" +#include "open/hythread_ext.h" +#include "port_modules.h" +#include "port_filepath.h" +#include "crash_dump.h" + + +static const char* cd_get_region_access_info(MEMORY_BASIC_INFORMATION* pinfo) +{ + if ((pinfo->State & MEM_COMMIT) == 0) + return "not committed"; + + if ((pinfo->Protect & PAGE_GUARD) != 0) + return "guard page occured"; + + if ((pinfo->Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | + PAGE_READWRITE | PAGE_READONLY)) != 0) + return ""; + + if ((pinfo->Protect & (PAGE_READWRITE | PAGE_READONLY)) != 0) + return "without execution rights"; + + return "without read rights";; +} + +void cd_parse_module_info(native_module_t* module, void* ip) +{ + fprintf(stderr, "\nCrashed module:\n"); + + if (module) + { + native_segment_t* segment = module->segments; + + assert(module->filename); + + if (!module->filename) + { // We should not reach this code + fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + // Common shared module + const char* short_name = port_filepath_basename(module->filename); + const char* module_type = cd_get_module_type(short_name); + fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); + return; + } + + // module == NULL + size_t start_addr, end_addr, region_size; + MEMORY_BASIC_INFORMATION mem_info; + + VirtualQuery(ip, &mem_info, sizeof(mem_info)); + start_addr = (size_t)mem_info.BaseAddress; + region_size = (size_t)mem_info.RegionSize; + end_addr = start_addr + region_size; + + fprintf(stderr, "Memory region 0x%"W_PI_FMT":0x%"W_PI_FMT" %s\n", + start_addr, end_addr, cd_get_region_access_info(&mem_info)); +} diff --git a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp b/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp index 3e82e6a..d866d0a 100644 --- a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp +++ b/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp @@ -15,150 +15,24 @@ * limitations under the License. */ +#include -#include "clog.h" +#define LOG_DOMAIN "signals" +#include "cxxlog.h" +#include "open/platform_types.h" +#include "Class.h" +#include "interpreter.h" #include "method_lookup.h" -#include "Environment.h" +#include "environment.h" #include "exceptions.h" #include "exceptions_jit.h" -#include "interpreter_exports.h" -#include "stack_iterator.h" -#include "stack_dump.h" -#include "jvmti_break_intf.h" -#include "m2n.h" -#include "open/hythread_ext.h" -#include "port_thread.h" - -// Windows specific -#include -#include -#ifndef NO_DBGHELP -#include -#pragma comment(linker, "/defaultlib:dbghelp.lib") -#endif - -#include "exception_filter.h" - - -#if INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 -#define JVMTI_EXCEPTION_STATUS STATUS_BREAKPOINT -#elif INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_HLT || INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_CLI -#define JVMTI_EXCEPTION_STATUS STATUS_PRIVILEGED_INSTRUCTION -#else -#error Unknown value of INSTRUMENTATION_BYTE -#endif - - -#ifndef NO_DBGHELP -typedef BOOL (WINAPI *MiniDumpWriteDump_type) - (HANDLE hProcess, - DWORD ProcessId, - HANDLE hFile, - MINIDUMP_TYPE DumpType, - PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - PMINIDUMP_CALLBACK_INFORMATION CallbackParam); -#endif // #ifndef NO_DBGHELP - - -static void create_minidump(LPEXCEPTION_POINTERS exp) -{ -#ifndef NO_DBGHELP - MINIDUMP_EXCEPTION_INFORMATION mei = {GetCurrentThreadId(), exp, TRUE}; - MiniDumpWriteDump_type mdwd = NULL; - - HMODULE hdbghelp = ::LoadLibrary("dbghelp"); - - if (hdbghelp) - mdwd = (MiniDumpWriteDump_type)::GetProcAddress(hdbghelp, "MiniDumpWriteDump"); - - if (!mdwd) - { - fprintf(stderr, "Failed to open DbgHelp library"); - return; - } - - char filename[24]; - sprintf(filename, "minidump_%d.dmp", GetCurrentProcessId()); - - HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if (file == INVALID_HANDLE_VALUE) - { - fprintf(stderr, "Failed to create minidump file: %s", filename); - return; - } - - SymInitialize(GetCurrentProcess(), NULL, TRUE); - - BOOL res = mdwd(GetCurrentProcess(), GetCurrentProcessId(), - file, MiniDumpNormal, &mei, 0, 0); - - if (!res) - { - fprintf(stderr, "Failed to create minidump"); - } - else - { - char dir[_MAX_PATH]; - GetCurrentDirectory(_MAX_PATH, dir); - fprintf(stderr, "Minidump is generated:\n%s\\%s", dir, filename); - } - - CloseHandle(file); -#endif // #ifndef NO_DBGHELP -} - - -static LONG process_crash(Registers* regs, LPEXCEPTION_POINTERS exp, DWORD ExceptionCode) -{ -static DWORD saved_eip_index = TlsAlloc(); -static BOOL UNREF tmp_init = TlsSetValue(saved_eip_index, (LPVOID)0); - - // Check crash location to prevent infinite recursion - if (regs->get_ip() == (void*)TlsGetValue(saved_eip_index)) - return EXCEPTION_CONTINUE_SEARCH; - // Store registers to compare IP in future - TlsSetValue(saved_eip_index, (LPVOID)regs->get_ip()); - - switch (ExceptionCode) - { - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_PRIV_INSTRUCTION: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - break; - - case EXCEPTION_STACK_OVERFLOW: - default: - return EXCEPTION_CONTINUE_SEARCH; - } - - // We can't obtain a value of property if loader_env is NULL - if (VM_Global_State::loader_env == NULL || - get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) - return EXCEPTION_CONTINUE_SEARCH; - - // Report crash - fprintf(stderr, "Windows reported exception: 0x%x\n", ExceptionCode); - - sd_print_stack(regs); - create_minidump(exp); - LOGGER_EXIT(-1); - return EXCEPTION_CONTINUE_EXECUTION; -} +#include "signals.h" /* * Information about stack */ -inline void* find_stack_addr() { +static inline void* find_stack_addr() { void* stack_addr; size_t reg_size; MEMORY_BASIC_INFORMATION memory_information; @@ -170,7 +44,7 @@ inline void* find_stack_addr() { return stack_addr; } -inline size_t find_guard_page_size() { +static inline size_t find_guard_page_size() { size_t guard_size; SYSTEM_INFO system_info; @@ -180,7 +54,7 @@ inline size_t find_guard_page_size() { return guard_size; } -inline size_t find_guard_stack_size() { +static inline size_t find_guard_stack_size() { # ifdef _EM64T_ //this code in future should be used on both platforms x86-32 and x86-64 return 64*1024; @@ -193,19 +67,19 @@ inline size_t find_guard_stack_size() { static size_t common_guard_stack_size; static size_t common_guard_page_size; -inline void* get_stack_addr() { +static inline void* get_stack_addr() { return jthread_self_vm_thread_unsafe()->stack_addr; } -inline size_t get_stack_size() { +static inline size_t get_stack_size() { return jthread_self_vm_thread_unsafe()->stack_size; } -inline size_t get_guard_stack_size() { +static inline size_t get_guard_stack_size() { return common_guard_stack_size; } -inline size_t get_guard_page_size() { +static inline size_t get_guard_page_size() { return common_guard_page_size; } @@ -229,11 +103,11 @@ void init_stack_info() { # endif } -size_t get_mem_protect_stack_size() { +static inline size_t get_mem_protect_stack_size() { return 0x0100; } -size_t get_restore_stack_size() { +static inline size_t get_restore_stack_size() { return get_mem_protect_stack_size() + 0x0100; } @@ -265,12 +139,6 @@ bool set_guard_stack() { return true; } -void remove_guard_stack() { - vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); - assert(vm_thread); - remove_guard_stack(vm_thread); -} - void remove_guard_stack(vm_thread_t vm_thread) { void* stack_addr = get_stack_addr(); size_t stack_size = get_stack_size(); @@ -307,11 +175,6 @@ size_t get_available_stack_size() { } } -size_t get_default_stack_size() { - size_t default_stack_size = get_stack_size(); - return default_stack_size; -} - bool check_available_stack_size(size_t required_size) { size_t available_stack_size = get_available_stack_size(); if (available_stack_size < required_size) { @@ -336,193 +199,94 @@ bool check_stack_size_enough_for_exception_catch(void* sp) { } -LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception) -{ - DWORD code = nt_exception->ExceptionRecord->ExceptionCode; - PCONTEXT context = nt_exception->ContextRecord; - Registers regs; - bool flag_replaced = false; - VM_thread* vmthread = p_TLS_vmthread; - // Convert NT context to Registers - port_thread_context_to_regs(®s, context); - POINTER_SIZE_INT saved_eip = (POINTER_SIZE_INT)regs.get_ip(); +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())); - bool in_java = false; + 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 (vmthread) + if (is_in_ti_handler(vmthread, saved_ip)) { - // If exception is occured in processor instruction previously - // instrumented by breakpoint, the actual exception address will reside - // in jvmti_jit_breakpoints_handling_buffer - // We should replace exception address with saved address of instruction - POINTER_SIZE_INT break_buf = - (POINTER_SIZE_INT)vmthread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer; - if (saved_eip >= break_buf && - saved_eip < break_buf + TM_JVMTI_MAX_BUFFER_SIZE) - { - flag_replaced = true; - regs.set_ip(vm_get_ip_from_regs(vmthread)); - port_thread_regs_to_context(context, ®s); - } - - in_java = (vm_identify_eip(regs.get_ip()) == VM_TYPE_JAVA); + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); } - // the possible reasons for hardware exception are - // - segfault or division by zero in java code - // => NullPointerException or ArithmeticException - // - // - breakpoint or privileged instruction in java code - // => send jvmti breakpoint event - // - // - stack overflow, either in java or in native - // => StackOverflowError - // - // - other (internal VM error or debugger breakpoint) - // => delegate to default handler + if (!vmthread || env == NULL) + return FALSE; // Crash + + vmthread->restore_guard_page = true; // Pass exception to NCAI exception handler - bool is_continuable = - (nt_exception->ExceptionRecord->ExceptionFlags != EXCEPTION_NONCONTINUABLE); - bool is_handled = !is_continuable; - bool is_internal = (code == JVMTI_EXCEPTION_STATUS); - ncai_process_signal_event((NativeCodePtr)regs.get_ip(), - (jint)code, is_internal, &is_handled); - if (is_continuable && is_handled) - return EXCEPTION_CONTINUE_EXECUTION; - - // delegate "other" cases to crash handler - // Crash handler shouls be invoked when VM_thread is not attached to VM - // or exception has occured in native code and it's not STACK_OVERFLOW - if ((!vmthread || - (!in_java && code != STATUS_STACK_OVERFLOW)) && - code != JVMTI_EXCEPTION_STATUS) + bool is_handled = 0; + ncai_process_signal_event((NativeCodePtr)regs->get_ip(), + (jint)signum, false, &is_handled); + if (is_handled) { - LONG result = process_crash(®s, nt_exception, code); - regs.set_ip((void*)saved_eip); - port_thread_regs_to_context(context, ®s); - return result; + if (new_ip) + regs->set_ip(saved_ip); + return TRUE; } - TRACE2("signals", ("VEH received an exception: code = %x, ip = %p, sp = %p", - nt_exception->ExceptionRecord->ExceptionCode, regs.get_ip(), regs.get_sp())); + Class* exn_class = env->java_lang_StackOverflowError_Class; - // if HWE occured in java code, suspension should also have been disabled - bool ncai_enabled = GlobalNCAI::isEnabled(); - assert(!in_java || !hythread_is_suspend_enabled() || ncai_enabled); + 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); + } - Global_Env *env = VM_Global_State::loader_env; - // the actual exception object will be created lazily, - // we determine only exception class here - Class *exn_class = 0; + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); - switch(nt_exception->ExceptionRecord->ExceptionCode) - { - case STATUS_STACK_OVERFLOW: - { - TRACE2("signals", - ("StackOverflowError detected at ip = %p, esp = %p", - regs.get_ip(), regs.get_sp())); - - vmthread->restore_guard_page = true; - exn_class = env->java_lang_StackOverflowError_Class; - if (in_java) { - // stack overflow occured in java code: - // nothing special to do - } else if (is_unwindable()) { - // stack overflow occured in native code that can be unwound - // safely. - // Throwing exception requires suspend disabled status - if (hythread_is_suspend_enabled()) - hythread_suspend_disable(); - } else { - // stack overflow occured in native code that - // cannot be unwound. - // Mark raised exception in TLS and resume execution - exn_raise_by_class(env->java_lang_StackOverflowError_Class); - regs.set_ip((void*)saved_eip); - port_thread_regs_to_context(context, ®s); - return EXCEPTION_CONTINUE_EXECUTION; - } - } - break; - case STATUS_ACCESS_VIOLATION: - { - TRACE2("signals", - ("NullPointerException detected at ip = %p", regs.get_ip())); - exn_class = env->java_lang_NullPointerException_Class; - } - break; + return TRUE; +} - case STATUS_INTEGER_DIVIDE_BY_ZERO: - { - TRACE2("signals", - ("ArithmeticException detected at ip = %p", regs.get_ip())); - exn_class = env->java_lang_ArithmeticException_Class; - } - break; - case JVMTI_EXCEPTION_STATUS: - // JVMTI breakpoint in JITted code - { - // Breakpoints should not occur in breakpoint buffer - assert(!flag_replaced); - - TRACE2("signals", - ("JVMTI breakpoint detected at ip = %p", regs.get_ip())); - bool handled = jvmti_jit_breakpoint_handler(®s); - if (handled) - { - port_thread_regs_to_context(context, ®s); - return EXCEPTION_CONTINUE_EXECUTION; - } - else - return EXCEPTION_CONTINUE_SEARCH; - } - default: - // unexpected hardware exception occured in java code - LONG result = process_crash(®s, nt_exception, code); - regs.set_ip((void*)saved_eip); - port_thread_regs_to_context(context, ®s); - return result; - } +Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) +{ + TRACE2("signals", "NPE detected at " << regs->get_ip()); - // we must not call potentially blocking or suspendable code - // (i.e. java code of exception constructor) from exception - // handler, because this handler may hold a system-wide lock, - // and this may result in a deadlock. + 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; - // it was reported that exception handler grabs a system - // lock on Windows XPsp2 and 2003sp0, but not on a 2003sp1 + if (is_in_ti_handler(vmthread, saved_ip)) + { + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); + } - // save register context of hardware exception site - // into thread-local registers snapshot - vm_set_exception_registers(vmthread, regs); + if (!vmthread || env == NULL || + !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; + } - assert(exn_class); - // Set up parameters and registers for C handler - port_set_longjump_regs(c_exception_handler, ®s, - 3, ®s, exn_class, (POINTER_SIZE_INT)in_java); - // Store changes into NT context - port_thread_regs_to_context(context, ®s); + signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); - // exit NT exception handler and transfer - // control to VM exception handler - return EXCEPTION_CONTINUE_EXECUTION; -} + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); -void __cdecl c_exception_handler(Registers* regs, Class* exn_class, bool in_java) -{ - // this exception handler is executed *after* NT exception handler returned - DebugUtilsTI* ti = VM_Global_State::loader_env->TI; - // Create local copy for registers because registers in TLS can be changed - VM_thread *thread = p_TLS_vmthread; - assert(thread); - assert(exn_class); - - TRACE2("signals", ("should throw exception %p at IP=%p, SP=%p", - exn_class, regs->get_ip(), regs->get_sp())); - exn_athrow_regs(regs, exn_class, in_java, true); - - assert(!"si_transfer_control should not return"); + return TRUE; } diff --git a/vm/vmcore/src/util/win/include/exception_filter.h b/vm/vmcore/src/util/win/include/exception_filter.h deleted file mode 100644 index 503eee2..0000000 --- a/vm/vmcore/src/util/win/include/exception_filter.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 Euguene Ostrovsky - * @version $Revision: 1.1.2.1.4.5 $ - */ - -#ifndef nt_exception_filter_h -#define nt_exception_filter_h - -#include "platform_lowlevel.h" -#include "vm_core_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception); - -// Internal exception handler -// Is used when vectored_exception_handler is assembler wrapper -LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception); - -// Function to throw exception -void __cdecl c_exception_handler(Registers* regs, Class* exn_class, bool in_java); - -// exception catch callback to restore stack after Stack Overflow Error -void __cdecl exception_catch_callback_wrapper(); -// exception catch support for JVMTI -void __cdecl jvmti_exception_catch_callback_wrapper(); - -#ifdef __cplusplus -} // extern "C" -#endif - - -// Prints register state -void print_reg_state(Registers* regs); - - -#endif // nt_exception_filter_h - diff --git a/vm/vmcore/src/util/win/include/platform_lowlevel.h b/vm/vmcore/src/util/win/include/platform_lowlevel.h index 5badd27..e5547a1 100644 --- a/vm/vmcore/src/util/win/include/platform_lowlevel.h +++ b/vm/vmcore/src/util/win/include/platform_lowlevel.h @@ -39,19 +39,9 @@ #include -inline void disable_assert_dialogs() { - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); - _set_error_mode(_OUT_TO_STDERR); -} - -inline void debug_break() { - _CrtDbgBreak(); -} +#include +#include +#include struct timespec { long tv_sec; diff --git a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp index a871660..124a71c 100644 --- a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp @@ -31,8 +31,6 @@ #include "../../../arch/ipf/include/vm_ipf.h" -#include "exception_filter.h" - // Afremov Pavel 20050117 #include "../m2n_ipf_internal.h" diff --git a/vm/vmcore/src/util/win/nt_platform_utils.cpp b/vm/vmcore/src/util/win/nt_platform_utils.cpp index 6249872..139b459 100644 --- a/vm/vmcore/src/util/win/nt_platform_utils.cpp +++ b/vm/vmcore/src/util/win/nt_platform_utils.cpp @@ -33,48 +33,6 @@ #include "init.h" #include "platform_utils.h" #include "open/vm_util.h" -#include "stack_dump.h" -#include "exception_filter.h" - -BOOL ctrl_handler(DWORD ctrlType) -{ - switch (ctrlType) - { - case CTRL_BREAK_EVENT: - vm_dump_handler(0); - return TRUE; - case CTRL_C_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - vm_interrupt_handler(0); - return TRUE; - } - return FALSE; -} - -static PVOID veh = NULL; - -void initialize_signals(){ - TRACE2("signals", "Setting console control handle..."); - BOOL ok = SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrl_handler, TRUE); - assert(ok); - - // add VEH to catch NPE's from bytecode - TRACE2("signals", "Adding vectored exception handler..."); - veh = AddVectoredExceptionHandler(0, vectored_exception_handler); - assert(veh); - - // Prepare general crash handler - sd_init_crash_handler(); -} - -void shutdown_signals() { - TRACE2("signals", "Removing vectored exception handler..."); - ULONG res; - res = RemoveVectoredExceptionHandler(veh); - assert(res); -} //shutdown_signals //The following is for socket error handling const char *sock_errstr[] = { -- 1.5.0.3