8186349: [windows] Centralize dbghelp handling code
Rework and fix dbghelp.dll handling; add diagnostic output to hs-err file. Reviewed-by: iklam, rrich, goetz
This commit is contained in:
parent
a16dc52336
commit
7e3331d90d
@ -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,75 +27,27 @@
|
||||
#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)) {
|
||||
if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
|
||||
paths[0] = '\0';
|
||||
} else {
|
||||
// available spaces in path buffer
|
||||
@ -155,8 +107,7 @@ void WindowsDecoder::initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
_pfn_SymSetSearchPath(hProcess, paths);
|
||||
}
|
||||
WindowsDbgHelp::symSetSearchPath(hProcess, paths);
|
||||
|
||||
// find out if jvm.dll contains private symbols, by decoding
|
||||
// current function and comparing the result
|
||||
@ -168,19 +119,7 @@ void WindowsDecoder::initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
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::can_decode_C_frame_in_vm() const {
|
||||
|
||||
|
||||
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::decode(address addr, char *buf, int buflen, int* offset, co
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
|
@ -25,33 +25,8 @@
|
||||
#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP
|
||||
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
#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 @@ private:
|
||||
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
|
||||
|
@ -74,6 +74,8 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <crtdbg.h>
|
||||
@ -1009,7 +1011,6 @@ void os::check_dump_limit(char* buffer, size_t buffsz) {
|
||||
}
|
||||
|
||||
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 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
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 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
|
||||
// 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);
|
||||
|
306
hotspot/src/os/windows/vm/windbghelp.cpp
Normal file
306
hotspot/src/os/windows/vm/windbghelp.cpp
Normal file
@ -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 <windows.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
73
hotspot/src/os/windows/vm/windbghelp.hpp
Normal file
73
hotspot/src/os/windows/vm/windbghelp.hpp
Normal file
@ -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 <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
// 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
|
||||
|
@ -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 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
|
||||
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;
|
||||
|
@ -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 @@ void Decoder::shutdown() {
|
||||
_shared_decoder = &_do_nothing_decoder;
|
||||
}
|
||||
|
||||
void Decoder::print_state_on(outputStream* st) {
|
||||
#ifdef _WINDOWS
|
||||
WindowsDbgHelp::print_state_on(st);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
class AbstractDecoder : public CHeapObj<mtInternal> {
|
||||
public:
|
||||
@ -41,7 +42,6 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
// 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();
|
||||
|
@ -890,6 +890,13 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP("printing native decoder state")
|
||||
|
||||
if (_verbose) {
|
||||
Decoder::print_state_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP("printing VM options")
|
||||
|
||||
if (_verbose) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user