1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[Support] Lazy load of dbghlp.dll on Windows

This patch changes linkage with dbghlp.dll for clang from static (at load time)
to on demand (at the first use of required functions). Clang uses dbghlp.dll
only in minor use-cases. First of all in case of crash and in case of plugin load.
The dbghlp.dll library can be absent on system. In this case clang will fail
to load. With lazy load of dbghlp.dll clang can work even if dbghlp.dll
is not available.

Differential Revision: http://reviews.llvm.org/D10737

llvm-svn: 241271
This commit is contained in:
Leny Kholodov 2015-07-02 14:34:57 +00:00
parent d6fbeaef08
commit 76adfcc946
8 changed files with 55 additions and 50 deletions

View File

@ -1628,7 +1628,6 @@ dnl===-----------------------------------------------------------------------===
AC_CHECK_LIB(m,sin) AC_CHECK_LIB(m,sin)
if test "$llvm_cv_os_type" = "MingW" ; then if test "$llvm_cv_os_type" = "MingW" ; then
AC_CHECK_LIB(imagehlp, main)
AC_CHECK_LIB(ole32, main) AC_CHECK_LIB(ole32, main)
AC_CHECK_LIB(psapi, main) AC_CHECK_LIB(psapi, main)
AC_CHECK_LIB(shell32, main) AC_CHECK_LIB(shell32, main)

View File

@ -397,12 +397,10 @@ else ()
endif () endif ()
if( MINGW ) if( MINGW )
set(HAVE_LIBIMAGEHLP 1)
set(HAVE_LIBPSAPI 1) set(HAVE_LIBPSAPI 1)
set(HAVE_LIBSHELL32 1) set(HAVE_LIBSHELL32 1)
# TODO: Check existence of libraries. # TODO: Check existence of libraries.
# include(CheckLibraryExists) # include(CheckLibraryExists)
# CHECK_LIBRARY_EXISTS(imagehlp ??? . HAVE_LIBIMAGEHLP)
endif( MINGW ) endif( MINGW )
if (NOT HAVE_STRTOLL) if (NOT HAVE_STRTOLL)

View File

