llvm.org GIT mirror llvm / 479dc2c
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241271 91177308-0d34-0410-b5e6-96231b3b80d8 Leny Kholodov 4 years ago
8 changed file(s) with 57 addition(s) and 52 deletion(s). Raw diff Collapse all Expand all
16271627
16281628 AC_CHECK_LIB(m,sin)
16291629 if test "$llvm_cv_os_type" = "MingW" ; then
1630 AC_CHECK_LIB(imagehlp, main)
16311630 AC_CHECK_LIB(ole32, main)
16321631 AC_CHECK_LIB(psapi, main)
16331632 AC_CHECK_LIB(shell32, main)
396396 endif ()
397397
398398 if( MINGW )
399 set(HAVE_LIBIMAGEHLP 1)
400399 set(HAVE_LIBPSAPI 1)
401400 set(HAVE_LIBSHELL32 1)
402401 # TODO: Check existence of libraries.
403402 # include(CheckLibraryExists)
404 # CHECK_LIBRARY_EXISTS(imagehlp ??? . HAVE_LIBIMAGEHLP)
405403 endif( MINGW )
406404
407405 if (NOT HAVE_STRTOLL)
124124 /* Define if you have the libdl library or equivalent. */
125125 #cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
126126
127 /* Define to 1 if you have the `imagehlp' library (-limagehlp). */
128 #cmakedefine HAVE_LIBIMAGEHLP ${HAVE_LIBIMAGEHLP}
129
130127 /* Define to 1 if you have the `m' library (-lm). */
131128 #undef HAVE_LIBM
132129
136136 /* Define if libedit is available on this platform. */
137137 #undef HAVE_LIBEDIT
138138
139 /* Define to 1 if you have the `imagehlp' library (-limagehlp). */
140 #undef HAVE_LIBIMAGEHLP
141
142139 /* Define to 1 if you have the `m' library (-lm). */
143140 #undef HAVE_LIBM
144141
0 set(system_libs)
11 if( NOT MSVC )
22 if( MINGW )
3 set(system_libs ${system_libs} imagehlp psapi shell32 ole32)
3 set(system_libs ${system_libs} psapi shell32 ole32)
44 elseif( CMAKE_HOST_UNIX )
55 if( HAVE_LIBRT )
66 set(system_libs ${system_libs} rt)
2222 #include
2323 #endif
2424
25 #ifdef __MINGW32__
26 #if (HAVE_LIBIMAGEHLP != 1)
27 #error "libimagehlp.a should be present"
28 #endif
29 #else
30 #pragma comment(lib, "dbghelp.lib")
31 #endif
32
3325 namespace llvm {
3426 using namespace sys;
3527
3830 //=== and must not be UNIX code.
3931 //===----------------------------------------------------------------------===//
4032
33 typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID);
34 static fpEnumerateLoadedModules fEnumerateLoadedModules;
4135 static DenseSet *OpenedHandles;
4236
37 static bool loadDebugHelp(void) {
38 HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
39 if (hLib) {
40 fEnumerateLoadedModules = (fpEnumerateLoadedModules)
41 ::GetProcAddress(hLib, "EnumerateLoadedModules64");
42 }
43 return fEnumerateLoadedModules != 0;
44 }
45
4346 static BOOL CALLBACK
44 ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, ULONG_PTR ModuleBase,
47 ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, DWORD64 ModuleBase,
4548 ULONG ModuleSize, PVOID UserContext) {
4649 OpenedHandles->insert((HMODULE)ModuleBase);
4750 return TRUE;
5659 if (OpenedHandles == 0)
5760 OpenedHandles = new DenseSet();
5861
59 EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0);
62 if (!fEnumerateLoadedModules) {
63 if (!loadDebugHelp()) {
64 assert(false && "These APIs should always be available");
65 return DynamicLibrary();
66 }
67 }
68
69 fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0);
6070 // Dummy library that represents "search all handles".
6171 // This is mostly to ensure that the return value still shows up as "valid".
6272 return DynamicLibrary(&OpenedHandles);
3030
3131 #ifdef _MSC_VER
3232 #pragma comment(lib, "psapi.lib")
33 #pragma comment(lib, "dbghelp.lib")
3433 #elif __MINGW32__
35 #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1))
36 #error "libimagehlp.a & libpsapi.a should be present"
34 #if (HAVE_LIBPSAPI != 1)
35 #error "libpsapi.a should be present"
3736 #endif
3837 // The version of g++ that comes with MinGW does *not* properly understand
3938 // the ll format specifier for printf. However, MinGW passes the format
102101 DWORD64 Reserved[3];
103102 KDHELP64 KdHelp;
104103 } STACKFRAME64, *LPSTACKFRAME64;
104 #endif // !defined(__MINGW64_VERSION_MAJOR)
105 #endif // __MINGW32__
105106
106107 typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
107108 DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize,
121122 PFUNCTION_TABLE_ACCESS_ROUTINE64,
122123 PGET_MODULE_BASE_ROUTINE64,
123124 PTRANSLATE_ADDRESS_ROUTINE64);
124 static fpStackWalk64 StackWalk64;
125 static fpStackWalk64 fStackWalk64;
125126
126127 typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64);
127 static fpSymGetModuleBase64 SymGetModuleBase64;
128 static fpSymGetModuleBase64 fSymGetModuleBase64;
128129
129130 typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64,
130131 PDWORD64, PIMAGEHLP_SYMBOL64);
131 static fpSymGetSymFromAddr64 SymGetSymFromAddr64;
132 static fpSymGetSymFromAddr64 fSymGetSymFromAddr64;
132133
133134 typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64,
134135 PDWORD, PIMAGEHLP_LINE64);
135 static fpSymGetLineFromAddr64 SymGetLineFromAddr64;
136 static fpSymGetLineFromAddr64 fSymGetLineFromAddr64;
136137
137138 typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
138 static fpSymFunctionTableAccess64 SymFunctionTableAccess64;
139 static fpSymFunctionTableAccess64 fSymFunctionTableAccess64;
140
141 typedef DWORD (WINAPI *fpSymSetOptions)(DWORD);
142 static fpSymSetOptions fSymSetOptions;
143
144 typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL);
145 static fpSymInitialize fSymInitialize;
139146
140147 static bool load64BitDebugHelp(void) {
141148 HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
142149 if (hLib) {
143 StackWalk64 = (fpStackWalk64)
150 fStackWalk64 = (fpStackWalk64)
144151 ::GetProcAddress(hLib, "StackWalk64");
145 SymGetModuleBase64 = (fpSymGetModuleBase64)
152 fSymGetModuleBase64 = (fpSymGetModuleBase64)
146153 ::GetProcAddress(hLib, "SymGetModuleBase64");
147 SymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
154 fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64)
148155 ::GetProcAddress(hLib, "SymGetSymFromAddr64");
149 SymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
156 fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64)
150157 ::GetProcAddress(hLib, "SymGetLineFromAddr64");
151 SymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
158 fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64)
152159 ::GetProcAddress(hLib, "SymFunctionTableAccess64");
153 }
154 return StackWalk64 != NULL;
155 }
156 #endif // !defined(__MINGW64_VERSION_MAJOR)
157 #endif // __MINGW32__
160 fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions");
161 fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize");
162 }
163 return fStackWalk64 && fSymInitialize && fSymSetOptions;
164 }
158165
159166 // Forward declare.
160167 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep);
186193 #endif
187194
188195 // Initialize the symbol handler.
189 SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
190 SymInitialize(hProcess, NULL, TRUE);
196 fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
197 fSymInitialize(hProcess, NULL, TRUE);
191198
192199 while (true) {
193 if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, Context, NULL,
194 SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
200 if (!fStackWalk64(machineType, hProcess, hThread, &StackFrame, Context, 0,
201 fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) {
195202 break;
196203 }
197204
220227 static_cast(StackFrame.Params[3]));
221228 #endif
222229 // Verify the PC belongs to a module in this process.
223 if (!SymGetModuleBase64(hProcess, PC)) {
230 if (!fSymGetModuleBase64(hProcess, PC)) {
224231 OS << " \n";
225232 continue;
226233 }
233240 symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64);
234241
235242 DWORD64 dwDisp;
236 if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
243 if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) {
237244 OS << '\n';
238245 continue;
239246 }
249256 IMAGEHLP_LINE64 line = {};
250257 DWORD dwLineDisp;
251258 line.SizeOfStruct = sizeof(line);
252 if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
259 if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) {
253260 OS << format(", %s, line %lu", line.FileName, line.LineNumber);
254261 if (dwLineDisp > 0)
255262 OS << format(" + 0x%lX byte(s)", dwLineDisp);
300307 }
301308
302309 static void RegisterHandler() {
303 #if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR)
304 // On MinGW.org, we need to load up the symbols explicitly, because the
305 // Win32 framework they include does not have support for the 64-bit
306 // versions of the APIs we need. If we cannot load up the APIs (which
307 // would be unexpected as they should exist on every version of Windows
308 // we support), we will bail out since there would be nothing to report.
310 // If we cannot load up the APIs (which would be unexpected as they should
311 // exist on every version of Windows we support), we will bail out since
312 // there would be nothing to report.
309313 if (!load64BitDebugHelp()) {
310314 assert(false && "These APIs should always be available");
311315 return;
312316 }
313 #endif
314317
315318 if (RegisteredUnhandledExceptionFilter) {
316319 EnterCriticalSection(&CriticalSection);
3232 #if defined(_MSC_VER)
3333 #include
3434 #include
35 #pragma comment(lib, "dbghelp.lib")
3536 #endif
3637
3738 namespace llvm {