1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Test for dbghelp PDB functions
5  * COPYRIGHT:   Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include <ntstatus.h>
9 #define WIN32_NO_STATUS
10 #include <windows.h>
11 #include <dbghelp.h>
12 #include <cvconst.h>    // SymTagXXX
13 #include <stdio.h>
14 #include <delayimp.h>
15 
16 #include "wine/test.h"
17 
18 #define ok_ulonglong(expression, result) \
19     do { \
20         ULONG64 _value = (expression); \
21         ULONG64 _result = (result); \
22         ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
23            #expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
24     } while (0)
25 
26 
27 // data.c
28 void create_compressed_files();
29 int extract_msvc_dll(char szFile[MAX_PATH], char szPath[MAX_PATH]);
30 void cleanup_msvc_dll();
31 
32 static HANDLE proc()
33 {
34     return GetCurrentProcess();
35 }
36 
37 static BOOL init_sym_imp(BOOL fInvadeProcess, const char* file, int line)
38 {
39     if (!SymInitialize(proc(), NULL, fInvadeProcess))
40     {
41         DWORD err = GetLastError();
42         ok_(file, line)(0, "Failed to init: 0x%x\n", err);
43         return FALSE;
44     }
45     return TRUE;
46 }
47 
48 static void deinit_sym()
49 {
50     SymCleanup(proc());
51 }
52 
53 #define init_sym(fInvadeProcess)          init_sym_imp(fInvadeProcess, __FILE__, __LINE__)
54 
55 #define INIT_PSYM(buff) do { \
56     memset((buff), 0, sizeof((buff))); \
57     ((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
58     ((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
59 } while (0)
60 
61 /* modified copy of function from apitests/apphelp/apitest.c */
62 BOOL get_module_version(
63     _In_ HMODULE mod,
64     _Out_ VS_FIXEDFILEINFO *fileinfo)
65 {
66     BOOL res = FALSE;
67     HRSRC hResInfo;
68     char *errmsg;
69     DWORD dwSize, errcode = 0;
70     UINT uLen;
71     HGLOBAL hResData = 0;
72     LPVOID pRes = NULL;
73     HLOCAL pResCopy = 0;
74     VS_FIXEDFILEINFO *lpFfi;
75 
76     if (fileinfo == NULL)
77     {
78         errmsg = "fileinfo is NULL.\n";
79         goto cleanup;
80     }
81 
82     hResInfo = FindResource(mod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
83     if (hResInfo == 0)
84     {
85         errmsg = "FindResource failed";
86         errcode = GetLastError();
87         goto cleanup;
88     }
89 
90     dwSize = SizeofResource(mod, hResInfo);
91     if (dwSize == 0)
92     {
93         errmsg = "SizeofResource failed";
94         errcode = GetLastError();
95         goto cleanup;
96     }
97 
98     hResData = LoadResource(mod, hResInfo);
99     if (hResData == 0)
100     {
101         errmsg = "LoadResource failed";
102         errcode = GetLastError();
103         goto cleanup;
104     }
105 
106     pRes = LockResource(hResData);
107     if (pRes == NULL)
108     {
109         errmsg = "LockResource failed";
110         errcode = GetLastError();
111         goto cleanup;
112     }
113 
114     pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
115     if (pResCopy == NULL)
116     {
117         errmsg = "LocalAlloc failed";
118         errcode = GetLastError();
119         goto cleanup;
120     }
121 
122     CopyMemory(pResCopy, pRes, dwSize);
123 
124     if (VerQueryValueW(pResCopy, L"\\", (LPVOID*)&lpFfi, &uLen))
125     {
126         *fileinfo = *lpFfi;
127         res = TRUE;
128     }
129 
130 cleanup:
131     /* cleanup */
132     if (hResData != 0)
133         FreeResource(hResData);
134     if (pResCopy != NULL)
135         LocalFree(pResCopy);
136     /* if it was good */
137     if (res == TRUE)
138         return TRUE;
139     /* failure path */
140     if (errcode == 0)
141         trace("get_module_version - %s.\n", errmsg);
142     else
143         trace("get_module_version - %s (lasterror %d).\n", errmsg, errcode);
144     return FALSE;
145 }
146 
147 static VS_FIXEDFILEINFO dbghelpFileVer;
148 static void init_dbghelp_version()
149 {
150     LPAPI_VERSION v;
151     WCHAR filenameW[MAX_PATH + 1];
152     HMODULE hDLL;
153     DWORD fileLen;
154     VS_FIXEDFILEINFO fileInfo;
155 
156     memset(&dbghelpFileVer, 0, sizeof(dbghelpFileVer));
157 
158     /* get internal file version */
159     v = ImagehlpApiVersion();
160     if (v == NULL)
161         return;
162 
163     /* get module file version */
164     hDLL = GetModuleHandleW(L"dbghelp.dll");
165     if (hDLL == 0)
166     {
167         ok(FALSE, "Dbghelp.dll is not loaded!\n");
168         return;
169     }
170     if (!get_module_version(hDLL, &fileInfo))
171         memset(&fileInfo, 0, sizeof(fileInfo));
172     dbghelpFileVer = fileInfo;
173 
174     /* get full file path */
175     fileLen = GetModuleFileNameW(hDLL, filenameW, MAX_PATH + 1);
176     if (fileLen == 0)
177     {
178         ok(FALSE, "GetModuleFileNameW for dbghelp.dll failed!\n");
179         return;
180     }
181 
182     trace("Using %S\n", filenameW);
183     trace("  API-Version: %hu.%hu.%hu (%hu)\n",
184           v->MajorVersion, v->MinorVersion, v->Revision, v->Reserved);
185 
186     trace("  Fileversion: %hu.%hu.%hu.%hu\n",
187           HIWORD(fileInfo.dwProductVersionMS),
188           LOWORD(fileInfo.dwProductVersionMS),
189           HIWORD(fileInfo.dwProductVersionLS),
190           LOWORD(fileInfo.dwProductVersionLS));
191 }
192 
193 static
194 int g_SymRegisterCallbackW64NotFound = 0;
195 
196 static
197 BOOL WINAPI SymRegisterCallbackW64_Stub(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ULONG64 UserContext)
198 {
199     g_SymRegisterCallbackW64NotFound++;
200     return FALSE;
201 }
202 
203 /* A delay-load failure hook will be called when resolving a delay-load dependency (dll or function) fails */
204 FARPROC WINAPI DliFailHook(unsigned dliNotify, PDelayLoadInfo pdli)
205 {
206     /* Was the failure a function, and did we get info */
207     if (dliNotify == dliFailGetProc && pdli)
208     {
209         /* Is it our function? */
210         if (pdli->dlp.fImportByName && !strcmp(pdli->dlp.szProcName, "SymRegisterCallbackW64"))
211         {
212             /* Redirect execution to the stub */
213             return (FARPROC)SymRegisterCallbackW64_Stub;
214         }
215     }
216     /* This is not the function you are looking for, continue default behavior (throw exception) */
217     return NULL;
218 }
219 
220 /* Register the failure hook using the magic name '__pfnDliFailureHook2'. */
221 PfnDliHook __pfnDliFailureHook2 = DliFailHook;
222 
223 
224 /* Maybe our dbghelp.dll is too old? */
225 static BOOL supports_pdb(HANDLE hProc, DWORD64 BaseAddress)
226 {
227     IMAGEHLP_MODULE64 ModuleInfo;
228     BOOL Ret;
229 
230     memset(&ModuleInfo, 0, sizeof(ModuleInfo));
231     ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
232     Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
233 
234     return Ret && ModuleInfo.SymType == SymPdb;
235 }
236 
237 
238 static void test_SymFromName(HANDLE hProc, DWORD64 BaseAddress)
239 {
240     BOOL Ret;
241     char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
242     PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
243 
244     if (!supports_pdb(hProc, BaseAddress))
245     {
246         skip("dbghelp.dll too old or cannot enumerate symbols!\n");
247     }
248     else
249     {
250         INIT_PSYM(buffer);
251         Ret = SymFromName(hProc, "DllMain", pSymbol);
252         ok_int(Ret, TRUE);
253         ok_ulonglong(pSymbol->ModBase, BaseAddress);
254         ok_hex(pSymbol->Flags, 0);
255         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
256         ok_hex(pSymbol->Tag, SymTagFunction);
257         ok_str(pSymbol->Name, "DllMain");
258 
259         INIT_PSYM(buffer);
260         Ret = SymFromName(hProc, "_DllMain@12", pSymbol);
261         ok_int(Ret, TRUE);
262         ok_ulonglong(pSymbol->ModBase, BaseAddress);
263         ok_hex(pSymbol->Flags, 0x400000);   // ??
264         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
265         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
266         ok_str(pSymbol->Name, "_DllMain@12");
267 
268         INIT_PSYM(buffer);
269         Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
270         ok_int(Ret, TRUE);
271         ok_ulonglong(pSymbol->ModBase, BaseAddress);
272         ok_hex(pSymbol->Flags, 0);
273         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
274         ok_hex(pSymbol->Tag, SymTagFunction);
275         ok_str(pSymbol->Name, "FfsChkdsk");
276 
277         INIT_PSYM(buffer);
278         Ret = SymFromName(hProc, "_FfsChkdsk@24", pSymbol);
279         ok_int(Ret, TRUE);
280         ok_ulonglong(pSymbol->ModBase, BaseAddress);
281         ok_hex(pSymbol->Flags, 0x400000);   // ??
282         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
283         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
284         ok_str(pSymbol->Name, "_FfsChkdsk@24");
285 
286         INIT_PSYM(buffer);
287         Ret = SymFromName(hProc, "FfsFormat", pSymbol);
288         ok_int(Ret, TRUE);
289         ok_ulonglong(pSymbol->ModBase, BaseAddress);
290         ok_hex(pSymbol->Flags, 0);
291         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
292         ok_hex(pSymbol->Tag, SymTagFunction);
293         ok_str(pSymbol->Name, "FfsFormat");
294 
295         INIT_PSYM(buffer);
296         Ret = SymFromName(hProc, "_FfsFormat@24", pSymbol);
297         ok_int(Ret, TRUE);
298         ok_ulonglong(pSymbol->ModBase, BaseAddress);
299         ok_hex(pSymbol->Flags, 0x400000);   // ??
300         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
301         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
302         ok_str(pSymbol->Name, "_FfsFormat@24");
303     }
304 }
305 
306 static void test_SymFromAddr(HANDLE hProc, DWORD64 BaseAddress)
307 {
308     BOOL Ret;
309     char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
310     PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
311 
312     DWORD64 Displacement;
313     DWORD dwErr;
314 
315     /* No address found before load address of module */
316     Displacement = 0;
317     INIT_PSYM(buffer);
318     Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
319     dwErr = GetLastError();
320     ok_int(Ret, FALSE);
321     ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
322 
323     /* Right at the start of the module is recognized as the first symbol found */
324     Displacement = 0;
325     INIT_PSYM(buffer);
326     Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
327     ok_int(Ret, TRUE);
328     ok_ulonglong(Displacement, 0xffffffffffffffff);
329     ok_ulonglong(pSymbol->ModBase, BaseAddress);
330     ok_hex(pSymbol->Flags, 0);
331     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
332     ok_hex(pSymbol->Tag, SymTagFunction);
333     ok_str(pSymbol->Name, "DllMain");
334 
335     /* The actual first instruction of the function */
336     Displacement = 0;
337     INIT_PSYM(buffer);
338     Ret = SymFromAddr(hProc, BaseAddress + 0x1010, &Displacement, pSymbol);
339     ok_int(Ret, TRUE);
340     ok_ulonglong(Displacement, 0);
341     ok_ulonglong(pSymbol->ModBase, BaseAddress);
342     ok_hex(pSymbol->Flags, 0);
343     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
344     ok_hex(pSymbol->Tag, SymTagFunction);
345     ok_str(pSymbol->Name, "DllMain");
346 
347     /* The last instruction in the function */
348     Displacement = 0;
349     INIT_PSYM(buffer);
350     Ret = SymFromAddr(hProc, BaseAddress + 0x102D, &Displacement, pSymbol);
351     ok_int(Ret, TRUE);
352     ok_ulonglong(Displacement, 0x1d);
353     ok_ulonglong(pSymbol->ModBase, BaseAddress);
354     ok_hex(pSymbol->Flags, 0);
355     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
356     ok_hex(pSymbol->Tag, SymTagFunction);
357     ok_str(pSymbol->Name, "DllMain");
358 
359     /* The padding below the function */
360     Displacement = 0;
361     INIT_PSYM(buffer);
362     Ret = SymFromAddr(hProc, BaseAddress + 0x102E, &Displacement, pSymbol);
363     ok_int(Ret, TRUE);
364     ok_ulonglong(Displacement, 0x1e);
365     ok_ulonglong(pSymbol->ModBase, BaseAddress);
366     ok_hex(pSymbol->Flags, 0);
367     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
368     ok_hex(pSymbol->Tag, SymTagFunction);
369     ok_str(pSymbol->Name, "DllMain");
370 
371     /* One byte before the next function */
372     Displacement = 0;
373     INIT_PSYM(buffer);
374     Ret = SymFromAddr(hProc, BaseAddress + 0x103f, &Displacement, pSymbol);
375     ok_int(Ret, TRUE);
376     ok_ulonglong(Displacement, 0x2f);
377     ok_ulonglong(pSymbol->ModBase, BaseAddress);
378     ok_hex(pSymbol->Flags, 0);
379     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
380     ok_hex(pSymbol->Tag, SymTagFunction);
381     ok_str(pSymbol->Name, "DllMain");
382 
383     /* First byte of the next function */
384     Displacement = 0;
385     INIT_PSYM(buffer);
386     Ret = SymFromAddr(hProc, BaseAddress + 0x1040, &Displacement, pSymbol);
387     ok_int(Ret, TRUE);
388     ok_ulonglong(Displacement, 0);
389     ok_ulonglong(pSymbol->ModBase, BaseAddress);
390     ok_hex(pSymbol->Flags, 0);
391     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
392     ok_hex(pSymbol->Tag, SymTagFunction);
393     ok_str(pSymbol->Name, "FfsChkdsk");
394 
395     if (!supports_pdb(hProc, BaseAddress))
396     {
397         skip("dbghelp.dll too old or cannot read this symbol!\n");
398     }
399     else
400     {
401         /* .idata */
402         Displacement = 0;
403         INIT_PSYM(buffer);
404         Ret = SymFromAddr(hProc, BaseAddress + 0x2000, &Displacement, pSymbol);
405         ok_int(Ret, TRUE);
406         ok_ulonglong(Displacement, 0);
407         ok_ulonglong(pSymbol->ModBase, BaseAddress);
408         ok_hex(pSymbol->Flags, 0);
409         ok_ulonglong(pSymbol->Address, BaseAddress + 0x2000);
410         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
411         ok_str(pSymbol->Name, "__imp__DbgPrint");
412     }
413 }
414 
415 typedef struct _test_context
416 {
417     DWORD64 BaseAddress;
418     SIZE_T Index;
419 } test_context;
420 
421 static struct _test_data {
422     DWORD64 AddressOffset;
423     ULONG Size;
424     ULONG Tag;
425     const char* Name;
426 } test_data[] = {
427     /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
428     { 0x1070, 36, SymTagFunction, "FfsFormat" },
429     { 0x1010, 32, SymTagFunction, "DllMain" },
430     { 0x1040, 36, SymTagFunction, "FfsChkdsk" },
431 
432     { 0x2100, 0, SymTagPublicSymbol, "__IMPORT_DESCRIPTOR_ntdll" },
433     { 0x109a, 0, SymTagPublicSymbol, "_DbgPrint" },
434     { 0x2004, 0, SymTagPublicSymbol, "\x7fntdll_NULL_THUNK_DATA" },
435     { 0x2000, 0, SymTagPublicSymbol, "__imp__DbgPrint" },
436     { 0x2114, 0, SymTagPublicSymbol, "__NULL_IMPORT_DESCRIPTOR" },
437 };
438 
439 static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
440 {
441     test_context* ctx = UserContext;
442 
443     if (ctx->Index < ARRAYSIZE(test_data))
444     {
445         ok_ulonglong(pSymInfo->ModBase, ctx->BaseAddress);
446         ok_ulonglong(pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
447         ok_hex(pSymInfo->Tag, test_data[ctx->Index].Tag);
448         ok_str(pSymInfo->Name, test_data[ctx->Index].Name);
449 
450         ctx->Index++;
451     }
452     else
453     {
454         ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
455     }
456 
457     return TRUE;
458 }
459 
460 static void test_SymEnumSymbols(HANDLE hProc, DWORD64 BaseAddress)
461 {
462     BOOL Ret;
463     test_context ctx;
464 
465     ctx.Index = 0;
466     ctx.BaseAddress = BaseAddress;
467 
468     if (!supports_pdb(hProc, ctx.BaseAddress))
469     {
470         skip("dbghelp.dll too old or cannot enumerate symbols!\n");
471     }
472     else
473     {
474         Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
475         ok_int(Ret, TRUE);
476         ok_int(ctx.Index, ARRAYSIZE(test_data));
477     }
478 }
479 
480 typedef struct _symregcallback_context
481 {
482     UINT idx;
483     BOOL isANSI;
484 } symregcallback_context;
485 
486 static struct _symregcallback_test_data {
487     ULONG ActionCode;
488 } symregcallback_test_data[] = {
489     { CBA_DEFERRED_SYMBOL_LOAD_CANCEL },
490     { CBA_DEFERRED_SYMBOL_LOAD_START },
491     { CBA_READ_MEMORY },
492     { CBA_DEFERRED_SYMBOL_LOAD_PARTIAL },
493     { CBA_DEFERRED_SYMBOL_LOAD_COMPLETE }
494 };
495 
496 static BOOL CALLBACK SymRegisterCallback64Proc(
497     HANDLE hProcess,
498     ULONG ActionCode,
499     ULONG64 CallbackData,
500     ULONG64 UserContext)
501 {
502     symregcallback_context *ctx;
503     ctx = (symregcallback_context*)(ULONG_PTR)UserContext;
504 
505     if (ctx->idx > sizeof(symregcallback_test_data))
506     {
507         ok(FALSE, "SymRegisterCallback64Proc: Too many calls.\n");
508     }
509     else
510     {
511         ok(ActionCode == symregcallback_test_data[ctx->idx].ActionCode,
512             "ActionCode (idx %u) expected %u, got %u\n",
513             ctx->idx, symregcallback_test_data[ctx->idx].ActionCode, ActionCode);
514     }
515     ctx->idx++;
516 
517     return FALSE;
518 }
519 
520 static void test_SymRegCallback(HANDLE hProc, const char* szModuleName, BOOL testANSI)
521 {
522     BOOL Ret;
523     DWORD dwErr;
524     ULONG64 BaseAddress;
525     symregcallback_context ctx;
526 
527     ctx.idx = 0;
528     ctx.isANSI = testANSI;
529 
530     if (!init_sym(FALSE))
531         return;
532 
533     if (testANSI)
534     {
535         Ret = SymRegisterCallback64(hProc, SymRegisterCallback64Proc, (ULONG_PTR)&ctx);
536     }
537     else
538     {
539         Ret = SymRegisterCallbackW64(hProc, SymRegisterCallback64Proc, (ULONG_PTR)&ctx);
540         if (g_SymRegisterCallbackW64NotFound)
541         {
542             skip("SymRegisterCallbackW64 not found in dbghelp.dll\n");
543             return;
544         }
545     }
546 
547     ok_int(Ret, TRUE);
548     if (!Ret)
549         return;
550 
551     SetLastError(ERROR_SUCCESS);
552     BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
553     dwErr = GetLastError();
554 
555     ok_ulonglong(BaseAddress, 0x600000);
556     ok_hex(dwErr, ERROR_SUCCESS);
557 
558     /* this is what we want to test ... we expect 5 calls */
559     ok_int(ctx.idx, 5);
560 
561     deinit_sym();
562 }
563 
564 START_TEST(pdb)
565 {
566     char szDllName[MAX_PATH];
567     char szDllPath[MAX_PATH], szOldDir[MAX_PATH];
568 #ifdef _M_IX86
569     HMODULE hMod;
570 #endif
571     DWORD64 BaseAddress;
572     DWORD dwErr, Options;
573 
574     Options = SymGetOptions();
575     Options &= ~(SYMOPT_UNDNAME);
576     //Options |= SYMOPT_DEBUG;
577     SymSetOptions(Options);
578 
579     if (!extract_msvc_dll(szDllName, szDllPath))
580     {
581         ok(0, "Failed extracting files\n");
582         return;
583     }
584 
585     init_dbghelp_version();
586 
587     if (init_sym(FALSE))
588     {
589         SetLastError(ERROR_SUCCESS);
590         BaseAddress = SymLoadModule64(proc(), NULL, szDllName, NULL, 0x600000, 0);
591         dwErr = GetLastError();
592 
593         ok_ulonglong(BaseAddress, 0x600000);
594         ok_hex(dwErr, ERROR_SUCCESS);
595 
596         if (BaseAddress == 0x600000)
597         {
598             trace("Module loaded by SymLoadModule64\n");
599             test_SymFromName(proc(), BaseAddress);
600             test_SymFromAddr(proc(), BaseAddress);
601             test_SymEnumSymbols(proc(), BaseAddress);
602         }
603 
604         deinit_sym();
605     }
606 
607     /* This needs to load the module by itself */
608     test_SymRegCallback(proc(), szDllName, TRUE);
609     test_SymRegCallback(proc(), szDllName, FALSE);
610 
611 #ifdef _M_IX86
612     hMod = LoadLibraryA(szDllName);
613     if (hMod)
614     {
615         BaseAddress = (DWORD64)(DWORD_PTR)hMod;
616         /* Make sure we can find the pdb */
617         GetCurrentDirectoryA(_countof(szOldDir), szOldDir);
618         SetCurrentDirectoryA(szDllPath);
619         /* Invade process */
620         if (init_sym(TRUE))
621         {
622             trace("Module loaded by LoadLibraryA\n");
623             test_SymFromName(proc(), BaseAddress);
624             test_SymFromAddr(proc(), BaseAddress);
625             test_SymEnumSymbols(proc(), BaseAddress);
626 
627             deinit_sym();
628         }
629         /* Restore working dir */
630         SetCurrentDirectoryA(szOldDir);
631 
632         FreeLibrary(hMod);
633     }
634 #endif
635 
636     cleanup_msvc_dll();
637 }
638