changeset 13627:38ff008318c3

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
author stuefe
date Fri, 18 Aug 2017 09:05:42 +0200
parents f3413e6d6b8f
children a20f0fa4c426
files src/os/windows/vm/decoder_windows.cpp src/os/windows/vm/decoder_windows.hpp src/os/windows/vm/os_windows.cpp src/os/windows/vm/windbghelp.cpp src/os/windows/vm/windbghelp.hpp src/os_cpu/windows_x86/vm/os_windows_x86.cpp src/share/vm/utilities/decoder.cpp src/share/vm/utilities/decoder.hpp src/share/vm/utilities/vmError.cpp
diffstat 9 files changed, 483 insertions(+), 289 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/windows/vm/decoder_windows.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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 --;
       }
 
-      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';
 
-        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;
+      }
+    }
 
-        if (dwSize > 0 && len > (int)dwSize + 1) {
+    // 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);
+    }
+
+    // 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, dwSize);
-          len -= dwSize + 1;
+          strncat(paths, tmp_path, java_home_len);
         }
       }
-
-      // 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);
-      }
-
-      // 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);
+  if (!has_error()) {
+    return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
+  }
+  return false;
 }
 
-#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;
-  }
-}
-
-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
--- a/src/os/windows/vm/decoder_windows.hpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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 <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 @@
   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
--- a/src/os/windows/vm/os_windows.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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 <crtdbg.h>
@@ -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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/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 <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();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/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 <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
+
--- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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;
--- a/src/share/vm/utilities/decoder.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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
+}
+
--- a/src/share/vm/utilities/decoder.hpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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<mtInternal> {
 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();
--- a/src/share/vm/utilities/vmError.cpp	Mon Aug 28 16:40:01 2017 +0000
+++ b/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) {