2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for dbghelp PDB functions
5 * PROGRAMMER: Mark Jansen
9 #define WIN32_NO_STATUS
12 #include <cvconst.h> // SymTagXXX
15 #include "wine/test.h"
17 #define ok_ulonglong(expression, result) \
19 ULONG64 _value = (expression); \
20 ULONG64 _result = (result); \
21 ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
22 #expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
27 void create_compressed_files();
28 int extract_msvc_exe(char szFile
[MAX_PATH
]);
29 void cleanup_msvc_exe();
33 return GetCurrentProcess();
36 static BOOL
init_sym_imp(const char* file
, int line
)
38 if (!SymInitialize(proc(), NULL
, FALSE
))
40 DWORD err
= GetLastError();
41 ok_(file
, line
)(0, "Failed to init: 0x%x\n", err
);
47 static void deinit_sym()
52 #define init_sym() init_sym_imp(__FILE__, __LINE__)
54 #define INIT_PSYM(buff) do { \
55 memset((buff), 0, sizeof((buff))); \
56 ((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
57 ((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
60 /* modified copy of function from apitests/apphelp/apitest.c */
61 BOOL
get_module_version(
63 _Out_ VS_FIXEDFILEINFO
*fileinfo
)
68 DWORD dwSize
, errcode
= 0;
73 VS_FIXEDFILEINFO
*lpFfi
;
77 errmsg
= "fileinfo is NULL.\n";
81 hResInfo
= FindResource(mod
, MAKEINTRESOURCE(VS_VERSION_INFO
), RT_VERSION
);
84 errmsg
= "FindResource failed";
85 errcode
= GetLastError();
89 dwSize
= SizeofResource(mod
, hResInfo
);
92 errmsg
= "SizeofResource failed";
93 errcode
= GetLastError();
97 hResData
= LoadResource(mod
, hResInfo
);
100 errmsg
= "LoadResource failed";
101 errcode
= GetLastError();
105 pRes
= LockResource(hResData
);
108 errmsg
= "LockResource failed";
109 errcode
= GetLastError();
113 pResCopy
= LocalAlloc(LMEM_FIXED
, dwSize
);
114 if (pResCopy
== NULL
)
116 errmsg
= "LocalAlloc failed";
117 errcode
= GetLastError();
121 CopyMemory(pResCopy
, pRes
, dwSize
);
123 if (VerQueryValueW(pResCopy
, L
"\\", (LPVOID
*)&lpFfi
, &uLen
))
132 FreeResource(hResData
);
133 if (pResCopy
!= NULL
)
140 trace("get_module_version - %s.\n", errmsg
);
142 trace("get_module_version - %s (lasterror %d).\n", errmsg
, errcode
);
146 static VS_FIXEDFILEINFO dbghelpFileVer
;
147 static void init_dbghelp_version()
150 WCHAR filenameW
[MAX_PATH
+ 1];
153 VS_FIXEDFILEINFO fileInfo
;
155 memset(&dbghelpFileVer
, 0, sizeof(dbghelpFileVer
));
157 /* get internal file version */
158 v
= ImagehlpApiVersion();
162 /* get module file version */
163 hDLL
= GetModuleHandleW(L
"dbghelp.dll");
166 ok(FALSE
, "Dbghelp.dll is not loaded!\n");
169 if (!get_module_version(hDLL
, &fileInfo
))
170 memset(&fileInfo
, 0, sizeof(fileInfo
));
171 dbghelpFileVer
= fileInfo
;
173 /* get full file path */
174 fileLen
= GetModuleFileNameW(hDLL
, filenameW
, MAX_PATH
+ 1);
177 ok(FALSE
, "GetModuleFileNameW for dbghelp.dll failed!\n");
181 trace("Using %S\n", filenameW
);
182 trace(" API-Version: %hu.%hu.%hu (%hu)\n",
183 v
->MajorVersion
, v
->MinorVersion
, v
->Revision
, v
->Reserved
);
185 trace(" Fileversion: %hu.%hu.%hu.%hu\n",
186 HIWORD(fileInfo
.dwProductVersionMS
),
187 LOWORD(fileInfo
.dwProductVersionMS
),
188 HIWORD(fileInfo
.dwProductVersionLS
),
189 LOWORD(fileInfo
.dwProductVersionLS
));
192 /* Maybe our dbghelp.dll is too old? */
193 static BOOL
can_enumerate(HANDLE hProc
, DWORD64 BaseAddress
)
195 IMAGEHLP_MODULE64 ModuleInfo
;
198 memset(&ModuleInfo
, 0, sizeof(ModuleInfo
));
199 ModuleInfo
.SizeOfStruct
= sizeof(ModuleInfo
);
200 Ret
= SymGetModuleInfo64(hProc
, BaseAddress
, &ModuleInfo
);
202 return Ret
&& ModuleInfo
.SymType
== SymPdb
;
206 static void test_SymFromName(HANDLE hProc
, const char* szModuleName
)
209 char buffer
[sizeof(SYMBOL_INFO
) + MAX_SYM_NAME
* sizeof(TCHAR
)];
210 PSYMBOL_INFO pSymbol
= (PSYMBOL_INFO
)buffer
;
218 SetLastError(ERROR_SUCCESS
);
219 BaseAddress
= SymLoadModule64(hProc
, NULL
, szModuleName
, NULL
, 0x600000, 0);
220 dwErr
= GetLastError();
222 ok_ulonglong(BaseAddress
, 0x600000);
223 ok_hex(dwErr
, ERROR_SUCCESS
);
225 if (!can_enumerate(hProc
, BaseAddress
))
227 skip("dbghelp.dll too old or cannot enumerate symbols!\n");
232 Ret
= SymFromName(hProc
, "DllMain", pSymbol
);
234 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
235 ok_hex(pSymbol
->Flags
, 0);
236 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
237 ok_hex(pSymbol
->Tag
, SymTagFunction
);
238 ok_str(pSymbol
->Name
, "DllMain");
241 Ret
= SymFromName(hProc
, "_DllMain@12", pSymbol
);
243 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
244 ok_hex(pSymbol
->Flags
, 0x400000); // ??
245 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
246 ok_hex(pSymbol
->Tag
, SymTagPublicSymbol
);
247 ok_str(pSymbol
->Name
, "_DllMain@12");
250 Ret
= SymFromName(hProc
, "FfsChkdsk", pSymbol
);
252 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
253 ok_hex(pSymbol
->Flags
, 0);
254 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1040);
255 ok_hex(pSymbol
->Tag
, SymTagFunction
);
256 ok_str(pSymbol
->Name
, "FfsChkdsk");
259 Ret
= SymFromName(hProc
, "_FfsChkdsk@24", pSymbol
);
261 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
262 ok_hex(pSymbol
->Flags
, 0x400000); // ??
263 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1040);
264 ok_hex(pSymbol
->Tag
, SymTagPublicSymbol
);
265 ok_str(pSymbol
->Name
, "_FfsChkdsk@24");
268 Ret
= SymFromName(hProc
, "FfsFormat", pSymbol
);
270 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
271 ok_hex(pSymbol
->Flags
, 0);
272 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1070);
273 ok_hex(pSymbol
->Tag
, SymTagFunction
);
274 ok_str(pSymbol
->Name
, "FfsFormat");
277 Ret
= SymFromName(hProc
, "_FfsFormat@24", pSymbol
);
279 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
280 ok_hex(pSymbol
->Flags
, 0x400000); // ??
281 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1070);
282 ok_hex(pSymbol
->Tag
, SymTagPublicSymbol
);
283 ok_str(pSymbol
->Name
, "_FfsFormat@24");
289 static void test_SymFromAddr(HANDLE hProc
, const char* szModuleName
)
292 char buffer
[sizeof(SYMBOL_INFO
) + MAX_SYM_NAME
* sizeof(TCHAR
)];
293 PSYMBOL_INFO pSymbol
= (PSYMBOL_INFO
)buffer
;
295 DWORD64 BaseAddress
, Displacement
;
301 SetLastError(ERROR_SUCCESS
);
302 BaseAddress
= SymLoadModule64(hProc
, NULL
, szModuleName
, NULL
, 0x600000, 0);
303 dwErr
= GetLastError();
305 ok_ulonglong(BaseAddress
, 0x600000);
306 ok_hex(dwErr
, ERROR_SUCCESS
);
308 /* No address found before load address of module */
311 Ret
= SymFromAddr(hProc
, BaseAddress
-1, &Displacement
, pSymbol
);
312 dwErr
= GetLastError();
314 ok_hex(dwErr
, ERROR_MOD_NOT_FOUND
);
316 /* Right at the start of the module is recognized as the first symbol found */
319 Ret
= SymFromAddr(hProc
, BaseAddress
, &Displacement
, pSymbol
);
321 ok_ulonglong(Displacement
, 0xffffffffffffffff);
322 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
323 ok_hex(pSymbol
->Flags
, 0);
324 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
325 ok_hex(pSymbol
->Tag
, SymTagFunction
);
326 ok_str(pSymbol
->Name
, "DllMain");
328 /* The actual first instruction of the function */
331 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x1010, &Displacement
, pSymbol
);
333 ok_ulonglong(Displacement
, 0);
334 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
335 ok_hex(pSymbol
->Flags
, 0);
336 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
337 ok_hex(pSymbol
->Tag
, SymTagFunction
);
338 ok_str(pSymbol
->Name
, "DllMain");
340 /* The last instruction in the function */
343 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x102D, &Displacement
, pSymbol
);
345 ok_ulonglong(Displacement
, 0x1d);
346 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
347 ok_hex(pSymbol
->Flags
, 0);
348 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
349 ok_hex(pSymbol
->Tag
, SymTagFunction
);
350 ok_str(pSymbol
->Name
, "DllMain");
352 /* The padding below the function */
355 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x102E, &Displacement
, pSymbol
);
357 ok_ulonglong(Displacement
, 0x1e);
358 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
359 ok_hex(pSymbol
->Flags
, 0);
360 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
361 ok_hex(pSymbol
->Tag
, SymTagFunction
);
362 ok_str(pSymbol
->Name
, "DllMain");
364 /* One byte before the next function */
367 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x103f, &Displacement
, pSymbol
);
369 ok_ulonglong(Displacement
, 0x2f);
370 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
371 ok_hex(pSymbol
->Flags
, 0);
372 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1010);
373 ok_hex(pSymbol
->Tag
, SymTagFunction
);
374 ok_str(pSymbol
->Name
, "DllMain");
376 /* First byte of the next function */
379 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x1040, &Displacement
, pSymbol
);
381 ok_ulonglong(Displacement
, 0);
382 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
383 ok_hex(pSymbol
->Flags
, 0);
384 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1040);
385 ok_hex(pSymbol
->Tag
, SymTagFunction
);
386 ok_str(pSymbol
->Name
, "FfsChkdsk");
388 if (!can_enumerate(hProc
, BaseAddress
))
390 skip("dbghelp.dll too old or cannot read this symbol!\n");
397 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x2000, &Displacement
, pSymbol
);
399 ok_ulonglong(Displacement
, 0);
400 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
401 ok_hex(pSymbol
->Flags
, 0);
402 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x2000);
403 ok_hex(pSymbol
->Tag
, SymTagPublicSymbol
);
404 ok_str(pSymbol
->Name
, "__imp__DbgPrint");
410 typedef struct _test_context
416 static struct _test_data
{
417 DWORD64 AddressOffset
;
422 /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
423 { 0x1070, 36, SymTagFunction
, "FfsFormat" },
424 { 0x1010, 32, SymTagFunction
, "DllMain" },
425 { 0x1040, 36, SymTagFunction
, "FfsChkdsk" },
427 { 0x2100, 0, SymTagPublicSymbol
, "__IMPORT_DESCRIPTOR_ntdll" },
428 { 0x109a, 0, SymTagPublicSymbol
, "_DbgPrint" },
429 { 0x2004, 0, SymTagPublicSymbol
, "\x7fntdll_NULL_THUNK_DATA" },
430 { 0x2000, 0, SymTagPublicSymbol
, "__imp__DbgPrint" },
431 { 0x2114, 0, SymTagPublicSymbol
, "__NULL_IMPORT_DESCRIPTOR" },
434 static BOOL CALLBACK
EnumSymProc(PSYMBOL_INFO pSymInfo
, ULONG SymbolSize
, PVOID UserContext
)
436 test_context
* ctx
= UserContext
;
438 if (ctx
->Index
< ARRAYSIZE(test_data
))
440 ok_ulonglong(pSymInfo
->ModBase
, ctx
->BaseAddress
);
441 ok_ulonglong(pSymInfo
->Address
, ctx
->BaseAddress
+ test_data
[ctx
->Index
].AddressOffset
);
442 ok_hex(pSymInfo
->Tag
, test_data
[ctx
->Index
].Tag
);
443 ok_str(pSymInfo
->Name
, test_data
[ctx
->Index
].Name
);
449 ok(0, "Out of bounds (%lu), max is: %i!\n", ctx
->Index
, ARRAYSIZE(test_data
));
455 static void test_SymEnumSymbols(HANDLE hProc
, const char* szModuleName
)
466 SetLastError(ERROR_SUCCESS
);
467 ctx
.BaseAddress
= SymLoadModule64(hProc
, NULL
, szModuleName
, NULL
, 0x600000, 0);
468 dwErr
= GetLastError();
470 ok_ulonglong(ctx
.BaseAddress
, 0x600000);
471 ok_hex(dwErr
, ERROR_SUCCESS
);
473 if (!can_enumerate(hProc
, ctx
.BaseAddress
))
475 skip("dbghelp.dll too old or cannot enumerate symbols!\n");
479 Ret
= SymEnumSymbols(hProc
, ctx
.BaseAddress
, NULL
, EnumSymProc
, &ctx
);
481 ok_int(ctx
.Index
, ARRAYSIZE(test_data
));
487 typedef struct _symregcallback_context
491 } symregcallback_context
;
493 static struct _symregcallback_test_data
{
496 } symregcallback_test_data
[] = {
497 { CBA_DEFERRED_SYMBOL_LOAD_CANCEL
},
498 { CBA_DEFERRED_SYMBOL_LOAD_START
},
500 { CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
},
501 { CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
}
504 static BOOL CALLBACK
SymRegisterCallback64Proc(
507 ULONG64 CallbackData
,
510 symregcallback_context
*ctx
;
511 ctx
= (symregcallback_context
*)(ULONG_PTR
)UserContext
;
513 if (ctx
->idx
> sizeof(symregcallback_test_data
))
515 ok(FALSE
, "SymRegisterCallback64Proc: Too many calls.\n");
519 ok(ActionCode
== symregcallback_test_data
[ctx
->idx
].ActionCode
,
520 "ActionCode (idx %u) expected %u, got %u\n",
521 ctx
->idx
, symregcallback_test_data
[ctx
->idx
].ActionCode
, ActionCode
);
528 static void test_SymRegCallback(HANDLE hProc
, const char* szModuleName
, BOOL testANSI
)
533 symregcallback_context ctx
;
536 ctx
.isANSI
= testANSI
;
543 Ret
= SymRegisterCallback64(hProc
, SymRegisterCallback64Proc
, (ULONG_PTR
)&ctx
);
547 // dbghelp fileversion 5.2.3790.3959
548 // SymRegisterCallbackW64 crash only happens on real Windows 2003
549 // Fileversion 5.2.3790.3959 is used in Windows 2003.
550 // In ROS there is no crash.
551 // I could not figure out whats wrong.
552 if ((dbghelpFileVer
.dwProductVersionMS
== MAKELONG(2, 5)) &&
553 (dbghelpFileVer
.dwProductVersionLS
== MAKELONG(3959, 3790)))
555 skip("dbghelp.dll ver 5.2.3790.3959 (w2k3), SymRegisterCallbackW64 would crash!\n");
558 Ret
= SymRegisterCallbackW64(hProc
, SymRegisterCallback64Proc
, (ULONG_PTR
)&ctx
);
565 SetLastError(ERROR_SUCCESS
);
566 BaseAddress
= SymLoadModule64(hProc
, NULL
, szModuleName
, NULL
, 0x600000, 0);
567 dwErr
= GetLastError();
569 ok_ulonglong(BaseAddress
, 0x600000);
570 ok_hex(dwErr
, ERROR_SUCCESS
);
572 /* this is what we want to test ... we expect 5 calls */
580 char szDllName
[MAX_PATH
];
581 //create_compressed_files();
583 DWORD Options
= SymGetOptions();
584 Options
&= ~(SYMOPT_UNDNAME
);
585 //Options |= SYMOPT_DEBUG;
586 SymSetOptions(Options
);
588 if (!extract_msvc_exe(szDllName
))
590 ok(0, "Failed extracting files\n");
594 init_dbghelp_version();
596 test_SymFromName(proc(), szDllName
);
597 test_SymFromAddr(proc(), szDllName
);
598 test_SymEnumSymbols(proc(), szDllName
);
599 test_SymRegCallback(proc(), szDllName
, TRUE
);
600 test_SymRegCallback(proc(), szDllName
, FALSE
);