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:
Thomas Stuefe 2017-08-18 09:05:42 +02:00
parent a16dc52336
commit 7e3331d90d
9 changed files with 489 additions and 295 deletions

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,75 +27,27 @@
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "decoder_windows.hpp" #include "decoder_windows.hpp"
#include "windbghelp.hpp"
WindowsDecoder::WindowsDecoder() { WindowsDecoder::WindowsDecoder() {
_dbghelp_handle = NULL; _can_decode_in_vm = true;
_can_decode_in_vm = false;
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
#ifdef AMD64
_pfnStackWalk64 = NULL;
_pfnSymFunctionTableAccess64 = NULL;
_pfnSymGetModuleBase64 = NULL;
#endif
_decoder_status = no_error; _decoder_status = no_error;
initialize(); initialize();
} }
void WindowsDecoder::initialize() { void WindowsDecoder::initialize() {
if (!has_error() && _dbghelp_handle == NULL) { if (!has_error()) {
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
HANDLE hProcess = ::GetCurrentProcess(); HANDLE hProcess = ::GetCurrentProcess();
_pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS); WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
if (!_pfnSymInitialize(hProcess, NULL, TRUE)) { if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
::FreeLibrary(handle);
_dbghelp_handle = NULL;
_decoder_status = helper_init_error; _decoder_status = helper_init_error;
return; return;
} }
// set pdb search paths // 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]; char paths[MAX_PATH];
int len = sizeof(paths); int len = sizeof(paths);
if (!_pfn_SymGetSearchPath(hProcess, paths, len)) { if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
paths[0] = '\0'; paths[0] = '\0';
} else { } else {
// available spaces in path buffer // 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 // find out if jvm.dll contains private symbols, by decoding
// current function and comparing the result // current function and comparing the result
@ -168,19 +119,7 @@ void WindowsDecoder::initialize() {
} }
} }
void WindowsDecoder::uninitialize() { 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;
}
bool WindowsDecoder::can_decode_C_frame_in_vm() const { bool WindowsDecoder::can_decode_C_frame_in_vm() const {
return (!has_error() && _can_decode_in_vm); 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) { 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; PIMAGEHLP_SYMBOL64 pSymbol;
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo; pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
pSymbol->MaxNameLength = MAX_PATH; pSymbol->MaxNameLength = MAX_PATH;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 displacement; DWORD64 displacement;
if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
if (buf != NULL) { if (buf != NULL) {
if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) { if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", pSymbol->Name); 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) { bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
return _pfnUndecorateSymbolName != NULL && if (!has_error()) {
_pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
} }
#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; 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

View File

@ -25,33 +25,8 @@
#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP #ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP #define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
#include <windows.h>
#include <imagehlp.h>
#include "utilities/decoder.hpp" #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 { class WindowsDecoder : public AbstractDecoder {
public: public:
@ -70,38 +45,8 @@ private:
void initialize(); void initialize();
void uninitialize(); void uninitialize();
private:
HMODULE _dbghelp_handle;
bool _can_decode_in_vm; 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 #endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP

View File

@ -74,6 +74,8 @@
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#include "windbghelp.hpp"
#ifdef _DEBUG #ifdef _DEBUG
#include <crtdbg.h> #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) { void os::abort(bool dump_core, void* siginfo, const void* context) {
HINSTANCE dbghelp;
EXCEPTION_POINTERS ep; EXCEPTION_POINTERS ep;
MINIDUMP_EXCEPTION_INFORMATION mei; MINIDUMP_EXCEPTION_INFORMATION mei;
MINIDUMP_EXCEPTION_INFORMATION* pmei; 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); 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 | dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData |
MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); 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 // 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. // 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 && if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) &&
_MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { !WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) {
jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError()); jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError());
} }
CloseHandle(dumpFile); CloseHandle(dumpFile);

View 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();
}

View 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

View File

@ -29,7 +29,6 @@
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp" #include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "decoder_windows.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "jvm_windows.h" #include "jvm_windows.h"
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
@ -51,10 +50,12 @@
#include "runtime/stubRoutines.hpp" #include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp" #include "runtime/timer.hpp"
#include "unwind_windows_x86.hpp"
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#include "windbghelp.hpp"
# include "unwind_windows_x86.hpp"
#undef REG_SP #undef REG_SP
#undef REG_FP #undef REG_FP
#undef REG_PC #undef REG_PC
@ -401,24 +402,18 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
lastpc = pc; lastpc = pc;
} }
PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset); PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
if (!p) { if (!p) {
// StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash. // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
break; break;
} }
BOOL result = WindowsDbgHelp::StackWalk64( BOOL result = WindowsDbgHelp::stackWalk64(
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType, IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
GetCurrentProcess(), // __in HANDLE hProcess, GetCurrentProcess(), // __in HANDLE hProcess,
GetCurrentThread(), // __in HANDLE hThread, GetCurrentThread(), // __in HANDLE hThread,
&stk, // __inout LP STACKFRAME64 StackFrame, &stk, // __inout LP STACKFRAME64 StackFrame,
&ctx, // __inout PVOID ContextRecord, &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
if (!result) { if (!result) {
break; break;

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@
#if defined(_WINDOWS) #if defined(_WINDOWS)
#include "decoder_windows.hpp" #include "decoder_windows.hpp"
#include "windbghelp.hpp"
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include "decoder_machO.hpp" #include "decoder_machO.hpp"
#elif defined(AIX) #elif defined(AIX)
@ -162,3 +163,9 @@ void Decoder::shutdown() {
_shared_decoder = &_do_nothing_decoder; _shared_decoder = &_do_nothing_decoder;
} }
void Decoder::print_state_on(outputStream* st) {
#ifdef _WINDOWS
WindowsDbgHelp::print_state_on(st);
#endif
}

View File

@ -29,6 +29,7 @@
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "runtime/mutex.hpp" #include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp" #include "runtime/mutexLocker.hpp"
#include "utilities/ostream.hpp"
class AbstractDecoder : public CHeapObj<mtInternal> { class AbstractDecoder : public CHeapObj<mtInternal> {
public: public:
@ -41,7 +42,6 @@ public:
out_of_memory, // out of memory out_of_memory, // out of memory
file_invalid, // invalid elf file file_invalid, // invalid elf file
file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map 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_func_error, // decoding functions not found (Windows only)
helper_init_error // SymInitialize failed (Windows only) helper_init_error // SymInitialize failed (Windows only)
}; };
@ -117,6 +117,9 @@ public:
// shutdown shared instance // shutdown shared instance
static void shutdown(); static void shutdown();
static void print_state_on(outputStream* st);
protected: protected:
// shared decoder instance, _shared_instance_lock is needed // shared decoder instance, _shared_instance_lock is needed
static AbstractDecoder* get_shared_instance(); static AbstractDecoder* get_shared_instance();

View File

@ -890,6 +890,13 @@ void VMError::report(outputStream* st, bool _verbose) {
st->cr(); st->cr();
} }
STEP("printing native decoder state")
if (_verbose) {
Decoder::print_state_on(st);
st->cr();
}
STEP("printing VM options") STEP("printing VM options")
if (_verbose) { if (_verbose) {