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