# HG changeset patch # User stuefe # Date 1503039942 -7200 # Node ID 2b35673f6297c39dd7aca313e70e7cb8d207699b # Parent dd86717fe58be920e068a79f4e47c385f1cadbd3 8186349: [windows] Centralize dbghelp handling code Summary: Rework and fix dbghelp.dll handling; add diagnostic output to hs-err file. Reviewed-by: iklam, rrich, goetz diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os/windows/vm/decoder_windows.cpp --- a/hotspot/src/os/windows/vm/decoder_windows.cpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/os/windows/vm/decoder_windows.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -27,160 +27,99 @@ #include "runtime/arguments.hpp" #include "runtime/os.hpp" #include "decoder_windows.hpp" +#include "windbghelp.hpp" WindowsDecoder::WindowsDecoder() { - _dbghelp_handle = NULL; - _can_decode_in_vm = false; - _pfnSymGetSymFromAddr64 = NULL; - _pfnUndecorateSymbolName = NULL; -#ifdef AMD64 - _pfnStackWalk64 = NULL; - _pfnSymFunctionTableAccess64 = NULL; - _pfnSymGetModuleBase64 = NULL; -#endif + _can_decode_in_vm = true; _decoder_status = no_error; initialize(); } void WindowsDecoder::initialize() { - if (!has_error() && _dbghelp_handle == NULL) { - 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) { - uninitialize(); - _decoder_status = helper_func_error; - return; - } - -#ifdef AMD64 - _pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64"); - _pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64"); - _pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64"); - if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) { - // We can't call StackWalk64 to walk the stack, but we are still - // able to decode the symbols. Let's limp on. - _pfnStackWalk64 = NULL; - _pfnSymFunctionTableAccess64 = NULL; - _pfnSymGetModuleBase64 = NULL; - } -#endif - + if (!has_error()) { HANDLE hProcess = ::GetCurrentProcess(); - _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); - if (!_pfnSymInitialize(hProcess, NULL, TRUE)) { - _pfnSymGetSymFromAddr64 = NULL; - _pfnUndecorateSymbolName = NULL; - ::FreeLibrary(handle); - _dbghelp_handle = NULL; + WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); + if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) { _decoder_status = helper_init_error; return; } // set pdb search paths - pfn_SymSetSearchPath _pfn_SymSetSearchPath = - (pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath"); - pfn_SymGetSearchPath _pfn_SymGetSearchPath = - (pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath"); - if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) { - char paths[MAX_PATH]; - int len = sizeof(paths); - if (!_pfn_SymGetSearchPath(hProcess, paths, len)) { - paths[0] = '\0'; - } else { - // available spaces in path buffer - len -= (int)strlen(paths); - } + char paths[MAX_PATH]; + int len = sizeof(paths); + if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) { + paths[0] = '\0'; + } else { + // available spaces in path buffer + len -= (int)strlen(paths); + } - char tmp_path[MAX_PATH]; - DWORD dwSize; - HMODULE hJVM = ::GetModuleHandle("jvm.dll"); - tmp_path[0] = '\0'; - // append the path where jvm.dll is located - if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) { - while (dwSize > 0 && tmp_path[dwSize] != '\\') { - dwSize --; - } - - tmp_path[dwSize] = '\0'; - - if (dwSize > 0 && len > (int)dwSize + 1) { - strncat(paths, os::path_separator(), 1); - strncat(paths, tmp_path, dwSize); - len -= dwSize + 1; - } + char tmp_path[MAX_PATH]; + DWORD dwSize; + HMODULE hJVM = ::GetModuleHandle("jvm.dll"); + tmp_path[0] = '\0'; + // append the path where jvm.dll is located + if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) { + while (dwSize > 0 && tmp_path[dwSize] != '\\') { + dwSize --; } - // append $JRE/bin. Arguments::get_java_home actually returns $JRE - // path - char *p = Arguments::get_java_home(); - assert(p != NULL, "empty java home"); - size_t java_home_len = strlen(p); - if (len > (int)java_home_len + 5) { + tmp_path[dwSize] = '\0'; + + if (dwSize > 0 && len > (int)dwSize + 1) { strncat(paths, os::path_separator(), 1); - strncat(paths, p, java_home_len); - strncat(paths, "\\bin", 4); - len -= (int)(java_home_len + 5); + strncat(paths, tmp_path, dwSize); + len -= dwSize + 1; } + } - // append $JDK/bin path if it exists - assert(java_home_len < MAX_PATH, "Invalid path length"); - // assume $JRE is under $JDK, construct $JDK/bin path and - // see if it exists or not - if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) { - strncpy(tmp_path, p, java_home_len - 3); - tmp_path[java_home_len - 3] = '\0'; - strncat(tmp_path, "bin", 3); + // append $JRE/bin. Arguments::get_java_home actually returns $JRE + // path + char *p = Arguments::get_java_home(); + assert(p != NULL, "empty java home"); + size_t java_home_len = strlen(p); + if (len > (int)java_home_len + 5) { + strncat(paths, os::path_separator(), 1); + strncat(paths, p, java_home_len); + strncat(paths, "\\bin", 4); + len -= (int)(java_home_len + 5); + } - // if the directory exists - DWORD dwAttrib = GetFileAttributes(tmp_path); - if (dwAttrib != INVALID_FILE_ATTRIBUTES && - (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { - // tmp_path should have the same length as java_home_len, since we only - // replaced 'jre' with 'bin' - if (len > (int)java_home_len + 1) { - strncat(paths, os::path_separator(), 1); - strncat(paths, tmp_path, java_home_len); - } + // append $JDK/bin path if it exists + assert(java_home_len < MAX_PATH, "Invalid path length"); + // assume $JRE is under $JDK, construct $JDK/bin path and + // see if it exists or not + if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) { + strncpy(tmp_path, p, java_home_len - 3); + tmp_path[java_home_len - 3] = '\0'; + strncat(tmp_path, "bin", 3); + + // if the directory exists + DWORD dwAttrib = GetFileAttributes(tmp_path); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + // tmp_path should have the same length as java_home_len, since we only + // replaced 'jre' with 'bin' + if (len > (int)java_home_len + 1) { + strncat(paths, os::path_separator(), 1); + strncat(paths, tmp_path, java_home_len); } } - - _pfn_SymSetSearchPath(hProcess, paths); } - // find out if jvm.dll contains private symbols, by decoding - // current function and comparing the result - address addr = (address)Decoder::demangle; - char buf[MAX_PATH]; - if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) { - _can_decode_in_vm = !strcmp(buf, "Decoder::demangle"); - } + WindowsDbgHelp::symSetSearchPath(hProcess, paths); + + // find out if jvm.dll contains private symbols, by decoding + // current function and comparing the result + address addr = (address)Decoder::demangle; + char buf[MAX_PATH]; + if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) { + _can_decode_in_vm = !strcmp(buf, "Decoder::demangle"); + } } } -void WindowsDecoder::uninitialize() { - _pfnSymGetSymFromAddr64 = NULL; - _pfnUndecorateSymbolName = NULL; -#ifdef AMD64 - _pfnStackWalk64 = NULL; - _pfnSymFunctionTableAccess64 = NULL; - _pfnSymGetModuleBase64 = NULL; -#endif - if (_dbghelp_handle != NULL) { - ::FreeLibrary(_dbghelp_handle); - } - _dbghelp_handle = NULL; -} +void WindowsDecoder::uninitialize() {} bool WindowsDecoder::can_decode_C_frame_in_vm() const { return (!has_error() && _can_decode_in_vm); @@ -188,14 +127,14 @@ bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) { - if (_pfnSymGetSymFromAddr64 != NULL) { + if (!has_error()) { 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 (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { if (buf != NULL) { if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) { jio_snprintf(buf, buflen, "%s", pSymbol->Name); @@ -211,69 +150,9 @@ } bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) { - return _pfnUndecorateSymbolName != NULL && - _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); -} - -#ifdef AMD64 -BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) { - DecoderLocker locker; - WindowsDecoder* wd = (WindowsDecoder*)locker.decoder(); - - if (!wd->has_error() && wd->_pfnStackWalk64) { - return wd->_pfnStackWalk64(MachineType, - hProcess, - hThread, - StackFrame, - ContextRecord, - ReadMemoryRoutine, - FunctionTableAccessRoutine, - GetModuleBaseRoutine, - TranslateAddress); - } else { - return false; + if (!has_error()) { + return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0; } + return false; } -PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { - DecoderLocker locker; - WindowsDecoder* wd = (WindowsDecoder*)locker.decoder(); - - if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) { - return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase); - } else { - return NULL; - } -} - -pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() { - DecoderLocker locker; - WindowsDecoder* wd = (WindowsDecoder*)locker.decoder(); - - if (!wd->has_error()) { - return wd->_pfnSymFunctionTableAccess64; - } else { - return NULL; - } -} - -pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() { - DecoderLocker locker; - WindowsDecoder* wd = (WindowsDecoder*)locker.decoder(); - - if (!wd->has_error()) { - return wd->_pfnSymGetModuleBase64; - } else { - return NULL; - } -} - -#endif // AMD64 diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os/windows/vm/decoder_windows.hpp --- a/hotspot/src/os/windows/vm/decoder_windows.hpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/os/windows/vm/decoder_windows.hpp Fri Aug 18 09:05:42 2017 +0200 @@ -25,33 +25,8 @@ #ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP #define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP -#include -#include - #include "utilities/decoder.hpp" -// 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); -typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR); -typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int); - -#ifdef AMD64 -typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); -typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); -typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr); -#endif - class WindowsDecoder : public AbstractDecoder { public: @@ -70,38 +45,8 @@ void initialize(); void uninitialize(); -private: - HMODULE _dbghelp_handle; bool _can_decode_in_vm; - pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64; - pfn_UndecorateSymbolName _pfnUndecorateSymbolName; -#ifdef AMD64 - pfn_StackWalk64 _pfnStackWalk64; - pfn_SymFunctionTableAccess64 _pfnSymFunctionTableAccess64; - pfn_SymGetModuleBase64 _pfnSymGetModuleBase64; - friend class WindowsDbgHelp; -#endif }; -#ifdef AMD64 -// TODO: refactor and move the handling of dbghelp.dll outside of Decoder -class WindowsDbgHelp : public Decoder { -public: - static BOOL StackWalk64(DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); - static PVOID SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); - - static pfn_SymFunctionTableAccess64 pfnSymFunctionTableAccess64(); - static pfn_SymGetModuleBase64 pfnSymGetModuleBase64(); -}; -#endif - #endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -74,6 +74,8 @@ #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/vmError.hpp" +#include "windbghelp.hpp" + #ifdef _DEBUG #include @@ -1009,7 +1011,6 @@ } void os::abort(bool dump_core, void* siginfo, const void* context) { - HINSTANCE dbghelp; EXCEPTION_POINTERS ep; MINIDUMP_EXCEPTION_INFORMATION mei; MINIDUMP_EXCEPTION_INFORMATION* pmei; @@ -1026,28 +1027,6 @@ win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } - dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0); - - if (dbghelp == NULL) { - jio_fprintf(stderr, "Failed to load dbghelp.dll\n"); - CloseHandle(dumpFile); - win32::exit_process_or_thread(win32::EPT_PROCESS, 1); - } - - _MiniDumpWriteDump = - CAST_TO_FN_PTR(BOOL(WINAPI *)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, - PMINIDUMP_EXCEPTION_INFORMATION, - PMINIDUMP_USER_STREAM_INFORMATION, - PMINIDUMP_CALLBACK_INFORMATION), - GetProcAddress(dbghelp, - "MiniDumpWriteDump")); - - if (_MiniDumpWriteDump == NULL) { - jio_fprintf(stderr, "Failed to find MiniDumpWriteDump() in module dbghelp.dll.\n"); - CloseHandle(dumpFile); - win32::exit_process_or_thread(win32::EPT_PROCESS, 1); - } - dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); @@ -1064,8 +1043,8 @@ // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. - if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false && - _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { + if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) && + !WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) { jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError()); } CloseHandle(dumpFile); diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os/windows/vm/windbghelp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/windows/vm/windbghelp.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2017, 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 "utilities/ostream.hpp" +#include "windbghelp.hpp" + +#include + +typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD); +typedef DWORD (WINAPI *pfn_SymGetOptions)(void); +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); +typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR); +typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int); +typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); +typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); +typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr); +typedef BOOL (WINAPI *pfn_MiniDumpWriteDump) (HANDLE hProcess, DWORD ProcessId, HANDLE hFile, + MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + PMINIDUMP_CALLBACK_INFORMATION CallbackParam); +typedef BOOL (WINAPI *pfn_SymGetLineFromAddr64) (HANDLE hProcess, DWORD64 dwAddr, + PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line); +typedef LPAPI_VERSION (WINAPI *pfn_ImagehlpApiVersion)(void); + +// Add functions as needed. +#define FOR_ALL_FUNCTIONS(DO) \ + DO(ImagehlpApiVersion) \ + DO(SymGetOptions) \ + DO(SymSetOptions) \ + DO(SymInitialize) \ + DO(SymGetSymFromAddr64) \ + DO(UnDecorateSymbolName) \ + DO(SymSetSearchPath) \ + DO(SymGetSearchPath) \ + DO(StackWalk64) \ + DO(SymFunctionTableAccess64) \ + DO(SymGetModuleBase64) \ + DO(MiniDumpWriteDump) \ + DO(SymGetLineFromAddr64) + + +#define DECLARE_FUNCTION_POINTER(functionname) \ +static pfn_##functionname g_pfn_##functionname; + +FOR_ALL_FUNCTIONS(DECLARE_FUNCTION_POINTER) + + +static HMODULE g_dll_handle = NULL; +static DWORD g_dll_load_error = 0; +static API_VERSION g_version = { 0, 0, 0, 0 }; + +static enum { + state_uninitialized = 0, + state_ready = 1, + state_error = 2 +} g_state = state_uninitialized; + +static void initialize() { + + assert(g_state == state_uninitialized, "wrong sequence"); + g_state = state_error; + + g_dll_handle = ::LoadLibrary("DBGHELP.DLL"); + if (g_dll_handle == NULL) { + g_dll_load_error = ::GetLastError(); + } else { + // Note: We loaded the DLL successfully. From here on we count + // initialization as success. We still may fail to load all of the + // desired function pointers successfully, but DLL may still be usable + // enough for our purposes. + g_state = state_ready; + +#define DO_RESOLVE(functionname) \ + g_pfn_##functionname = (pfn_##functionname) ::GetProcAddress(g_dll_handle, #functionname); + + FOR_ALL_FUNCTIONS(DO_RESOLVE) + + // Retrieve version information. + if (g_pfn_ImagehlpApiVersion) { + const API_VERSION* p = g_pfn_ImagehlpApiVersion(); + memcpy(&g_version, p, sizeof(API_VERSION)); + } + } + +} + +///////////////////// External functions ////////////////////////// + +// All outside facing functions are synchronized. Also, we run +// initialization on first touch. + + +// Call InitializeCriticalSection as early as possible. +class CritSect { + CRITICAL_SECTION cs; +public: + CritSect() { ::InitializeCriticalSection(&cs); } + void enter() { ::EnterCriticalSection(&cs); } + void leave() { ::LeaveCriticalSection(&cs); } +}; + +static CritSect g_cs; + +class EntryGuard { +public: + EntryGuard() { + g_cs.enter(); + if (g_state == state_uninitialized) { + initialize(); + } + } + ~EntryGuard() { + g_cs.leave(); + } +}; + +DWORD WindowsDbgHelp::symSetOptions(DWORD arg) { + EntryGuard entry_guard; + if (g_pfn_SymSetOptions != NULL) { + return g_pfn_SymSetOptions(arg); + } + return 0; +} + +DWORD WindowsDbgHelp::symGetOptions(void) { + EntryGuard entry_guard; + if (g_pfn_SymGetOptions != NULL) { + return g_pfn_SymGetOptions(); + } + return 0; +} + +BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) { + EntryGuard entry_guard; + if (g_pfn_SymInitialize != NULL) { + return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess); + } + return FALSE; +} + +BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address, + PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) { + EntryGuard entry_guard; + if (g_pfn_SymGetSymFromAddr64 != NULL) { + return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol); + } + return FALSE; +} + +DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName, + DWORD UndecoratedLength, DWORD Flags) { + EntryGuard entry_guard; + if (g_pfn_UnDecorateSymbolName != NULL) { + return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags); + } + if (UnDecoratedName != NULL && UndecoratedLength > 0) { + UnDecoratedName[0] = '\0'; + } + return 0; +} + +BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) { + EntryGuard entry_guard; + if (g_pfn_SymSetSearchPath != NULL) { + return g_pfn_SymSetSearchPath(hProcess, SearchPath); + } + return FALSE; +} + +BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) { + EntryGuard entry_guard; + if (g_pfn_SymGetSearchPath != NULL) { + return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength); + } + return FALSE; +} + +BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord) { + EntryGuard entry_guard; + if (g_pfn_StackWalk64 != NULL) { + return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame, + ContextRecord, + NULL, // ReadMemoryRoutine + g_pfn_SymFunctionTableAccess64, // FunctionTableAccessRoutine, + g_pfn_SymGetModuleBase64, // GetModuleBaseRoutine + NULL // TranslateAddressRoutine + ); + } + return FALSE; +} + +PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) { + EntryGuard entry_guard; + if (g_pfn_SymFunctionTableAccess64 != NULL) { + return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase); + } + return NULL; +} + +DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) { + EntryGuard entry_guard; + if (g_pfn_SymGetModuleBase64 != NULL) { + return g_pfn_SymGetModuleBase64(hProcess, dwAddr); + } + return 0; +} + +BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, + MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + PMINIDUMP_CALLBACK_INFORMATION CallbackParam) { + EntryGuard entry_guard; + if (g_pfn_MiniDumpWriteDump != NULL) { + return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, + ExceptionParam, UserStreamParam, CallbackParam); + } + return FALSE; +} + +BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, + PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) { + EntryGuard entry_guard; + if (g_pfn_SymGetLineFromAddr64 != NULL) { + return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line); + } + return FALSE; +} + +// Print one liner describing state (if library loaded, which functions are +// missing - if any, and the dbhelp API version) +void WindowsDbgHelp::print_state_on(outputStream* st) { + // Note: We should not lock while printing, but this should be + // safe to do without lock anyway. + st->print("dbghelp: "); + + if (g_state == state_uninitialized) { + st->print("uninitialized."); + } else if (g_state == state_error) { + st->print("loading error: %u", g_dll_load_error); + } else { + st->print("loaded successfully "); + + // We may want to print dll file name here - which may be interesting for + // cases where more than one version exists on the system, e.g. with a + // debugging sdk separately installed. But we get the file name in the DLL + // section of the hs-err file too, so this may be redundant. + + // Print version. + st->print("- version: %u.%u.%u", + g_version.MajorVersion, g_version.MinorVersion, g_version.Revision); + + // Print any functions which failed to load. + int num_missing = 0; + st->print(" - missing functions: "); + + #define CHECK_AND_PRINT_IF_NULL(functionname) \ + if (g_pfn_##functionname == NULL) { \ + st->print("%s" #functionname, ((num_missing > 0) ? ", " : "")); \ + num_missing ++; \ + } + + FOR_ALL_FUNCTIONS(CHECK_AND_PRINT_IF_NULL) + + if (num_missing == 0) { + st->print("none"); + } + } + st->cr(); +} + diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os/windows/vm/windbghelp.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/windows/vm/windbghelp.hpp Fri Aug 18 09:05:42 2017 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, 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 OS_WINDOWS_VM_DBGHELPLOADER_HPP +#define OS_WINDOWS_VM_DBGHELPLOADER_HPP + +#include +#include + +// This is a very plain wrapper for loading dbghelp.dll. It does not offer +// any additional functionality. It takes care of locking. + +class outputStream; + +// Please note: dbghelp.dll may not have been loaded, or it may have been loaded but not +// all functions may be available (because on the target system dbghelp.dll is of an +// older version). +// In all these cases we return an error from the WindowsDbgHelp::symXXXX() wrapper. We never +// assert. It should always be safe to call these functions, but caller has to process the +// return code (which he would have to do anyway). +namespace WindowsDbgHelp { + + DWORD symSetOptions(DWORD); + DWORD symGetOptions(void); + BOOL symInitialize(HANDLE, PCTSTR, BOOL); + BOOL symGetSymFromAddr64(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); + DWORD unDecorateSymbolName(const char*, char*, DWORD, DWORD); + BOOL symSetSearchPath(HANDLE, PCTSTR); + BOOL symGetSearchPath(HANDLE, PTSTR, int); + BOOL stackWalk64(DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord); + PVOID symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase); + DWORD64 symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr); + BOOL miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, + MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + BOOL symGetLineFromAddr64 (HANDLE hProcess, DWORD64 dwAddr, + PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line); + + // Print one liner describing state (if library loaded, which functions are + // missing - if any, and the dbhelp API version) + void print_state_on(outputStream* st); + +}; + + +#endif // OS_WINDOWS_VM_DBGHELPLOADER_HPP + diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -29,7 +29,6 @@ #include "classfile/vmSymbols.hpp" #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" -#include "decoder_windows.hpp" #include "interpreter/interpreter.hpp" #include "jvm_windows.h" #include "memory/allocation.inline.hpp" @@ -51,10 +50,12 @@ #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" +#include "unwind_windows_x86.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" +#include "windbghelp.hpp" -# include "unwind_windows_x86.hpp" + #undef REG_SP #undef REG_FP #undef REG_PC @@ -401,24 +402,18 @@ lastpc = pc; } - PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); + PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); if (!p) { // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash. break; } - BOOL result = WindowsDbgHelp::StackWalk64( + BOOL result = WindowsDbgHelp::stackWalk64( IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType, GetCurrentProcess(), // __in HANDLE hProcess, GetCurrentThread(), // __in HANDLE hThread, &stk, // __inout LP STACKFRAME64 StackFrame, - &ctx, // __inout PVOID ContextRecord, - NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - WindowsDbgHelp::pfnSymFunctionTableAccess64(), - // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - WindowsDbgHelp::pfnSymGetModuleBase64(), - // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - NULL); // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + &ctx); // __inout PVOID ContextRecord, if (!result) { break; diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/share/vm/utilities/decoder.cpp --- a/hotspot/src/share/vm/utilities/decoder.cpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/share/vm/utilities/decoder.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -30,6 +30,7 @@ #if defined(_WINDOWS) #include "decoder_windows.hpp" + #include "windbghelp.hpp" #elif defined(__APPLE__) #include "decoder_machO.hpp" #elif defined(AIX) @@ -162,3 +163,9 @@ _shared_decoder = &_do_nothing_decoder; } +void Decoder::print_state_on(outputStream* st) { +#ifdef _WINDOWS + WindowsDbgHelp::print_state_on(st); +#endif +} + diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/share/vm/utilities/decoder.hpp --- a/hotspot/src/share/vm/utilities/decoder.hpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/share/vm/utilities/decoder.hpp Fri Aug 18 09:05:42 2017 +0200 @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" +#include "utilities/ostream.hpp" class AbstractDecoder : public CHeapObj { public: @@ -41,7 +42,6 @@ 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) }; @@ -117,6 +117,9 @@ // shutdown shared instance static void shutdown(); + + static void print_state_on(outputStream* st); + protected: // shared decoder instance, _shared_instance_lock is needed static AbstractDecoder* get_shared_instance(); diff -r dd86717fe58b -r 2b35673f6297 hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Mon Aug 28 16:40:01 2017 +0000 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Fri Aug 18 09:05:42 2017 +0200 @@ -890,6 +890,13 @@ st->cr(); } + STEP("printing native decoder state") + + if (_verbose) { + Decoder::print_state_on(st); + st->cr(); + } + STEP("printing VM options") if (_verbose) {