@ -125,9 +125,6 @@
/* Define if you have the libdl library or equivalent. */ /* Define if you have the libdl library or equivalent. */
#cmakedefine HAVE_LIBDL ${HAVE_LIBDL} #cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
/* Define to 1 if you have the `imagehlp' library (-limagehlp). */
#cmakedefine HAVE_LIBIMAGEHLP ${HAVE_LIBIMAGEHLP}
/* Define to 1 if you have the `m' library (-lm). */ /* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM #undef HAVE_LIBM

View File

@ -137,9 +137,6 @@
/* Define if libedit is available on this platform. */ /* Define if libedit is available on this platform. */
#undef HAVE_LIBEDIT #undef HAVE_LIBEDIT
/* Define to 1 if you have the `imagehlp' library (-limagehlp). */
#undef HAVE_LIBIMAGEHLP
/* Define to 1 if you have the `m' library (-lm). */ /* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM #undef HAVE_LIBM

View File

@ -1,7 +1,7 @@
set(system_libs) set(system_libs)
if( NOT MSVC ) if( NOT MSVC )
if( MINGW ) if( MINGW )
set(system_libs ${system_libs} imagehlp psapi shell32 ole32) set(system_libs ${system_libs} psapi shell32 ole32)
elseif( CMAKE_HOST_UNIX ) elseif( CMAKE_HOST_UNIX )
if( HAVE_LIBRT ) if( HAVE_LIBRT )
set(system_libs ${system_libs} rt) set(system_libs ${system_libs} rt)

View File

@ -23,14 +23,6 @@
#include <ntverp.h> #include <ntverp.h>
#endif #endif
#ifdef __MINGW32__
#if (HAVE_LIBIMAGEHLP != 1)
#error "libimagehlp.a should be present"
#endif
#else
#pragma comment(lib, "dbghelp.lib")
#endif
namespace llvm { namespace llvm {
using namespace sys; using namespace sys;
@ -39,10 +31,21 @@ using namespace sys;
//=== and must not be UNIX code. //=== and must not be UNIX code.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
static fpEnumerateLoadedModules fEnumerateLoadedModules;
static DenseSet<HMODULE> *OpenedHandles; static DenseSet<HMODULE> *OpenedHandles;
static bool loadDebugHelp(void) {
HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
if (hLib) {
fEnumerateLoadedModules = (fpEnumerateLoadedModules)
::GetProcAddress(hLib, "EnumerateLoadedModules64");
}
return fEnumerateLoadedModules != 0;
}
static BOOL CALLBACK static BOOL CALLBACK
ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, ULONG_PTR ModuleBase, ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, DWORD64 ModuleBase,
ULONG ModuleSize, PVOID UserContext) { ULONG ModuleSize, PVOID UserContext) {
OpenedHandles->insert((HMODULE)ModuleBase); OpenedHandles->insert((HMODULE)ModuleBase);
return TRUE; return TRUE;
@ -57,7 +60,14 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
if (OpenedHandles == 0) if (OpenedHandles == 0)
OpenedHandles = new DenseSet<HMODULE>(); OpenedHandles = new DenseSet<HMODULE>();
EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); if (!fEnumerateLoadedModules) {
if (!loadDebugHelp()) {
assert(false && "These APIs should always be available");
return DynamicLibrary();
}
}
fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0);
// Dummy library that represents "search all handles". // Dummy library that represents "search all handles".
// This is mostly to ensure that the return value still shows up as "valid". // This is mostly to ensure that the return value still shows up as "valid".
return DynamicLibrary(&OpenedHandles); return DynamicLibrary(&OpenedHandles);

View File

@ -31,10 +31,9 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma comment(lib, "psapi.lib") #pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
#elif __MINGW32__ #elif __MINGW32__
#if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) #if (HAVE_LIBPSAPI != 1)
#error "libimagehlp.a & libpsapi.a should be present" #error "libpsapi.a should be present"
#endif #endif
// The version of g++ that comes with MinGW does *not* properly understand // The version of g++ that comes with MinGW does *not* properly understand
// the ll format specifier for printf. However, MinGW passes the format // the ll format specifier for printf. However, MinGW passes the format
@ -103,6 +102,8 @@
DWORD64 Reserved[3]; DWORD64 Reserved[3];
KDHELP64 KdHelp; KDHELP64 KdHelp;
} STACKFRAME64, *LPSTACKFRAME64; } STACKFRAME64, *LPSTACKFRAME64;
#endif // !defined(__MINGW64_VERSION_MAJOR)
#endif // __MINGW32__
typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
@ -122,40 +123,46 @@ typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
PFUNCTION_TABLE_ACCESS_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64,
PGET_MODULE_BASE_ROUTINE64, PGET_MODULE_BASE_ROUTINE64,
PTRANSLATE_ADDRESS_ROUTINE64); PTRANSLATE_ADDRESS_ROUTINE64);
static fpStackWalk64 StackWalk64; static fpStackWalk64 fStackWalk64;
typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
static fpSymGetModuleBase64 SymGetModuleBase64; static fpSymGetModuleBase64 fSymGetModuleBase64;
typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
PDWORD64, PIMAGEHLP_SYMBOL64); PDWORD64, PIMAGEHLP_SYMBOL64);
static fpSymGetSymFromAddr64 SymGetSymFromAddr64; static fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
PDWORD, PIMAGEHLP_LINE64); PDWORD, PIMAGEHLP_LINE64);
static fpSymGetLineFromAddr64 SymGetLineFromAddr64; static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
static fpSymFunctionTableAccess64 SymFunctionTableAccess64; static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
typedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
static fpSymSetOptions fSymSetOptions;
typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
static fpSymInitialize fSymInitialize;
static bool load64BitDebugHelp(void) { static bool load64BitDebugHelp(void) {
HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
if (hLib) { if (hLib) {
StackWalk64 = (fpStackWalk64) fStackWalk64 = (fpStackWalk64)
::GetProcAddress(hLib, "StackWalk64"); ::GetProcAddress(hLib, "StackWalk64");
SymGetModuleBase64 = (fpSymGetModuleBase64) fSymGetModuleBase64 = (fpSymGetModuleBase64)
::GetProcAddress(hLib, "SymGetModuleBase64"); ::GetProcAddress(hLib, "SymGetModuleBase64");
SymGetSymFromAddr64 = (fpSymGetSymFromAddr64) fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
::GetProcAddress(hLib, "SymGetSymFromAddr64"); ::GetProcAddress(hLib, "SymGetSymFromAddr64");
SymGetLineFromAddr64 = (fpSymGetLineFromAddr64) fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
::GetProcAddress(hLib, "SymGetLineFromAddr64"); ::GetProcAddress(hLib, "SymGetLineFromAddr64");
SymFunctionTableAccess64 = (fpSymFunctionTableAccess64) fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
::GetProcAddress(hLib, "SymFunctionTableAccess64"); ::GetProcAddress(hLib, "SymFunctionTableAccess64");
fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
} }
return StackWalk64 != NULL; return fStackWalk64 && fSymInitialize && fSymSetOptions;
} }
#endif // !defined(__MINGW64_VERSION_MAJOR)
#endif // __MINGW32__
// Forward declare. // Forward declare.
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
@ -187,12 +194,12 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
#endif #endif
// Initialize the symbol handler. // Initialize the symbol handler.
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
SymInitialize(hProcess, NULL, TRUE); fSymInitialize(hProcess, NULL, TRUE);
while (true) { while (true) {
if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, Context, NULL, if (!fStackWalk64(machineType, hProcess, hThread, &StackFrame, Context, 0,
SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) {
break; break;
} }
@ -221,7 +228,7 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
static_cast<DWORD>(StackFrame.Params[3])); static_cast<DWORD>(StackFrame.Params[3]));
#endif #endif
// Verify the PC belongs to a module in this process. // Verify the PC belongs to a module in this process.
if (!SymGetModuleBase64(hProcess, PC)) { if (!fSymGetModuleBase64(hProcess, PC)) {
OS << " <unknown module>\n"; OS << " <unknown module>\n";
continue; continue;
} }
@ -234,7 +241,7 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
DWORD64 dwDisp; DWORD64 dwDisp;
if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
OS << '\n'; OS << '\n';
continue; continue;
} }
@ -250,7 +257,7 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,
IMAGEHLP_LINE64 line = {}; IMAGEHLP_LINE64 line = {};
DWORD dwLineDisp; DWORD dwLineDisp;
line.SizeOfStruct = sizeof(line); line.SizeOfStruct = sizeof(line);
if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
OS << format(", %s, line %lu", line.FileName, line.LineNumber); OS << format(", %s, line %lu", line.FileName, line.LineNumber);
if (dwLineDisp > 0) if (dwLineDisp > 0)
OS << format(" + 0x%lX byte(s)", dwLineDisp); OS << format(" + 0x%lX byte(s)", dwLineDisp);
@ -301,17 +308,13 @@ static void InitializeThreading() {
} }
static void RegisterHandler() { static void RegisterHandler() {
#if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR) // If we cannot load up the APIs (which would be unexpected as they should
// On MinGW.org, we need to load up the symbols explicitly, because the // exist on every version of Windows we support), we will bail out since
// Win32 framework they include does not have support for the 64-bit // there would be nothing to report.
// versions of the APIs we need. If we cannot load up the APIs (which
// would be unexpected as they should exist on every version of Windows
// we support), we will bail out since there would be nothing to report.
if (!load64BitDebugHelp()) { if (!load64BitDebugHelp()) {
assert(false && "These APIs should always be available"); assert(false && "These APIs should always be available");
return; return;
} }
#endif
if (RegisteredUnhandledExceptionFilter) { if (RegisteredUnhandledExceptionFilter) {
EnterCriticalSection(&CriticalSection); EnterCriticalSection(&CriticalSection);

View File

@ -33,6 +33,7 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <Windows.h> #include <Windows.h>
#include <DbgHelp.h> #include <DbgHelp.h>
#pragma comment(lib, "dbghelp.lib")
#endif #endif
namespace llvm { namespace llvm {