# HG changeset patch # User coleenp # Date 1292280411 28800 # Node ID 06ba968629497f958057e165551d44aa06449bb5 # Parent 54f5dd2aa1d9458c97ff4389e09d4434e14c0e84# Parent 0d43957458609cc18550c49e7367ca26c884c875 Merge diff -r 0d4395745860 -r 06ba96862949 make/linux/makefiles/build_vm_def.sh --- a/make/linux/makefiles/build_vm_def.sh Fri Dec 10 18:05:39 2010 -0800 +++ b/make/linux/makefiles/build_vm_def.sh Mon Dec 13 14:46:51 2010 -0800 @@ -1,7 +1,7 @@ #!/bin/sh # If we're cross compiling use that path for nm -if [ "$ALT_COMPILER_PATH" != "" ]; then +if [ "$CROSS_COMPILE_ARCH" != "" ]; then NM=$ALT_COMPILER_PATH/nm else NM=nm diff -r 0d4395745860 -r 06ba96862949 make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Fri Dec 10 18:05:39 2010 -0800 +++ b/make/linux/makefiles/gcc.make Mon Dec 13 14:46:51 2010 -0800 @@ -25,7 +25,9 @@ #------------------------------------------------------------------------ # CC, CPP & AS -ifdef ALT_COMPILER_PATH +# When cross-compiling the ALT_COMPILER_PATH points +# to the cross-compilation toolset +ifdef CROSS_COMPILE_ARCH CPP = $(ALT_COMPILER_PATH)/g++ CC = $(ALT_COMPILER_PATH)/gcc else diff -r 0d4395745860 -r 06ba96862949 make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Fri Dec 10 18:05:39 2010 -0800 +++ b/make/solaris/makefiles/vm.make Mon Dec 13 14:46:51 2010 -0800 @@ -106,17 +106,17 @@ # Not sure what the 'designed for' comment is referring too above. # The order may not be too significant anymore, but I have placed this # older libm before libCrun, just to make sure it's found and used first. -LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc +LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc -ldemangle else ifeq ($(COMPILER_REV_NUMERIC), 502) # SC6.1 has it's own libm.so: specifying anything else provokes a name conflict. -LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor +LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor -ldemangle else -LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor +LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor -ldemangle endif # 502 endif # 505 else -LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc +LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle endif # sparcWorks # By default, link the *.o into the library, not the executable. diff -r 0d4395745860 -r 06ba96862949 src/os/linux/vm/decoder_linux.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/linux/vm/decoder_linux.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "prims/jvm.h" +#include "utilities/decoder.hpp" + +#include + +bool Decoder::demangle(const char* symbol, char *buf, int buflen) { + int status; + char* result; + size_t size = (size_t)buflen; + + // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, + // __cxa_demangle will call system "realloc" for additional memory, which + // may use different malloc/realloc mechanism that allocates 'buf'. + if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { + jio_snprintf(buf, buflen, "%s", result); + // call c library's free + ::free(result); + return true; + } + return false; +} diff -r 0d4395745860 -r 06ba96862949 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/os/linux/vm/os_linux.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -59,6 +59,7 @@ #include "services/attachListener.hpp" #include "services/runtimeService.hpp" #include "thread_linux.inline.hpp" +#include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" @@ -1688,14 +1689,23 @@ Dl_info dlinfo; if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) { - if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); - if (offset) *offset = addr - (address)dlinfo.dli_saddr; + if (buf != NULL) { + if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) { + jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); + } + } + if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; return true; - } else { - if (buf) buf[0] = '\0'; - if (offset) *offset = -1; - return false; + } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { + if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), + dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + return true; + } } + + if (buf != NULL) buf[0] = '\0'; + if (offset != NULL) *offset = -1; + return false; } struct _address_to_library_name { diff -r 0d4395745860 -r 06ba96862949 src/os/solaris/vm/decoder_solaris.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/solaris/vm/decoder_solaris.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "utilities/decoder.hpp" + +#include + +bool Decoder::demangle(const char* symbol, char *buf, int buflen) { + return !cplus_demangle(symbol, buf, (size_t)buflen); +} diff -r 0d4395745860 -r 06ba96862949 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -57,6 +57,7 @@ #include "services/attachListener.hpp" #include "services/runtimeService.hpp" #include "thread_solaris.inline.hpp" +#include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" @@ -1969,27 +1970,42 @@ Sym * info; if (dladdr1_func((void *)addr, &dlinfo, (void **)&info, RTLD_DL_SYMENT)) { - if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); - if (offset) *offset = addr - (address)dlinfo.dli_saddr; - - // check if the returned symbol really covers addr - return ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr); - } else { - if (buf) buf[0] = '\0'; - if (offset) *offset = -1; - return false; + if ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr) { + if (buf != NULL) { + if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) + jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); + } + if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; + return true; + } } + if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { + if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), + dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { + return true; + } + } + if (buf != NULL) buf[0] = '\0'; + if (offset != NULL) *offset = -1; + return false; } else { // no, only dladdr is available - if(dladdr((void *)addr, &dlinfo)) { - if (buf) jio_snprintf(buf, buflen, dlinfo.dli_sname); - if (offset) *offset = addr - (address)dlinfo.dli_saddr; + if (dladdr((void *)addr, &dlinfo)) { + if (buf != NULL) { + if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) + jio_snprintf(buf, buflen, dlinfo.dli_sname); + } + if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; + return true; + } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { + if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), + dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { return true; - } else { - if (buf) buf[0] = '\0'; - if (offset) *offset = -1; - return false; + } } + if (buf != NULL) buf[0] = '\0'; + if (offset != NULL) *offset = -1; + return false; } } diff -r 0d4395745860 -r 06ba96862949 src/os/windows/vm/decoder_windows.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/windows/vm/decoder_windows.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "prims/jvm.h" +#include "utilities/decoder.hpp" + +HMODULE Decoder::_dbghelp_handle = NULL; +bool Decoder::_can_decode_in_vm = false; +pfn_SymGetSymFromAddr64 Decoder::_pfnSymGetSymFromAddr64 = NULL; +pfn_UndecorateSymbolName Decoder::_pfnUndecorateSymbolName = NULL; + +void Decoder::initialize() { + if (!_initialized) { + _initialized = true; + + HMODULE handle = ::LoadLibrary("dbghelp.dll"); + if (!handle) { + _decoder_status = helper_not_found; + return; + } + + _dbghelp_handle = handle; + + pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions"); + pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize"); + _pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64"); + _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)GetProcAddress(handle, "UnDecorateSymbolName"); + + if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) { + _pfnSymGetSymFromAddr64 = NULL; + _pfnUndecorateSymbolName = NULL; + ::FreeLibrary(handle); + _dbghelp_handle = NULL; + _decoder_status = helper_func_error; + return; + } + + _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + if (!_pfnSymInitialize(GetCurrentProcess(), NULL, TRUE)) { + _pfnSymGetSymFromAddr64 = NULL; + _pfnUndecorateSymbolName = NULL; + ::FreeLibrary(handle); + _dbghelp_handle = NULL; + _decoder_status = helper_init_error; + return; + } + + // find out if jvm.dll contains private symbols, by decoding + // current function and comparing the result + address addr = (address)Decoder::initialize; + char buf[MAX_PATH]; + if (decode(addr, buf, sizeof(buf), NULL) == no_error) { + _can_decode_in_vm = !strcmp(buf, "Decoder::initialize"); + } + } +} + +void Decoder::uninitialize() { + assert(_initialized, "Decoder not yet initialized"); + _pfnSymGetSymFromAddr64 = NULL; + _pfnUndecorateSymbolName = NULL; + if (_dbghelp_handle != NULL) { + ::FreeLibrary(_dbghelp_handle); + } + _initialized = false; +} + +bool Decoder::can_decode_C_frame_in_vm() { + initialize(); + return _can_decode_in_vm; +} + + +Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int *offset) { + assert(_initialized, "Decoder not yet initialized"); + if (_pfnSymGetSymFromAddr64 != NULL) { + PIMAGEHLP_SYMBOL64 pSymbol; + char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; + pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo; + pSymbol->MaxNameLength = MAX_PATH; + pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + DWORD64 displacement; + if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { + if (buf != NULL) { + if (!demangle(pSymbol->Name, buf, buflen)) { + jio_snprintf(buf, buflen, "%s", pSymbol->Name); + } + } + if (offset != NULL) *offset = (int)displacement; + return no_error; + } + } + return helper_not_found; +} + +bool Decoder::demangle(const char* symbol, char *buf, int buflen) { + assert(_initialized, "Decoder not yet initialized"); + return _pfnUndecorateSymbolName != NULL && + _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); +} + diff -r 0d4395745860 -r 06ba96862949 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/os/windows/vm/os_windows.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -62,6 +62,7 @@ #include "services/attachListener.hpp" #include "services/runtimeService.hpp" #include "thread_windows.inline.hpp" +#include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" @@ -1365,12 +1366,11 @@ bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset) { - // Unimplemented on Windows - in order to use SymGetSymFromAddr(), - // we need to initialize imagehlp/dbghelp, then load symbol table - // for every module. That's too much work to do after a fatal error. - // For an example on how to implement this function, see 1.4.2. - if (offset) *offset = -1; - if (buf) buf[0] = '\0'; + if (Decoder::decode(addr, buf, buflen, offset) == Decoder::no_error) { + return true; + } + if (offset != NULL) *offset = -1; + if (buf != NULL) buf[0] = '\0'; return false; } diff -r 0d4395745860 -r 06ba96862949 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/code/nmethod.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -619,8 +619,8 @@ OopMapSet* oop_maps ) : CodeBlob("native nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), - _compiled_synchronized_native_basic_lock_owner_sp_offset(basic_lock_owner_sp_offset), - _compiled_synchronized_native_basic_lock_sp_offset(basic_lock_sp_offset) + _native_receiver_sp_offset(basic_lock_owner_sp_offset), + _native_basic_lock_sp_offset(basic_lock_sp_offset) { { debug_only(No_Safepoint_Verifier nsv;) @@ -696,8 +696,8 @@ int frame_size) : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL), - _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), - _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) + _native_receiver_sp_offset(in_ByteSize(-1)), + _native_basic_lock_sp_offset(in_ByteSize(-1)) { { debug_only(No_Safepoint_Verifier nsv;) @@ -790,8 +790,8 @@ ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), - _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), - _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) + _native_receiver_sp_offset(in_ByteSize(-1)), + _native_basic_lock_sp_offset(in_ByteSize(-1)) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); { diff -r 0d4395745860 -r 06ba96862949 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/code/nmethod.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -210,7 +210,7 @@ ExceptionCache *_exception_cache; PcDescCache _pc_desc_cache; - // These are only used for compiled synchronized native methods to + // These are used for compiled synchronized native methods to // locate the owner and stack slot for the BasicLock so that we can // properly revoke the bias of the owner if necessary. They are // needed because there is no debug information for compiled native @@ -220,8 +220,10 @@ // sharing between platforms. Note that currently biased locking // will never cause Class instances to be biased but this code // handles the static synchronized case as well. - ByteSize _compiled_synchronized_native_basic_lock_owner_sp_offset; - ByteSize _compiled_synchronized_native_basic_lock_sp_offset; + // JVMTI's GetLocalInstance() also uses these offsets to find the receiver + // for non-static native wrapper frames. + ByteSize _native_receiver_sp_offset; + ByteSize _native_basic_lock_sp_offset; friend class nmethodLocker; @@ -676,11 +678,11 @@ bool is_patchable_at(address instr_address); // UseBiasedLocking support - ByteSize compiled_synchronized_native_basic_lock_owner_sp_offset() { - return _compiled_synchronized_native_basic_lock_owner_sp_offset; + ByteSize native_receiver_sp_offset() { + return _native_receiver_sp_offset; } - ByteSize compiled_synchronized_native_basic_lock_sp_offset() { - return _compiled_synchronized_native_basic_lock_sp_offset; + ByteSize native_basic_lock_sp_offset() { + return _native_basic_lock_sp_offset; } // support for code generation diff -r 0d4395745860 -r 06ba96862949 src/share/vm/oops/instanceRefKlass.cpp --- a/src/share/vm/oops/instanceRefKlass.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/oops/instanceRefKlass.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -457,6 +457,11 @@ } } +bool instanceRefKlass::owns_pending_list_lock(JavaThread* thread) { + Handle h_lock(thread, java_lang_ref_Reference::pending_list_lock()); + return ObjectSynchronizer::current_thread_holds_lock(thread, h_lock); +} + void instanceRefKlass::acquire_pending_list_lock(BasicLock *pending_list_basic_lock) { // we may enter this with pending exception set PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument diff -r 0d4395745860 -r 06ba96862949 src/share/vm/oops/instanceRefKlass.hpp --- a/src/share/vm/oops/instanceRefKlass.hpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/oops/instanceRefKlass.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -89,6 +89,7 @@ static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock); static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock); + static bool owns_pending_list_lock(JavaThread* thread); // Update non-static oop maps so 'referent', 'nextPending' and // 'discovered' will look like non-oops diff -r 0d4395745860 -r 06ba96862949 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/oops/klassVtable.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -518,18 +518,21 @@ bool klassVtable::is_miranda(methodOop m, objArrayOop class_methods, klassOop super) { symbolOop name = m->name(); symbolOop signature = m->signature(); + if (instanceKlass::find_method(class_methods, name, signature) == NULL) { - // did not find it in the method table of the current class + // did not find it in the method table of the current class if (super == NULL) { // super doesn't exist return true; - } else { - if (instanceKlass::cast(super)->lookup_method(name, signature) == NULL) { - // super class hierarchy does not implement it - return true; - } + } + + methodOop mo = instanceKlass::cast(super)->lookup_method(name, signature); + if (mo == NULL || mo->access_flags().is_private() ) { + // super class hierarchy does not implement it or protection is different + return true; } } + return false; } diff -r 0d4395745860 -r 06ba96862949 src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/oops/methodOop.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -309,6 +309,12 @@ // Build a methodDataOop object to hold information about this method // collected in the interpreter. void methodOopDesc::build_interpreter_method_data(methodHandle method, TRAPS) { + // Do not profile method if current thread holds the pending list lock, + // which avoids deadlock for acquiring the MethodData_lock. + if (instanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { + return; + } + // Grab a lock here to prevent multiple // methodDataOops from being created. MutexLocker ml(MethodData_lock, THREAD); diff -r 0d4395745860 -r 06ba96862949 src/share/vm/prims/jvmti.xml --- a/src/share/vm/prims/jvmti.xml Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/prims/jvmti.xml Mon Dec 13 14:46:51 2010 -0800 @@ -5649,6 +5649,45 @@ + + Get Local Instance + + This function can be used to retrieve the value of the local object + variable at slot 0 (the "this" object) from non-static + frames. This function can retrieve the "this" object from + native method frames, whereas GetLocalObject() would + return JVMTI_ERROR_OPAQUE_FRAME in those cases. + + new + + + + + + + + The thread of the frame containing the variable's value. + + + + + + The depth of the frame containing the variable's value. + + + + + + On return, points to the variable's value. + + + + + + If the specified frame is a static method frame. + + + Get Local Variable - Int diff -r 0d4395745860 -r 06ba96862949 src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/prims/jvmtiEnv.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -1796,6 +1796,29 @@ } } /* end GetLocalObject */ +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value - pre-checked for NULL +jvmtiError +JvmtiEnv::GetLocalInstance(JavaThread* java_thread, jint depth, jobject* value){ + JavaThread* current_thread = JavaThread::current(); + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm(current_thread); + + VM_GetReceiver op(java_thread, current_thread, depth); + VMThread::execute(&op); + jvmtiError err = op.result(); + if (err != JVMTI_ERROR_NONE) { + return err; + } else { + *value = op.value().l; + return JVMTI_ERROR_NONE; + } +} /* end GetLocalInstance */ + // Threads_lock NOT held, java_thread not protected by lock // java_thread - pre-checked diff -r 0d4395745860 -r 06ba96862949 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/prims/jvmtiImpl.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -586,7 +586,6 @@ { } - vframe *VM_GetOrSetLocal::get_vframe() { if (!_thread->has_last_Java_frame()) { return NULL; @@ -609,7 +608,7 @@ } javaVFrame *jvf = (javaVFrame*)vf; - if (!vf->is_java_frame() || jvf->method()->is_native()) { + if (!vf->is_java_frame()) { _result = JVMTI_ERROR_OPAQUE_FRAME; return NULL; } @@ -740,6 +739,15 @@ _jvf = get_java_vframe(); NULL_CHECK(_jvf, false); + if (_jvf->method()->is_native()) { + if (getting_receiver() && !_jvf->method()->is_static()) { + return true; + } else { + _result = JVMTI_ERROR_OPAQUE_FRAME; + return false; + } + } + if (!check_slot_type(_jvf)) { return false; } @@ -781,40 +789,46 @@ HandleMark hm; switch (_type) { - case T_INT: locals->set_int_at (_index, _value.i); break; - case T_LONG: locals->set_long_at (_index, _value.j); break; - case T_FLOAT: locals->set_float_at (_index, _value.f); break; - case T_DOUBLE: locals->set_double_at(_index, _value.d); break; - case T_OBJECT: { - Handle ob_h(JNIHandles::resolve_external_guard(_value.l)); - locals->set_obj_at (_index, ob_h); - break; - } - default: ShouldNotReachHere(); + case T_INT: locals->set_int_at (_index, _value.i); break; + case T_LONG: locals->set_long_at (_index, _value.j); break; + case T_FLOAT: locals->set_float_at (_index, _value.f); break; + case T_DOUBLE: locals->set_double_at(_index, _value.d); break; + case T_OBJECT: { + Handle ob_h(JNIHandles::resolve_external_guard(_value.l)); + locals->set_obj_at (_index, ob_h); + break; + } + default: ShouldNotReachHere(); } _jvf->set_locals(locals); } else { - StackValueCollection *locals = _jvf->locals(); + if (_jvf->method()->is_native() && _jvf->is_compiled_frame()) { + assert(getting_receiver(), "Can only get here when getting receiver"); + oop receiver = _jvf->fr().get_native_receiver(); + _value.l = JNIHandles::make_local(_calling_thread, receiver); + } else { + StackValueCollection *locals = _jvf->locals(); - if (locals->at(_index)->type() == T_CONFLICT) { - memset(&_value, 0, sizeof(_value)); - _value.l = NULL; - return; - } + if (locals->at(_index)->type() == T_CONFLICT) { + memset(&_value, 0, sizeof(_value)); + _value.l = NULL; + return; + } - switch (_type) { - case T_INT: _value.i = locals->int_at (_index); break; - case T_LONG: _value.j = locals->long_at (_index); break; - case T_FLOAT: _value.f = locals->float_at (_index); break; - case T_DOUBLE: _value.d = locals->double_at(_index); break; - case T_OBJECT: { - // Wrap the oop to be returned in a local JNI handle since - // oops_do() no longer applies after doit() is finished. - oop obj = locals->obj_at(_index)(); - _value.l = JNIHandles::make_local(_calling_thread, obj); - break; - } - default: ShouldNotReachHere(); + switch (_type) { + case T_INT: _value.i = locals->int_at (_index); break; + case T_LONG: _value.j = locals->long_at (_index); break; + case T_FLOAT: _value.f = locals->float_at (_index); break; + case T_DOUBLE: _value.d = locals->double_at(_index); break; + case T_OBJECT: { + // Wrap the oop to be returned in a local JNI handle since + // oops_do() no longer applies after doit() is finished. + oop obj = locals->obj_at(_index)(); + _value.l = JNIHandles::make_local(_calling_thread, obj); + break; + } + default: ShouldNotReachHere(); + } } } } @@ -825,6 +839,10 @@ } +VM_GetReceiver::VM_GetReceiver( + JavaThread* thread, JavaThread* caller_thread, jint depth) + : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {} + ///////////////////////////////////////////////////////////////////////////////////////// // diff -r 0d4395745860 -r 06ba96862949 src/share/vm/prims/jvmtiImpl.hpp --- a/src/share/vm/prims/jvmtiImpl.hpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/prims/jvmtiImpl.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -355,7 +355,7 @@ // to the thread simultaneously. // class VM_GetOrSetLocal : public VM_Operation { -private: + protected: JavaThread* _thread; JavaThread* _calling_thread; jint _depth; @@ -365,6 +365,10 @@ javaVFrame* _jvf; bool _set; + // It is possible to get the receiver out of a non-static native wrapper + // frame. Use VM_GetReceiver to do this. + virtual bool getting_receiver() const { return false; } + jvmtiError _result; vframe* get_vframe(); @@ -395,6 +399,15 @@ static bool is_assignable(const char* ty_sign, Klass* klass, Thread* thread); }; +class VM_GetReceiver : public VM_GetOrSetLocal { + protected: + virtual bool getting_receiver() const { return true; } + + public: + VM_GetReceiver(JavaThread* thread, JavaThread* calling_thread, jint depth); + const char* name() const { return "get receiver"; } +}; + /////////////////////////////////////////////////////////////// // diff -r 0d4395745860 -r 06ba96862949 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/runtime/frame.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -41,6 +41,8 @@ #include "runtime/signature.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" +#include "utilities/decoder.hpp" + #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" #endif @@ -652,7 +654,7 @@ // names if pc is within jvm.dll or libjvm.so, because JVM only has // JVM_xxxx and a few other symbols in the dynamic symbol table. Do this // only for native libraries. - if (!in_vm) { + if (!in_vm || Decoder::can_decode_C_frame_in_vm()) { found = os::dll_address_to_function_name(pc, buf, buflen, &offset); if (found) { @@ -1071,28 +1073,20 @@ } } -BasicLock* frame::compiled_synchronized_native_monitor(nmethod* nm) { - if (nm == NULL) { - assert(_cb != NULL && _cb->is_nmethod() && - nm->method()->is_native() && - nm->method()->is_synchronized(), - "should not call this otherwise"); - nm = (nmethod*) _cb; - } - int byte_offset = in_bytes(nm->compiled_synchronized_native_basic_lock_sp_offset()); +BasicLock* frame::get_native_monitor() { + nmethod* nm = (nmethod*)_cb; + assert(_cb != NULL && _cb->is_nmethod() && nm->method()->is_native(), + "Should not call this unless it's a native nmethod"); + int byte_offset = in_bytes(nm->native_basic_lock_sp_offset()); assert(byte_offset >= 0, "should not see invalid offset"); return (BasicLock*) &sp()[byte_offset / wordSize]; } -oop frame::compiled_synchronized_native_monitor_owner(nmethod* nm) { - if (nm == NULL) { - assert(_cb != NULL && _cb->is_nmethod() && - nm->method()->is_native() && - nm->method()->is_synchronized(), - "should not call this otherwise"); - nm = (nmethod*) _cb; - } - int byte_offset = in_bytes(nm->compiled_synchronized_native_basic_lock_owner_sp_offset()); +oop frame::get_native_receiver() { + nmethod* nm = (nmethod*)_cb; + assert(_cb != NULL && _cb->is_nmethod() && nm->method()->is_native(), + "Should not call this unless it's a native nmethod"); + int byte_offset = in_bytes(nm->native_receiver_sp_offset()); assert(byte_offset >= 0, "should not see invalid offset"); oop owner = ((oop*) sp())[byte_offset / wordSize]; assert( Universe::heap()->is_in(owner), "bad receiver" ); diff -r 0d4395745860 -r 06ba96862949 src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/runtime/frame.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -254,10 +254,10 @@ // Return the monitor owner and BasicLock for compiled synchronized // native methods so that biased locking can revoke the receiver's - // bias if necessary. Takes optional nmethod for this frame as - // argument to avoid performing repeated lookups in code cache. - BasicLock* compiled_synchronized_native_monitor (nmethod* nm = NULL); - oop compiled_synchronized_native_monitor_owner(nmethod* nm = NULL); + // bias if necessary. This is also used by JVMTI's GetLocalInstance method + // (via VM_GetReceiver) to retrieve the receiver from a native wrapper frame. + BasicLock* get_native_monitor(); + oop get_native_receiver(); // Find receiver for an invoke when arguments are just pushed on stack (i.e., callee stack-frame is // not setup) diff -r 0d4395745860 -r 06ba96862949 src/share/vm/runtime/vframe_hp.cpp --- a/src/share/vm/runtime/vframe_hp.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/runtime/vframe_hp.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -207,8 +207,8 @@ GrowableArray *monitors = new GrowableArray(1); // Casting away const frame& fr = (frame&) _fr; - MonitorInfo* info = new MonitorInfo(fr.compiled_synchronized_native_monitor_owner(nm), - fr.compiled_synchronized_native_monitor(nm), false, false); + MonitorInfo* info = new MonitorInfo( + fr.get_native_receiver(), fr.get_native_monitor(), false, false); monitors->push(info); return monitors; } diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/decoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/decoder.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "prims/jvm.h" +#include "utilities/decoder.hpp" + +Decoder::decoder_status Decoder::_decoder_status = Decoder::no_error; +bool Decoder::_initialized = false; + +#ifndef _WINDOWS + +// Implementation of common functionalities among Solaris and Linux +#include "utilities/elfFile.hpp" + +ElfFile* Decoder::_opened_elf_files = NULL; + +bool Decoder::can_decode_C_frame_in_vm() { + return true; +} + +void Decoder::initialize() { + _initialized = true; +} + +void Decoder::uninitialize() { + if (_opened_elf_files != NULL) { + delete _opened_elf_files; + _opened_elf_files = NULL; + } + _initialized = false; +} + +Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) { + if (_decoder_status != no_error) { + return _decoder_status; + } + + ElfFile* file = get_elf_file(filepath); + if (_decoder_status != no_error) { + return _decoder_status; + } + + const char* symbol = file->decode(addr, offset); + if (file->get_status() == out_of_memory) { + _decoder_status = out_of_memory; + return _decoder_status; + } else if (symbol != NULL) { + if (!demangle(symbol, buf, buflen)) { + jio_snprintf(buf, buflen, "%s", symbol); + } + return no_error; + } else { + return symbol_not_found; + } +} + +ElfFile* Decoder::get_elf_file(const char* filepath) { + if (_decoder_status != no_error) { + return NULL; + } + ElfFile* file = _opened_elf_files; + while (file != NULL) { + if (file->same_elf_file(filepath)) { + return file; + } + file = file->m_next; + } + + file = new ElfFile(filepath); + if (file == NULL) { + _decoder_status = out_of_memory; + } + if (_opened_elf_files != NULL) { + file->m_next = _opened_elf_files; + } + + _opened_elf_files = file; + return file; +} + +#endif + diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/decoder.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/decoder.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#ifndef __DECODER_HPP +#define __DECODER_HPP + +#include "memory/allocation.hpp" + +#ifdef _WINDOWS +#include +#include + +// functions needed for decoding symbols +typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD); +typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL); +typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); +typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD); + +#else + +class ElfFile; + +#endif // _WINDOWS + + +class Decoder: public StackObj { + + public: + // status code for decoding native C frame + enum decoder_status { + no_error, // successfully decoded frames + out_of_memory, // out of memory + file_invalid, // invalid elf file + file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map + helper_not_found, // could not load dbghelp.dll (Windows only) + helper_func_error, // decoding functions not found (Windows only) + helper_init_error, // SymInitialize failed (Windows only) + symbol_not_found // could not find the symbol + }; + + public: + Decoder() { initialize(); }; + ~Decoder() { uninitialize(); }; + + static bool can_decode_C_frame_in_vm(); + + static void initialize(); + static void uninitialize(); + +#ifdef _WINDOWS + static decoder_status decode(address addr, char *buf, int buflen, int *offset); +#else + static decoder_status decode(address addr, const char* filepath, char *buf, int buflen, int *offset); +#endif + + static bool demangle(const char* symbol, char *buf, int buflen); + + static decoder_status get_status() { return _decoder_status; }; + +#ifndef _WINDOWS + private: + static ElfFile* get_elf_file(const char* filepath); +#endif // _WINDOWS + + + private: + static decoder_status _decoder_status; + static bool _initialized; + +#ifdef _WINDOWS + static HMODULE _dbghelp_handle; + static bool _can_decode_in_vm; + static pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64; + static pfn_UndecorateSymbolName _pfnUndecorateSymbolName; +#else + static ElfFile* _opened_elf_files; +#endif // _WINDOWS +}; + +#endif // __DECODER_HPP diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfFile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfFile.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#ifndef _WINDOWS + +#include +#include +#include + +#include "memory/allocation.inline.hpp" +#include "utilities/decoder.hpp" +#include "utilities/elfFile.hpp" +#include "utilities/elfStringTable.hpp" +#include "utilities/elfSymbolTable.hpp" + + +ElfFile::ElfFile(const char* filepath) { + assert(filepath, "null file path"); + memset(&m_elfHdr, 0, sizeof(m_elfHdr)); + m_string_tables = NULL; + m_symbol_tables = NULL; + m_next = NULL; + m_status = Decoder::no_error; + + int len = strlen(filepath) + 1; + m_filepath = NEW_C_HEAP_ARRAY(char, len); + if (m_filepath != NULL) { + strcpy((char*)m_filepath, filepath); + m_file = fopen(filepath, "r"); + if (m_file != NULL) { + load_tables(); + } else { + m_status = Decoder::file_not_found; + } + } else { + m_status = Decoder::out_of_memory; + } +} + +ElfFile::~ElfFile() { + if (m_string_tables != NULL) { + delete m_string_tables; + } + + if (m_symbol_tables != NULL) { + delete m_symbol_tables; + } + + if (m_file != NULL) { + fclose(m_file); + } + + if (m_filepath != NULL) { + FREE_C_HEAP_ARRAY(char, m_filepath); + } + + if (m_next != NULL) { + delete m_next; + } +}; + + +//Check elf header to ensure the file is valid. +bool ElfFile::is_elf_file(Elf_Ehdr& hdr) { + return (ELFMAG0 == hdr.e_ident[EI_MAG0] && + ELFMAG1 == hdr.e_ident[EI_MAG1] && + ELFMAG2 == hdr.e_ident[EI_MAG2] && + ELFMAG3 == hdr.e_ident[EI_MAG3] && + ELFCLASSNONE != hdr.e_ident[EI_CLASS] && + ELFDATANONE != hdr.e_ident[EI_DATA]); +} + +bool ElfFile::load_tables() { + assert(m_file, "file not open"); + assert(m_status == Decoder::no_error, "already in error"); + + // read elf file header + if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { + m_status = Decoder::file_invalid; + return false; + } + + if (!is_elf_file(m_elfHdr)) { + m_status = Decoder::file_invalid; + return false; + } + + // walk elf file's section headers, and load string tables + Elf_Shdr shdr; + if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { + if (m_status != Decoder::no_error) return false; + + for (int index = 0; index < m_elfHdr.e_shnum; index ++) { + if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { + m_status = Decoder::file_invalid; + return false; + } + // string table + if (shdr.sh_type == SHT_STRTAB) { + ElfStringTable* table = new ElfStringTable(m_file, shdr, index); + if (table == NULL) { + m_status = Decoder::out_of_memory; + return false; + } + add_string_table(table); + } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { + ElfSymbolTable* table = new ElfSymbolTable(m_file, shdr); + if (table == NULL) { + m_status = Decoder::out_of_memory; + return false; + } + add_symbol_table(table); + } + } + } + return true; +} + +const char* ElfFile::decode(address addr, int* offset) { + // something already went wrong, just give up + if (m_status != Decoder::no_error) { + return NULL; + } + + ElfSymbolTable* symbol_table = m_symbol_tables; + int string_table_index; + int pos_in_string_table; + int off = INT_MAX; + bool found_symbol = false; + while (symbol_table != NULL) { + if (Decoder::no_error == symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) { + found_symbol = true; + } + symbol_table = symbol_table->m_next; + } + if (!found_symbol) return NULL; + + ElfStringTable* string_table = get_string_table(string_table_index); + if (string_table == NULL) { + m_status = Decoder::file_invalid; + return NULL; + } + if (offset) *offset = off; + return string_table->string_at(pos_in_string_table); +} + + +void ElfFile::add_symbol_table(ElfSymbolTable* table) { + if (m_symbol_tables == NULL) { + m_symbol_tables = table; + } else { + table->m_next = m_symbol_tables; + m_symbol_tables = table; + } +} + +void ElfFile::add_string_table(ElfStringTable* table) { + if (m_string_tables == NULL) { + m_string_tables = table; + } else { + table->m_next = m_string_tables; + m_string_tables = table; + } +} + +ElfStringTable* ElfFile::get_string_table(int index) { + ElfStringTable* p = m_string_tables; + while (p != NULL) { + if (p->index() == index) return p; + p = p->m_next; + } + return NULL; +} + +#endif // _WINDOWS diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfFile.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfFile.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef __ELF_FILE_HPP +#define __ELF_FILE_HPP + +#ifndef _WINDOWS + +#include +#include + +#ifdef _LP64 + +typedef Elf64_Half Elf_Half; +typedef Elf64_Word Elf_Word; +typedef Elf64_Off Elf_Off; +typedef Elf64_Addr Elf_Addr; + +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Sym Elf_Sym; + +#define ELF_ST_TYPE ELF64_ST_TYPE + +#else + +typedef Elf32_Half Elf_Half; +typedef Elf32_Word Elf_Word; +typedef Elf32_Off Elf_Off; +typedef Elf32_Addr Elf_Addr; + + +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Sym Elf_Sym; + +#define ELF_ST_TYPE ELF32_ST_TYPE +#endif + +#include "globalDefinitions.hpp" +#include "memory/allocation.hpp" +#include "utilities/decoder.hpp" + + +class ElfStringTable; +class ElfSymbolTable; + + +// On Solaris/Linux platforms, libjvm.so does contain all private symbols. +// ElfFile is basically an elf file parser, which can lookup the symbol +// that is the nearest to the given address. +// Beware, this code is called from vm error reporting code, when vm is already +// in "error" state, so there are scenarios, lookup will fail. We want this +// part of code to be very defensive, and bait out if anything went wrong. + +class ElfFile: public CHeapObj { + friend class Decoder; + public: + ElfFile(const char* filepath); + ~ElfFile(); + + const char* decode(address addr, int* offset); + const char* filepath() { + return m_filepath; + } + + bool same_elf_file(const char* filepath) { + assert(filepath, "null file path"); + assert(m_filepath, "already out of memory"); + return (m_filepath && !strcmp(filepath, m_filepath)); + } + + Decoder::decoder_status get_status() { + return m_status; + } + + private: + // sanity check, if the file is a real elf file + bool is_elf_file(Elf_Ehdr&); + + // load string tables from the elf file + bool load_tables(); + + // string tables are stored in a linked list + void add_string_table(ElfStringTable* table); + + // symbol tables are stored in a linked list + void add_symbol_table(ElfSymbolTable* table); + + // return a string table at specified section index + ElfStringTable* get_string_table(int index); + + // look up an address and return the nearest symbol + const char* look_up(Elf_Shdr shdr, address addr, int* offset); + + protected: + ElfFile* m_next; + + private: + // file + const char* m_filepath; + FILE* m_file; + + // Elf header + Elf_Ehdr m_elfHdr; + + // symbol tables + ElfSymbolTable* m_symbol_tables; + + // string tables + ElfStringTable* m_string_tables; + + Decoder::decoder_status m_status; +}; + +#endif // _WINDOWS + +#endif // __ELF_FILE_HPP + diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfStringTable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfStringTable.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#ifndef _WINDOWS + +#include "memory/allocation.inline.hpp" +#include "utilities/elfStringTable.hpp" + +// We will try to load whole string table into memory if we can. +// Otherwise, fallback to more expensive file operation. +ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) { + assert(file, "null file handle"); + m_table = NULL; + m_index = index; + m_next = NULL; + m_file = file; + m_status = Decoder::no_error; + + // try to load the string table + long cur_offset = ftell(file); + m_table = (char*)NEW_C_HEAP_ARRAY(char, shdr.sh_size); + if (m_table != NULL) { + // if there is an error, mark the error + if (fseek(file, shdr.sh_offset, SEEK_SET) || + fread((void*)m_table, shdr.sh_size, 1, file) != 1 || + fseek(file, cur_offset, SEEK_SET)) { + m_status = Decoder::file_invalid; + FREE_C_HEAP_ARRAY(char, m_table); + m_table = NULL; + } + } else { + memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); + } +} + +ElfStringTable::~ElfStringTable() { + if (m_table != NULL) { + FREE_C_HEAP_ARRAY(char, m_table); + } + + if (m_next != NULL) { + delete m_next; + } +} + +const char* ElfStringTable::string_at(int pos) { + if (m_status != Decoder::no_error) { + return NULL; + } + if (m_table != NULL) { + return (const char*)(m_table + pos); + } else { + long cur_pos = ftell(m_file); + if (cur_pos == -1 || + fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) || + fread(m_symbol, 1, MAX_SYMBOL_LEN, m_file) <= 0 || + fseek(m_file, cur_pos, SEEK_SET)) { + m_status = Decoder::file_invalid; + return NULL; + } + return (const char*)m_symbol; + } +} + +#endif // _WINDOWS + diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfStringTable.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfStringTable.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef __ELF_STRING_TABLE_HPP +#define __ELF_STRING_TABLE_HPP + +#ifndef _WINDOWS + +#include "memory/allocation.hpp" +#include "utilities/decoder.hpp" +#include "utilities/elfFile.hpp" + + +// The string table represents a string table section in an elf file. +// Whenever there is enough memory, it will load whole string table as +// one blob. Otherwise, it will load string from file when requested. + +#define MAX_SYMBOL_LEN 256 + +class ElfStringTable: CHeapObj { + friend class ElfFile; + public: + ElfStringTable(FILE* file, Elf_Shdr shdr, int index); + ~ElfStringTable(); + + // section index + int index() { return m_index; }; + + // get string at specified offset + const char* string_at(int offset); + + // get status code + Decoder::decoder_status get_status() { return m_status; }; + + protected: + ElfStringTable* m_next; + + // section index + int m_index; + + // holds complete string table if can + // allocate enough memory + const char* m_table; + + // file contains string table + FILE* m_file; + + // section header + Elf_Shdr m_shdr; + + // buffer for reading individual string + char m_symbol[MAX_SYMBOL_LEN]; + + // error code + Decoder::decoder_status m_status; +}; + +#endif // _WINDOWS + +#endif // __ELF_STRING_TABLE_HPP + diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfSymbolTable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfSymbolTable.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#ifndef _WINDOWS + +#include "memory/allocation.inline.hpp" +#include "utilities/elfSymbolTable.hpp" + +ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) { + assert(file, "null file handle"); + m_symbols = NULL; + m_next = NULL; + m_file = file; + m_status = Decoder::no_error; + + // try to load the string table + long cur_offset = ftell(file); + if (cur_offset != -1) { + m_symbols = (Elf_Sym*)NEW_C_HEAP_ARRAY(char, shdr.sh_size); + if (m_symbols) { + if (fseek(file, shdr.sh_offset, SEEK_SET) || + fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 || + fseek(file, cur_offset, SEEK_SET)) { + m_status = Decoder::file_invalid; + FREE_C_HEAP_ARRAY(char, m_symbols); + m_symbols = NULL; + } + } + if (m_status == Decoder::no_error) { + memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); + } + } else { + m_status = Decoder::file_invalid; + } +} + +ElfSymbolTable::~ElfSymbolTable() { + if (m_symbols != NULL) { + FREE_C_HEAP_ARRAY(char, m_symbols); + } + + if (m_next != NULL) { + delete m_next; + } +} + +Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) { + assert(stringtableIndex, "null string table index pointer"); + assert(posIndex, "null string table offset pointer"); + assert(offset, "null offset pointer"); + + if (m_status != Decoder::no_error) { + return m_status; + } + + address pc = 0; + size_t sym_size = sizeof(Elf_Sym); + assert((m_shdr.sh_size % sym_size) == 0, "check size"); + int count = m_shdr.sh_size / sym_size; + if (m_symbols != NULL) { + for (int index = 0; index < count; index ++) { + if (STT_FUNC == ELF_ST_TYPE(m_symbols[index].st_info)) { + address sym_addr = (address)m_symbols[index].st_value; + if (sym_addr < addr && (addr - sym_addr) < *offset) { + pc = (address)m_symbols[index].st_value; + *offset = (int)(addr - pc); + *posIndex = m_symbols[index].st_name; + *stringtableIndex = m_shdr.sh_link; + } + } + } + } else { + long cur_pos; + if ((cur_pos = ftell(m_file)) == -1 || + fseek(m_file, m_shdr.sh_offset, SEEK_SET)) { + m_status = Decoder::file_invalid; + return m_status; + } + + Elf_Sym sym; + for (int index = 0; index < count; index ++) { + if (fread(&sym, sym_size, 1, m_file) == 1) { + if (STT_FUNC == ELF_ST_TYPE(sym.st_info)) { + address sym_addr = (address)sym.st_value; + if (sym_addr < addr && (addr - sym_addr) < *offset) { + pc = (address)sym.st_value; + *offset = (int)(addr - pc); + *posIndex = sym.st_name; + *stringtableIndex = m_shdr.sh_link; + } + } + } else { + m_status = Decoder::file_invalid; + return m_status; + } + } + fseek(m_file, cur_pos, SEEK_SET); + } + return m_status; +} + +#endif // _WINDOWS diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/elfSymbolTable.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/elfSymbolTable.hpp Mon Dec 13 14:46:51 2010 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef __ELF_SYMBOL_TABLE_HPP +#define __ELF_SYMBOL_TABLE_HPP + +#ifndef _WINDOWS + + +#include "memory/allocation.hpp" +#include "utilities/decoder.hpp" +#include "utilities/elfFile.hpp" + +/* + * symbol table object represents a symbol section in an elf file. + * Whenever possible, it will load all symbols from the corresponding section + * of the elf file into memory. Otherwise, it will walk the section in file + * to look up the symbol that nearest the given address. + */ +class ElfSymbolTable: public CHeapObj { + friend class ElfFile; + public: + ElfSymbolTable(FILE* file, Elf_Shdr shdr); + ~ElfSymbolTable(); + + // search the symbol that is nearest to the specified address. + Decoder::decoder_status lookup(address addr, int* stringtableIndex, int* posIndex, int* offset); + + Decoder::decoder_status get_status() { return m_status; }; + + protected: + ElfSymbolTable* m_next; + + // holds a complete symbol table section if + // can allocate enough memory + Elf_Sym* m_symbols; + + // file contains string table + FILE* m_file; + + // section header + Elf_Shdr m_shdr; + + Decoder::decoder_status m_status; +}; + +#endif // _WINDOWS + +#endif // __ELF_SYMBOL_TABLE_HPP + + + diff -r 0d4395745860 -r 06ba96862949 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Fri Dec 10 18:05:39 2010 -0800 +++ b/src/share/vm/utilities/vmError.cpp Mon Dec 13 14:46:51 2010 -0800 @@ -33,6 +33,7 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "utilities/debug.hpp" +#include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/top.hpp" #include "utilities/vmError.hpp" @@ -516,8 +517,10 @@ if (fr.pc()) { st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); + // initialize decoder to decode C frames + Decoder decoder; + int count = 0; - while (count++ < StackPrintLimit) { fr.print_on_error(st, buf, sizeof(buf)); st->cr();