1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS api tests
3*b8a1a612SMark Jansen  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4c2c66affSColin Finck  * PURPOSE:     Test for dbghelp PDB functions
5*b8a1a612SMark Jansen  * COPYRIGHT:   Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org)
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c2c66affSColin Finck #include <ntstatus.h>
9c2c66affSColin Finck #define WIN32_NO_STATUS
10c2c66affSColin Finck #include <windows.h>
11c2c66affSColin Finck #include <dbghelp.h>
12c2c66affSColin Finck #include <cvconst.h>    // SymTagXXX
13c2c66affSColin Finck #include <stdio.h>
14c296ee51SMark Jansen #include <delayimp.h>
15c2c66affSColin Finck 
16c2c66affSColin Finck #include "wine/test.h"
17c2c66affSColin Finck 
18c2c66affSColin Finck #define ok_ulonglong(expression, result) \
19c2c66affSColin Finck     do { \
20c2c66affSColin Finck         ULONG64 _value = (expression); \
21c2c66affSColin Finck         ULONG64 _result = (result); \
22c2c66affSColin Finck         ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
23c2c66affSColin Finck            #expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
24c2c66affSColin Finck     } while (0)
25c2c66affSColin Finck 
26c2c66affSColin Finck 
27c2c66affSColin Finck // data.c
28c2c66affSColin Finck void create_compressed_files();
29*b8a1a612SMark Jansen int extract_msvc_dll(char szFile[MAX_PATH], char szPath[MAX_PATH]);
30*b8a1a612SMark Jansen void cleanup_msvc_dll();
31c2c66affSColin Finck 
32c2c66affSColin Finck static HANDLE proc()
33c2c66affSColin Finck {
34c2c66affSColin Finck     return GetCurrentProcess();
35c2c66affSColin Finck }
36c2c66affSColin Finck 
37*b8a1a612SMark Jansen static BOOL init_sym_imp(BOOL fInvadeProcess, const char* file, int line)
38c2c66affSColin Finck {
39*b8a1a612SMark Jansen     if (!SymInitialize(proc(), NULL, fInvadeProcess))
40c2c66affSColin Finck     {
41c2c66affSColin Finck         DWORD err = GetLastError();
42c2c66affSColin Finck         ok_(file, line)(0, "Failed to init: 0x%x\n", err);
43c2c66affSColin Finck         return FALSE;
44c2c66affSColin Finck     }
45c2c66affSColin Finck     return TRUE;
46c2c66affSColin Finck }
47c2c66affSColin Finck 
48c2c66affSColin Finck static void deinit_sym()
49c2c66affSColin Finck {
50c2c66affSColin Finck     SymCleanup(proc());
51c2c66affSColin Finck }
52c2c66affSColin Finck 
53*b8a1a612SMark Jansen #define init_sym(fInvadeProcess)          init_sym_imp(fInvadeProcess, __FILE__, __LINE__)
54c2c66affSColin Finck 
55c2c66affSColin Finck #define INIT_PSYM(buff) do { \
56c2c66affSColin Finck     memset((buff), 0, sizeof((buff))); \
57c2c66affSColin Finck     ((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
58c2c66affSColin Finck     ((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
59c2c66affSColin Finck } while (0)
60c2c66affSColin Finck 
61184255ffSAndreas Maier /* modified copy of function from apitests/apphelp/apitest.c */
62184255ffSAndreas Maier BOOL get_module_version(
63184255ffSAndreas Maier     _In_ HMODULE mod,
64184255ffSAndreas Maier     _Out_ VS_FIXEDFILEINFO *fileinfo)
65184255ffSAndreas Maier {
66184255ffSAndreas Maier     BOOL res = FALSE;
67184255ffSAndreas Maier     HRSRC hResInfo;
68184255ffSAndreas Maier     char *errmsg;
69184255ffSAndreas Maier     DWORD dwSize, errcode = 0;
70184255ffSAndreas Maier     UINT uLen;
71184255ffSAndreas Maier     HGLOBAL hResData = 0;
72184255ffSAndreas Maier     LPVOID pRes = NULL;
73184255ffSAndreas Maier     HLOCAL pResCopy = 0;
74184255ffSAndreas Maier     VS_FIXEDFILEINFO *lpFfi;
75184255ffSAndreas Maier 
76184255ffSAndreas Maier     if (fileinfo == NULL)
77184255ffSAndreas Maier     {
78184255ffSAndreas Maier         errmsg = "fileinfo is NULL.\n";
79184255ffSAndreas Maier         goto cleanup;
80184255ffSAndreas Maier     }
81184255ffSAndreas Maier 
82184255ffSAndreas Maier     hResInfo = FindResource(mod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
83184255ffSAndreas Maier     if (hResInfo == 0)
84184255ffSAndreas Maier     {
85184255ffSAndreas Maier         errmsg = "FindResource failed";
86184255ffSAndreas Maier         errcode = GetLastError();
87184255ffSAndreas Maier         goto cleanup;
88184255ffSAndreas Maier     }
89184255ffSAndreas Maier 
90184255ffSAndreas Maier     dwSize = SizeofResource(mod, hResInfo);
91184255ffSAndreas Maier     if (dwSize == 0)
92184255ffSAndreas Maier     {
93184255ffSAndreas Maier         errmsg = "SizeofResource failed";
94184255ffSAndreas Maier         errcode = GetLastError();
95184255ffSAndreas Maier         goto cleanup;
96184255ffSAndreas Maier     }
97184255ffSAndreas Maier 
98184255ffSAndreas Maier     hResData = LoadResource(mod, hResInfo);
99184255ffSAndreas Maier     if (hResData == 0)
100184255ffSAndreas Maier     {
101184255ffSAndreas Maier         errmsg = "LoadResource failed";
102184255ffSAndreas Maier         errcode = GetLastError();
103184255ffSAndreas Maier         goto cleanup;
104184255ffSAndreas Maier     }
105184255ffSAndreas Maier 
106184255ffSAndreas Maier     pRes = LockResource(hResData);
107184255ffSAndreas Maier     if (pRes == NULL)
108184255ffSAndreas Maier     {
109184255ffSAndreas Maier         errmsg = "LockResource failed";
110184255ffSAndreas Maier         errcode = GetLastError();
111184255ffSAndreas Maier         goto cleanup;
112184255ffSAndreas Maier     }
113184255ffSAndreas Maier 
114184255ffSAndreas Maier     pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
115184255ffSAndreas Maier     if (pResCopy == NULL)
116184255ffSAndreas Maier     {
117184255ffSAndreas Maier         errmsg = "LocalAlloc failed";
118184255ffSAndreas Maier         errcode = GetLastError();
119184255ffSAndreas Maier         goto cleanup;
120184255ffSAndreas Maier     }
121184255ffSAndreas Maier 
122184255ffSAndreas Maier     CopyMemory(pResCopy, pRes, dwSize);
123184255ffSAndreas Maier 
124184255ffSAndreas Maier     if (VerQueryValueW(pResCopy, L"\\", (LPVOID*)&lpFfi, &uLen))
125184255ffSAndreas Maier     {
126184255ffSAndreas Maier         *fileinfo = *lpFfi;
127184255ffSAndreas Maier         res = TRUE;
128184255ffSAndreas Maier     }
129184255ffSAndreas Maier 
130184255ffSAndreas Maier cleanup:
131184255ffSAndreas Maier     /* cleanup */
132184255ffSAndreas Maier     if (hResData != 0)
133184255ffSAndreas Maier         FreeResource(hResData);
134184255ffSAndreas Maier     if (pResCopy != NULL)
135184255ffSAndreas Maier         LocalFree(pResCopy);
136184255ffSAndreas Maier     /* if it was good */
137184255ffSAndreas Maier     if (res == TRUE)
138184255ffSAndreas Maier         return TRUE;
139184255ffSAndreas Maier     /* failure path */
140184255ffSAndreas Maier     if (errcode == 0)
141184255ffSAndreas Maier         trace("get_module_version - %s.\n", errmsg);
142184255ffSAndreas Maier     else
143184255ffSAndreas Maier         trace("get_module_version - %s (lasterror %d).\n", errmsg, errcode);
144184255ffSAndreas Maier     return FALSE;
145184255ffSAndreas Maier }
146184255ffSAndreas Maier 
147184255ffSAndreas Maier static VS_FIXEDFILEINFO dbghelpFileVer;
148184255ffSAndreas Maier static void init_dbghelp_version()
149184255ffSAndreas Maier {
150184255ffSAndreas Maier     LPAPI_VERSION v;
151184255ffSAndreas Maier     WCHAR filenameW[MAX_PATH + 1];
152184255ffSAndreas Maier     HMODULE hDLL;
153184255ffSAndreas Maier     DWORD fileLen;
154184255ffSAndreas Maier     VS_FIXEDFILEINFO fileInfo;
155184255ffSAndreas Maier 
156184255ffSAndreas Maier     memset(&dbghelpFileVer, 0, sizeof(dbghelpFileVer));
157184255ffSAndreas Maier 
158184255ffSAndreas Maier     /* get internal file version */
159184255ffSAndreas Maier     v = ImagehlpApiVersion();
160184255ffSAndreas Maier     if (v == NULL)
161184255ffSAndreas Maier         return;
162184255ffSAndreas Maier 
163184255ffSAndreas Maier     /* get module file version */
164184255ffSAndreas Maier     hDLL = GetModuleHandleW(L"dbghelp.dll");
165184255ffSAndreas Maier     if (hDLL == 0)
166184255ffSAndreas Maier     {
167184255ffSAndreas Maier         ok(FALSE, "Dbghelp.dll is not loaded!\n");
168184255ffSAndreas Maier         return;
169184255ffSAndreas Maier     }
170184255ffSAndreas Maier     if (!get_module_version(hDLL, &fileInfo))
171184255ffSAndreas Maier         memset(&fileInfo, 0, sizeof(fileInfo));
172184255ffSAndreas Maier     dbghelpFileVer = fileInfo;
173184255ffSAndreas Maier 
174184255ffSAndreas Maier     /* get full file path */
175184255ffSAndreas Maier     fileLen = GetModuleFileNameW(hDLL, filenameW, MAX_PATH + 1);
176184255ffSAndreas Maier     if (fileLen == 0)
177184255ffSAndreas Maier     {
178184255ffSAndreas Maier         ok(FALSE, "GetModuleFileNameW for dbghelp.dll failed!\n");
179184255ffSAndreas Maier         return;
180184255ffSAndreas Maier     }
181184255ffSAndreas Maier 
182184255ffSAndreas Maier     trace("Using %S\n", filenameW);
183184255ffSAndreas Maier     trace("  API-Version: %hu.%hu.%hu (%hu)\n",
184184255ffSAndreas Maier           v->MajorVersion, v->MinorVersion, v->Revision, v->Reserved);
185184255ffSAndreas Maier 
186184255ffSAndreas Maier     trace("  Fileversion: %hu.%hu.%hu.%hu\n",
187184255ffSAndreas Maier           HIWORD(fileInfo.dwProductVersionMS),
188184255ffSAndreas Maier           LOWORD(fileInfo.dwProductVersionMS),
189184255ffSAndreas Maier           HIWORD(fileInfo.dwProductVersionLS),
190184255ffSAndreas Maier           LOWORD(fileInfo.dwProductVersionLS));
191184255ffSAndreas Maier }
192c2c66affSColin Finck 
193c296ee51SMark Jansen static
194c296ee51SMark Jansen int g_SymRegisterCallbackW64NotFound = 0;
195c296ee51SMark Jansen 
196c296ee51SMark Jansen static
197c296ee51SMark Jansen BOOL WINAPI SymRegisterCallbackW64_Stub(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ULONG64 UserContext)
198c296ee51SMark Jansen {
199c296ee51SMark Jansen     g_SymRegisterCallbackW64NotFound++;
200c296ee51SMark Jansen     return FALSE;
201c296ee51SMark Jansen }
202c296ee51SMark Jansen 
203c296ee51SMark Jansen /* A delay-load failure hook will be called when resolving a delay-load dependency (dll or function) fails */
204c296ee51SMark Jansen FARPROC WINAPI DliFailHook(unsigned dliNotify, PDelayLoadInfo pdli)
205c296ee51SMark Jansen {
206c296ee51SMark Jansen     /* Was the failure a function, and did we get info */
207c296ee51SMark Jansen     if (dliNotify == dliFailGetProc && pdli)
208c296ee51SMark Jansen     {
209c296ee51SMark Jansen         /* Is it our function? */
210c296ee51SMark Jansen         if (pdli->dlp.fImportByName && !strcmp(pdli->dlp.szProcName, "SymRegisterCallbackW64"))
211c296ee51SMark Jansen         {
212c296ee51SMark Jansen             /* Redirect execution to the stub */
213c296ee51SMark Jansen             return (FARPROC)SymRegisterCallbackW64_Stub;
214c296ee51SMark Jansen         }
215c296ee51SMark Jansen     }
216c296ee51SMark Jansen     /* This is not the function you are looking for, continue default behavior (throw exception) */
217c296ee51SMark Jansen     return NULL;
218c296ee51SMark Jansen }
219c296ee51SMark Jansen 
220c296ee51SMark Jansen /* Register the failure hook using the magic name '__pfnDliFailureHook2'. */
221c296ee51SMark Jansen PfnDliHook __pfnDliFailureHook2 = DliFailHook;
222c296ee51SMark Jansen 
223c296ee51SMark Jansen 
224c2c66affSColin Finck /* Maybe our dbghelp.dll is too old? */
225*b8a1a612SMark Jansen static BOOL supports_pdb(HANDLE hProc, DWORD64 BaseAddress)
226c2c66affSColin Finck {
227c2c66affSColin Finck     IMAGEHLP_MODULE64 ModuleInfo;
228c2c66affSColin Finck     BOOL Ret;
229c2c66affSColin Finck 
230c2c66affSColin Finck     memset(&ModuleInfo, 0, sizeof(ModuleInfo));
231c2c66affSColin Finck     ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
232c2c66affSColin Finck     Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
233c2c66affSColin Finck 
234c2c66affSColin Finck     return Ret && ModuleInfo.SymType == SymPdb;
235c2c66affSColin Finck }
236c2c66affSColin Finck 
237c2c66affSColin Finck 
238*b8a1a612SMark Jansen static void test_SymFromName(HANDLE hProc, DWORD64 BaseAddress)
239c2c66affSColin Finck {
240c2c66affSColin Finck     BOOL Ret;
241c2c66affSColin Finck     char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
242c2c66affSColin Finck     PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
243c2c66affSColin Finck 
244*b8a1a612SMark Jansen     if (!supports_pdb(hProc, BaseAddress))
245c2c66affSColin Finck     {
246c2c66affSColin Finck         skip("dbghelp.dll too old or cannot enumerate symbols!\n");
247c2c66affSColin Finck     }
248c2c66affSColin Finck     else
249c2c66affSColin Finck     {
250c2c66affSColin Finck         INIT_PSYM(buffer);
251c2c66affSColin Finck         Ret = SymFromName(hProc, "DllMain", pSymbol);
252c2c66affSColin Finck         ok_int(Ret, TRUE);
253c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
254c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0);
255c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
256c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagFunction);
257c2c66affSColin Finck         ok_str(pSymbol->Name, "DllMain");
258c2c66affSColin Finck 
259c2c66affSColin Finck         INIT_PSYM(buffer);
260c2c66affSColin Finck         Ret = SymFromName(hProc, "_DllMain@12", pSymbol);
261c2c66affSColin Finck         ok_int(Ret, TRUE);
262c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
263c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0x400000);   // ??
264c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
265c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
266c2c66affSColin Finck         ok_str(pSymbol->Name, "_DllMain@12");
267c2c66affSColin Finck 
268c2c66affSColin Finck         INIT_PSYM(buffer);
269c2c66affSColin Finck         Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
270c2c66affSColin Finck         ok_int(Ret, TRUE);
271c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
272c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0);
273c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
274c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagFunction);
275c2c66affSColin Finck         ok_str(pSymbol->Name, "FfsChkdsk");
276c2c66affSColin Finck 
277c2c66affSColin Finck         INIT_PSYM(buffer);
278c2c66affSColin Finck         Ret = SymFromName(hProc, "_FfsChkdsk@24", pSymbol);
279c2c66affSColin Finck         ok_int(Ret, TRUE);
280c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
281c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0x400000);   // ??
282c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
283c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
284c2c66affSColin Finck         ok_str(pSymbol->Name, "_FfsChkdsk@24");
285c2c66affSColin Finck 
286c2c66affSColin Finck         INIT_PSYM(buffer);
287c2c66affSColin Finck         Ret = SymFromName(hProc, "FfsFormat", pSymbol);
288c2c66affSColin Finck         ok_int(Ret, TRUE);
289c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
290c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0);
291c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
292c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagFunction);
293c2c66affSColin Finck         ok_str(pSymbol->Name, "FfsFormat");
294c2c66affSColin Finck 
295c2c66affSColin Finck         INIT_PSYM(buffer);
296c2c66affSColin Finck         Ret = SymFromName(hProc, "_FfsFormat@24", pSymbol);
297c2c66affSColin Finck         ok_int(Ret, TRUE);
298c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
299c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0x400000);   // ??
300c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
301c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
302c2c66affSColin Finck         ok_str(pSymbol->Name, "_FfsFormat@24");
303c2c66affSColin Finck     }
304c2c66affSColin Finck }
305c2c66affSColin Finck 
306*b8a1a612SMark Jansen static void test_SymFromAddr(HANDLE hProc, DWORD64 BaseAddress)
307c2c66affSColin Finck {
308c2c66affSColin Finck     BOOL Ret;
309c2c66affSColin Finck     char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
310c2c66affSColin Finck     PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
311c2c66affSColin Finck 
312*b8a1a612SMark Jansen     DWORD64 Displacement;
313c2c66affSColin Finck     DWORD dwErr;
314c2c66affSColin Finck 
315c2c66affSColin Finck     /* No address found before load address of module */
316c2c66affSColin Finck     Displacement = 0;
317c2c66affSColin Finck     INIT_PSYM(buffer);
318c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
319c2c66affSColin Finck     dwErr = GetLastError();
320c2c66affSColin Finck     ok_int(Ret, FALSE);
321c2c66affSColin Finck     ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
322c2c66affSColin Finck 
323c2c66affSColin Finck     /* Right at the start of the module is recognized as the first symbol found */
324c2c66affSColin Finck     Displacement = 0;
325c2c66affSColin Finck     INIT_PSYM(buffer);
326c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
327c2c66affSColin Finck     ok_int(Ret, TRUE);
328c2c66affSColin Finck     ok_ulonglong(Displacement, 0xffffffffffffffff);
329c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
330c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
331c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
332c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
333c2c66affSColin Finck     ok_str(pSymbol->Name, "DllMain");
334c2c66affSColin Finck 
335c2c66affSColin Finck     /* The actual first instruction of the function */
336c2c66affSColin Finck     Displacement = 0;
337c2c66affSColin Finck     INIT_PSYM(buffer);
338c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress + 0x1010, &Displacement, pSymbol);
339c2c66affSColin Finck     ok_int(Ret, TRUE);
340c2c66affSColin Finck     ok_ulonglong(Displacement, 0);
341c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
342c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
343c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
344c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
345c2c66affSColin Finck     ok_str(pSymbol->Name, "DllMain");
346c2c66affSColin Finck 
347c2c66affSColin Finck     /* The last instruction in the function */
348c2c66affSColin Finck     Displacement = 0;
349c2c66affSColin Finck     INIT_PSYM(buffer);
350c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress + 0x102D, &Displacement, pSymbol);
351c2c66affSColin Finck     ok_int(Ret, TRUE);
352c2c66affSColin Finck     ok_ulonglong(Displacement, 0x1d);
353c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
354c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
355c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
356c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
357c2c66affSColin Finck     ok_str(pSymbol->Name, "DllMain");
358c2c66affSColin Finck 
359c2c66affSColin Finck     /* The padding below the function */
360c2c66affSColin Finck     Displacement = 0;
361c2c66affSColin Finck     INIT_PSYM(buffer);
362c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress + 0x102E, &Displacement, pSymbol);
363c2c66affSColin Finck     ok_int(Ret, TRUE);
364c2c66affSColin Finck     ok_ulonglong(Displacement, 0x1e);
365c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
366c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
367c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
368c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
369c2c66affSColin Finck     ok_str(pSymbol->Name, "DllMain");
370c2c66affSColin Finck 
371c2c66affSColin Finck     /* One byte before the next function */
372c2c66affSColin Finck     Displacement = 0;
373c2c66affSColin Finck     INIT_PSYM(buffer);
374c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress + 0x103f, &Displacement, pSymbol);
375c2c66affSColin Finck     ok_int(Ret, TRUE);
376c2c66affSColin Finck     ok_ulonglong(Displacement, 0x2f);
377c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
378c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
379c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
380c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
381c2c66affSColin Finck     ok_str(pSymbol->Name, "DllMain");
382c2c66affSColin Finck 
383c2c66affSColin Finck     /* First byte of the next function */
384c2c66affSColin Finck     Displacement = 0;
385c2c66affSColin Finck     INIT_PSYM(buffer);
386c2c66affSColin Finck     Ret = SymFromAddr(hProc, BaseAddress + 0x1040, &Displacement, pSymbol);
387c2c66affSColin Finck     ok_int(Ret, TRUE);
388c2c66affSColin Finck     ok_ulonglong(Displacement, 0);
389c2c66affSColin Finck     ok_ulonglong(pSymbol->ModBase, BaseAddress);
390c2c66affSColin Finck     ok_hex(pSymbol->Flags, 0);
391c2c66affSColin Finck     ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
392c2c66affSColin Finck     ok_hex(pSymbol->Tag, SymTagFunction);
393c2c66affSColin Finck     ok_str(pSymbol->Name, "FfsChkdsk");
394c2c66affSColin Finck 
395*b8a1a612SMark Jansen     if (!supports_pdb(hProc, BaseAddress))
396c2c66affSColin Finck     {
397c2c66affSColin Finck         skip("dbghelp.dll too old or cannot read this symbol!\n");
398c2c66affSColin Finck     }
399c2c66affSColin Finck     else
400c2c66affSColin Finck     {
401c2c66affSColin Finck         /* .idata */
402c2c66affSColin Finck         Displacement = 0;
403c2c66affSColin Finck         INIT_PSYM(buffer);
404c2c66affSColin Finck         Ret = SymFromAddr(hProc, BaseAddress + 0x2000, &Displacement, pSymbol);
405c2c66affSColin Finck         ok_int(Ret, TRUE);
406c2c66affSColin Finck         ok_ulonglong(Displacement, 0);
407c2c66affSColin Finck         ok_ulonglong(pSymbol->ModBase, BaseAddress);
408c2c66affSColin Finck         ok_hex(pSymbol->Flags, 0);
409c2c66affSColin Finck         ok_ulonglong(pSymbol->Address, BaseAddress + 0x2000);
410c2c66affSColin Finck         ok_hex(pSymbol->Tag, SymTagPublicSymbol);
411c2c66affSColin Finck         ok_str(pSymbol->Name, "__imp__DbgPrint");
412c2c66affSColin Finck     }
413c2c66affSColin Finck }
414c2c66affSColin Finck 
415c2c66affSColin Finck typedef struct _test_context
416c2c66affSColin Finck {
417c2c66affSColin Finck     DWORD64 BaseAddress;
418c2c66affSColin Finck     SIZE_T Index;
419c2c66affSColin Finck } test_context;
420c2c66affSColin Finck 
421c2c66affSColin Finck static struct _test_data {
422c2c66affSColin Finck     DWORD64 AddressOffset;
423c2c66affSColin Finck     ULONG Size;
424c2c66affSColin Finck     ULONG Tag;
425c2c66affSColin Finck     const char* Name;
426c2c66affSColin Finck } test_data[] = {
427c2c66affSColin Finck     /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
428c2c66affSColin Finck     { 0x1070, 36, SymTagFunction, "FfsFormat" },
429c2c66affSColin Finck     { 0x1010, 32, SymTagFunction, "DllMain" },
430c2c66affSColin Finck     { 0x1040, 36, SymTagFunction, "FfsChkdsk" },
431c2c66affSColin Finck 
432c2c66affSColin Finck     { 0x2100, 0, SymTagPublicSymbol, "__IMPORT_DESCRIPTOR_ntdll" },
433c2c66affSColin Finck     { 0x109a, 0, SymTagPublicSymbol, "_DbgPrint" },
434c2c66affSColin Finck     { 0x2004, 0, SymTagPublicSymbol, "\x7fntdll_NULL_THUNK_DATA" },
435c2c66affSColin Finck     { 0x2000, 0, SymTagPublicSymbol, "__imp__DbgPrint" },
436c2c66affSColin Finck     { 0x2114, 0, SymTagPublicSymbol, "__NULL_IMPORT_DESCRIPTOR" },
437c2c66affSColin Finck };
438c2c66affSColin Finck 
439c2c66affSColin Finck static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
440c2c66affSColin Finck {
441c2c66affSColin Finck     test_context* ctx = UserContext;
442c2c66affSColin Finck 
443c2c66affSColin Finck     if (ctx->Index < ARRAYSIZE(test_data))
444c2c66affSColin Finck     {
445c2c66affSColin Finck         ok_ulonglong(pSymInfo->ModBase, ctx->BaseAddress);
446c2c66affSColin Finck         ok_ulonglong(pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
447c2c66affSColin Finck         ok_hex(pSymInfo->Tag, test_data[ctx->Index].Tag);
448c2c66affSColin Finck         ok_str(pSymInfo->Name, test_data[ctx->Index].Name);
449c2c66affSColin Finck 
450c2c66affSColin Finck         ctx->Index++;
451c2c66affSColin Finck     }
452c2c66affSColin Finck     else
453c2c66affSColin Finck     {
454c2c66affSColin Finck         ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
455c2c66affSColin Finck     }
456c2c66affSColin Finck 
457c2c66affSColin Finck     return TRUE;
458c2c66affSColin Finck }
459c2c66affSColin Finck 
460*b8a1a612SMark Jansen static void test_SymEnumSymbols(HANDLE hProc, DWORD64 BaseAddress)
461c2c66affSColin Finck {
462c2c66affSColin Finck     BOOL Ret;
463c2c66affSColin Finck     test_context ctx;
464c2c66affSColin Finck 
465c2c66affSColin Finck     ctx.Index = 0;
466*b8a1a612SMark Jansen     ctx.BaseAddress = BaseAddress;
467c2c66affSColin Finck 
468*b8a1a612SMark Jansen     if (!supports_pdb(hProc, ctx.BaseAddress))
469c2c66affSColin Finck     {
470c2c66affSColin Finck         skip("dbghelp.dll too old or cannot enumerate symbols!\n");
471c2c66affSColin Finck     }
472c2c66affSColin Finck     else
473c2c66affSColin Finck     {
474c2c66affSColin Finck         Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
475c2c66affSColin Finck         ok_int(Ret, TRUE);
476c2c66affSColin Finck         ok_int(ctx.Index, ARRAYSIZE(test_data));
477c2c66affSColin Finck     }
478c2c66affSColin Finck }
479c2c66affSColin Finck 
480184255ffSAndreas Maier typedef struct _symregcallback_context
481184255ffSAndreas Maier {
482184255ffSAndreas Maier     UINT idx;
483184255ffSAndreas Maier     BOOL isANSI;
484184255ffSAndreas Maier } symregcallback_context;
485184255ffSAndreas Maier 
486184255ffSAndreas Maier static struct _symregcallback_test_data {
487184255ffSAndreas Maier     ULONG ActionCode;
488184255ffSAndreas Maier } symregcallback_test_data[] = {
489184255ffSAndreas Maier     { CBA_DEFERRED_SYMBOL_LOAD_CANCEL },
490184255ffSAndreas Maier     { CBA_DEFERRED_SYMBOL_LOAD_START },
491184255ffSAndreas Maier     { CBA_READ_MEMORY },
492184255ffSAndreas Maier     { CBA_DEFERRED_SYMBOL_LOAD_PARTIAL },
493184255ffSAndreas Maier     { CBA_DEFERRED_SYMBOL_LOAD_COMPLETE }
494184255ffSAndreas Maier };
495184255ffSAndreas Maier 
496184255ffSAndreas Maier static BOOL CALLBACK SymRegisterCallback64Proc(
497184255ffSAndreas Maier     HANDLE hProcess,
498184255ffSAndreas Maier     ULONG ActionCode,
499184255ffSAndreas Maier     ULONG64 CallbackData,
500184255ffSAndreas Maier     ULONG64 UserContext)
501184255ffSAndreas Maier {
502184255ffSAndreas Maier     symregcallback_context *ctx;
503184255ffSAndreas Maier     ctx = (symregcallback_context*)(ULONG_PTR)UserContext;
504184255ffSAndreas Maier 
505184255ffSAndreas Maier     if (ctx->idx > sizeof(symregcallback_test_data))
506184255ffSAndreas Maier     {
507184255ffSAndreas Maier         ok(FALSE, "SymRegisterCallback64Proc: Too many calls.\n");
508184255ffSAndreas Maier     }
509184255ffSAndreas Maier     else
510184255ffSAndreas Maier     {
511184255ffSAndreas Maier         ok(ActionCode == symregcallback_test_data[ctx->idx].ActionCode,
512184255ffSAndreas Maier             "ActionCode (idx %u) expected %u, got %u\n",
513184255ffSAndreas Maier             ctx->idx, symregcallback_test_data[ctx->idx].ActionCode, ActionCode);
514184255ffSAndreas Maier     }
515184255ffSAndreas Maier     ctx->idx++;
516184255ffSAndreas Maier 
517184255ffSAndreas Maier     return FALSE;
518184255ffSAndreas Maier }
519184255ffSAndreas Maier 
520184255ffSAndreas Maier static void test_SymRegCallback(HANDLE hProc, const char* szModuleName, BOOL testANSI)
521184255ffSAndreas Maier {
522184255ffSAndreas Maier     BOOL Ret;
523184255ffSAndreas Maier     DWORD dwErr;
524184255ffSAndreas Maier     ULONG64 BaseAddress;
525184255ffSAndreas Maier     symregcallback_context ctx;
526184255ffSAndreas Maier 
527184255ffSAndreas Maier     ctx.idx = 0;
528184255ffSAndreas Maier     ctx.isANSI = testANSI;
529184255ffSAndreas Maier 
530*b8a1a612SMark Jansen     if (!init_sym(FALSE))
531184255ffSAndreas Maier         return;
532184255ffSAndreas Maier 
533184255ffSAndreas Maier     if (testANSI)
534184255ffSAndreas Maier     {
535184255ffSAndreas Maier         Ret = SymRegisterCallback64(hProc, SymRegisterCallback64Proc, (ULONG_PTR)&ctx);
536184255ffSAndreas Maier     }
537184255ffSAndreas Maier     else
538184255ffSAndreas Maier     {
539c296ee51SMark Jansen         Ret = SymRegisterCallbackW64(hProc, SymRegisterCallback64Proc, (ULONG_PTR)&ctx);
540c296ee51SMark Jansen         if (g_SymRegisterCallbackW64NotFound)
541184255ffSAndreas Maier         {
542c296ee51SMark Jansen             skip("SymRegisterCallbackW64 not found in dbghelp.dll\n");
543184255ffSAndreas Maier             return;
544184255ffSAndreas Maier         }
545184255ffSAndreas Maier     }
546184255ffSAndreas Maier 
547184255ffSAndreas Maier     ok_int(Ret, TRUE);
548184255ffSAndreas Maier     if (!Ret)
549184255ffSAndreas Maier         return;
550184255ffSAndreas Maier 
551184255ffSAndreas Maier     SetLastError(ERROR_SUCCESS);
552184255ffSAndreas Maier     BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
553184255ffSAndreas Maier     dwErr = GetLastError();
554184255ffSAndreas Maier 
555184255ffSAndreas Maier     ok_ulonglong(BaseAddress, 0x600000);
556184255ffSAndreas Maier     ok_hex(dwErr, ERROR_SUCCESS);
557184255ffSAndreas Maier 
558184255ffSAndreas Maier     /* this is what we want to test ... we expect 5 calls */
559184255ffSAndreas Maier     ok_int(ctx.idx, 5);
560184255ffSAndreas Maier 
561184255ffSAndreas Maier     deinit_sym();
562184255ffSAndreas Maier }
563c2c66affSColin Finck 
564c2c66affSColin Finck START_TEST(pdb)
565c2c66affSColin Finck {
566c2c66affSColin Finck     char szDllName[MAX_PATH];
567*b8a1a612SMark Jansen     char szDllPath[MAX_PATH], szOldDir[MAX_PATH];
568*b8a1a612SMark Jansen #ifdef _M_IX86
569*b8a1a612SMark Jansen     HMODULE hMod;
570*b8a1a612SMark Jansen #endif
571*b8a1a612SMark Jansen     DWORD64 BaseAddress;
572*b8a1a612SMark Jansen     DWORD dwErr, Options;
573c2c66affSColin Finck 
574*b8a1a612SMark Jansen     Options = SymGetOptions();
575c2c66affSColin Finck     Options &= ~(SYMOPT_UNDNAME);
576c2c66affSColin Finck     //Options |= SYMOPT_DEBUG;
577c2c66affSColin Finck     SymSetOptions(Options);
578c2c66affSColin Finck 
579*b8a1a612SMark Jansen     if (!extract_msvc_dll(szDllName, szDllPath))
580c2c66affSColin Finck     {
581c2c66affSColin Finck         ok(0, "Failed extracting files\n");
582c2c66affSColin Finck         return;
583c2c66affSColin Finck     }
584c2c66affSColin Finck 
585184255ffSAndreas Maier     init_dbghelp_version();
586184255ffSAndreas Maier 
587*b8a1a612SMark Jansen     if (init_sym(FALSE))
588*b8a1a612SMark Jansen     {
589*b8a1a612SMark Jansen         SetLastError(ERROR_SUCCESS);
590*b8a1a612SMark Jansen         BaseAddress = SymLoadModule64(proc(), NULL, szDllName, NULL, 0x600000, 0);
591*b8a1a612SMark Jansen         dwErr = GetLastError();
592*b8a1a612SMark Jansen 
593*b8a1a612SMark Jansen         ok_ulonglong(BaseAddress, 0x600000);
594*b8a1a612SMark Jansen         ok_hex(dwErr, ERROR_SUCCESS);
595*b8a1a612SMark Jansen 
596*b8a1a612SMark Jansen         if (BaseAddress == 0x600000)
597*b8a1a612SMark Jansen         {
598*b8a1a612SMark Jansen             trace("Module loaded by SymLoadModule64\n");
599*b8a1a612SMark Jansen             test_SymFromName(proc(), BaseAddress);
600*b8a1a612SMark Jansen             test_SymFromAddr(proc(), BaseAddress);
601*b8a1a612SMark Jansen             test_SymEnumSymbols(proc(), BaseAddress);
602*b8a1a612SMark Jansen         }
603*b8a1a612SMark Jansen 
604*b8a1a612SMark Jansen         deinit_sym();
605*b8a1a612SMark Jansen     }
606*b8a1a612SMark Jansen 
607*b8a1a612SMark Jansen     /* This needs to load the module by itself */
608184255ffSAndreas Maier     test_SymRegCallback(proc(), szDllName, TRUE);
609184255ffSAndreas Maier     test_SymRegCallback(proc(), szDllName, FALSE);
610c2c66affSColin Finck 
611*b8a1a612SMark Jansen #ifdef _M_IX86
612*b8a1a612SMark Jansen     hMod = LoadLibraryA(szDllName);
613*b8a1a612SMark Jansen     if (hMod)
614*b8a1a612SMark Jansen     {
615*b8a1a612SMark Jansen         BaseAddress = (DWORD64)(DWORD_PTR)hMod;
616*b8a1a612SMark Jansen         /* Make sure we can find the pdb */
617*b8a1a612SMark Jansen         GetCurrentDirectoryA(_countof(szOldDir), szOldDir);
618*b8a1a612SMark Jansen         SetCurrentDirectoryA(szDllPath);
619*b8a1a612SMark Jansen         /* Invade process */
620*b8a1a612SMark Jansen         if (init_sym(TRUE))
621*b8a1a612SMark Jansen         {
622*b8a1a612SMark Jansen             trace("Module loaded by LoadLibraryA\n");
623*b8a1a612SMark Jansen             test_SymFromName(proc(), BaseAddress);
624*b8a1a612SMark Jansen             test_SymFromAddr(proc(), BaseAddress);
625*b8a1a612SMark Jansen             test_SymEnumSymbols(proc(), BaseAddress);
626184255ffSAndreas Maier 
627*b8a1a612SMark Jansen             deinit_sym();
628*b8a1a612SMark Jansen         }
629*b8a1a612SMark Jansen         /* Restore working dir */
630*b8a1a612SMark Jansen         SetCurrentDirectoryA(szOldDir);
631*b8a1a612SMark Jansen 
632*b8a1a612SMark Jansen         FreeLibrary(hMod);
633*b8a1a612SMark Jansen     }
634*b8a1a612SMark Jansen #endif
635*b8a1a612SMark Jansen 
636*b8a1a612SMark Jansen     cleanup_msvc_dll();
637c2c66affSColin Finck }
638