[SHELL32_APITEST] -Add some tests for SHParseDisplayName for CORE-12882.
[reactos.git] / rostests / apitests / dbghelp / pdb.c
1 /*
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
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
15 #include "wine/test.h"
16
17 #define ok_ulonglong(expression, result) \
18 do { \
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)); \
23 } while (0)
24
25
26 // data.c
27 void create_compressed_files();
28 int extract_msvc_exe(char szFile[MAX_PATH]);
29 void cleanup_msvc_exe();
30
31 static HANDLE proc()
32 {
33 return GetCurrentProcess();
34 }
35
36 static BOOL init_sym_imp(const char* file, int line)
37 {
38 if (!SymInitialize(proc(), NULL, FALSE))
39 {
40 DWORD err = GetLastError();
41 ok_(file, line)(0, "Failed to init: 0x%x\n", err);
42 return FALSE;
43 }
44 return TRUE;
45 }
46
47 static void deinit_sym()
48 {
49 SymCleanup(proc());
50 }
51
52 #define init_sym() init_sym_imp(__FILE__, __LINE__)
53
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; \
58 } while (0)
59
60
61 /* Maybe our dbghelp.dll is too old? */
62 static BOOL can_enumerate(HANDLE hProc, DWORD64 BaseAddress)
63 {
64 IMAGEHLP_MODULE64 ModuleInfo;
65 BOOL Ret;
66
67 memset(&ModuleInfo, 0, sizeof(ModuleInfo));
68 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
69 Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
70
71 return Ret && ModuleInfo.SymType == SymPdb;
72 }
73
74
75 static void test_SymFromName(HANDLE hProc, const char* szModuleName)
76 {
77 BOOL Ret;
78 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
79 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
80
81 DWORD64 BaseAddress;
82 DWORD dwErr;
83
84 if (!init_sym())
85 return;
86
87 SetLastError(ERROR_SUCCESS);
88 BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
89 dwErr = GetLastError();
90
91 ok_ulonglong(BaseAddress, 0x600000);
92 ok_hex(dwErr, ERROR_SUCCESS);
93
94 if (!can_enumerate(hProc, BaseAddress))
95 {
96 skip("dbghelp.dll too old or cannot enumerate symbols!\n");
97 }
98 else
99 {
100 INIT_PSYM(buffer);
101 Ret = SymFromName(hProc, "DllMain", pSymbol);
102 ok_int(Ret, TRUE);
103 ok_ulonglong(pSymbol->ModBase, BaseAddress);
104 ok_hex(pSymbol->Flags, 0);
105 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
106 ok_hex(pSymbol->Tag, SymTagFunction);
107 ok_str(pSymbol->Name, "DllMain");
108
109 INIT_PSYM(buffer);
110 Ret = SymFromName(hProc, "_DllMain@12", pSymbol);
111 ok_int(Ret, TRUE);
112 ok_ulonglong(pSymbol->ModBase, BaseAddress);
113 ok_hex(pSymbol->Flags, 0x400000); // ??
114 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
115 ok_hex(pSymbol->Tag, SymTagPublicSymbol);
116 ok_str(pSymbol->Name, "_DllMain@12");
117
118 INIT_PSYM(buffer);
119 Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
120 ok_int(Ret, TRUE);
121 ok_ulonglong(pSymbol->ModBase, BaseAddress);
122 ok_hex(pSymbol->Flags, 0);
123 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
124 ok_hex(pSymbol->Tag, SymTagFunction);
125 ok_str(pSymbol->Name, "FfsChkdsk");
126
127 INIT_PSYM(buffer);
128 Ret = SymFromName(hProc, "_FfsChkdsk@24", pSymbol);
129 ok_int(Ret, TRUE);
130 ok_ulonglong(pSymbol->ModBase, BaseAddress);
131 ok_hex(pSymbol->Flags, 0x400000); // ??
132 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
133 ok_hex(pSymbol->Tag, SymTagPublicSymbol);
134 ok_str(pSymbol->Name, "_FfsChkdsk@24");
135
136 INIT_PSYM(buffer);
137 Ret = SymFromName(hProc, "FfsFormat", pSymbol);
138 ok_int(Ret, TRUE);
139 ok_ulonglong(pSymbol->ModBase, BaseAddress);
140 ok_hex(pSymbol->Flags, 0);
141 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
142 ok_hex(pSymbol->Tag, SymTagFunction);
143 ok_str(pSymbol->Name, "FfsFormat");
144
145 INIT_PSYM(buffer);
146 Ret = SymFromName(hProc, "_FfsFormat@24", pSymbol);
147 ok_int(Ret, TRUE);
148 ok_ulonglong(pSymbol->ModBase, BaseAddress);
149 ok_hex(pSymbol->Flags, 0x400000); // ??
150 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
151 ok_hex(pSymbol->Tag, SymTagPublicSymbol);
152 ok_str(pSymbol->Name, "_FfsFormat@24");
153 }
154
155 deinit_sym();
156 }
157
158 static void test_SymFromAddr(HANDLE hProc, const char* szModuleName)
159 {
160 BOOL Ret;
161 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
162 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
163
164 DWORD64 BaseAddress, Displacement;
165 DWORD dwErr;
166
167 if (!init_sym())
168 return;
169
170 SetLastError(ERROR_SUCCESS);
171 BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
172 dwErr = GetLastError();
173
174 ok_ulonglong(BaseAddress, 0x600000);
175 ok_hex(dwErr, ERROR_SUCCESS);
176
177 /* No address found before load address of module */
178 Displacement = 0;
179 INIT_PSYM(buffer);
180 Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
181 dwErr = GetLastError();
182 ok_int(Ret, FALSE);
183 ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
184
185 /* Right at the start of the module is recognized as the first symbol found */
186 Displacement = 0;
187 INIT_PSYM(buffer);
188 Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
189 ok_int(Ret, TRUE);
190 ok_ulonglong(Displacement, 0xffffffffffffffff);
191 ok_ulonglong(pSymbol->ModBase, BaseAddress);
192 ok_hex(pSymbol->Flags, 0);
193 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
194 ok_hex(pSymbol->Tag, SymTagFunction);
195 ok_str(pSymbol->Name, "DllMain");
196
197 /* The actual first instruction of the function */
198 Displacement = 0;
199 INIT_PSYM(buffer);
200 Ret = SymFromAddr(hProc, BaseAddress + 0x1010, &Displacement, pSymbol);
201 ok_int(Ret, TRUE);
202 ok_ulonglong(Displacement, 0);
203 ok_ulonglong(pSymbol->ModBase, BaseAddress);
204 ok_hex(pSymbol->Flags, 0);
205 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
206 ok_hex(pSymbol->Tag, SymTagFunction);
207 ok_str(pSymbol->Name, "DllMain");
208
209 /* The last instruction in the function */
210 Displacement = 0;
211 INIT_PSYM(buffer);
212 Ret = SymFromAddr(hProc, BaseAddress + 0x102D, &Displacement, pSymbol);
213 ok_int(Ret, TRUE);
214 ok_ulonglong(Displacement, 0x1d);
215 ok_ulonglong(pSymbol->ModBase, BaseAddress);
216 ok_hex(pSymbol->Flags, 0);
217 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
218 ok_hex(pSymbol->Tag, SymTagFunction);
219 ok_str(pSymbol->Name, "DllMain");
220
221 /* The padding below the function */
222 Displacement = 0;
223 INIT_PSYM(buffer);
224 Ret = SymFromAddr(hProc, BaseAddress + 0x102E, &Displacement, pSymbol);
225 ok_int(Ret, TRUE);
226 ok_ulonglong(Displacement, 0x1e);
227 ok_ulonglong(pSymbol->ModBase, BaseAddress);
228 ok_hex(pSymbol->Flags, 0);
229 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
230 ok_hex(pSymbol->Tag, SymTagFunction);
231 ok_str(pSymbol->Name, "DllMain");
232
233 /* One byte before the next function */
234 Displacement = 0;
235 INIT_PSYM(buffer);
236 Ret = SymFromAddr(hProc, BaseAddress + 0x103f, &Displacement, pSymbol);
237 ok_int(Ret, TRUE);
238 ok_ulonglong(Displacement, 0x2f);
239 ok_ulonglong(pSymbol->ModBase, BaseAddress);
240 ok_hex(pSymbol->Flags, 0);
241 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
242 ok_hex(pSymbol->Tag, SymTagFunction);
243 ok_str(pSymbol->Name, "DllMain");
244
245 /* First byte of the next function */
246 Displacement = 0;
247 INIT_PSYM(buffer);
248 Ret = SymFromAddr(hProc, BaseAddress + 0x1040, &Displacement, pSymbol);
249 ok_int(Ret, TRUE);
250 ok_ulonglong(Displacement, 0);
251 ok_ulonglong(pSymbol->ModBase, BaseAddress);
252 ok_hex(pSymbol->Flags, 0);
253 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
254 ok_hex(pSymbol->Tag, SymTagFunction);
255 ok_str(pSymbol->Name, "FfsChkdsk");
256
257 if (!can_enumerate(hProc, BaseAddress))
258 {
259 skip("dbghelp.dll too old or cannot read this symbol!\n");
260 }
261 else
262 {
263 /* .idata */
264 Displacement = 0;
265 INIT_PSYM(buffer);
266 Ret = SymFromAddr(hProc, BaseAddress + 0x2000, &Displacement, pSymbol);
267 ok_int(Ret, TRUE);
268 ok_ulonglong(Displacement, 0);
269 ok_ulonglong(pSymbol->ModBase, BaseAddress);
270 ok_hex(pSymbol->Flags, 0);
271 ok_ulonglong(pSymbol->Address, BaseAddress + 0x2000);
272 ok_hex(pSymbol->Tag, SymTagPublicSymbol);
273 ok_str(pSymbol->Name, "__imp__DbgPrint");
274 }
275
276 deinit_sym();
277 }
278
279 typedef struct _test_context
280 {
281 DWORD64 BaseAddress;
282 SIZE_T Index;
283 } test_context;
284
285 static struct _test_data {
286 DWORD64 AddressOffset;
287 ULONG Size;
288 ULONG Tag;
289 const char* Name;
290 } test_data[] = {
291 /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
292 { 0x1070, 36, SymTagFunction, "FfsFormat" },
293 { 0x1010, 32, SymTagFunction, "DllMain" },
294 { 0x1040, 36, SymTagFunction, "FfsChkdsk" },
295
296 { 0x2100, 0, SymTagPublicSymbol, "__IMPORT_DESCRIPTOR_ntdll" },
297 { 0x109a, 0, SymTagPublicSymbol, "_DbgPrint" },
298 { 0x2004, 0, SymTagPublicSymbol, "\x7fntdll_NULL_THUNK_DATA" },
299 { 0x2000, 0, SymTagPublicSymbol, "__imp__DbgPrint" },
300 { 0x2114, 0, SymTagPublicSymbol, "__NULL_IMPORT_DESCRIPTOR" },
301 };
302
303 static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
304 {
305 test_context* ctx = UserContext;
306
307 if (ctx->Index < ARRAYSIZE(test_data))
308 {
309 ok_ulonglong(pSymInfo->ModBase, ctx->BaseAddress);
310 ok_ulonglong(pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
311 ok_hex(pSymInfo->Tag, test_data[ctx->Index].Tag);
312 ok_str(pSymInfo->Name, test_data[ctx->Index].Name);
313
314 ctx->Index++;
315 }
316 else
317 {
318 ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
319 }
320
321 return TRUE;
322 }
323
324 static void test_SymEnumSymbols(HANDLE hProc, const char* szModuleName)
325 {
326 BOOL Ret;
327 DWORD dwErr;
328
329 test_context ctx;
330
331 if (!init_sym())
332 return;
333
334 ctx.Index = 0;
335 SetLastError(ERROR_SUCCESS);
336 ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
337 dwErr = GetLastError();
338
339 ok_ulonglong(ctx.BaseAddress, 0x600000);
340 ok_hex(dwErr, ERROR_SUCCESS);
341
342 if (!can_enumerate(hProc, ctx.BaseAddress))
343 {
344 skip("dbghelp.dll too old or cannot enumerate symbols!\n");
345 }
346 else
347 {
348 Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
349 ok_int(Ret, TRUE);
350 ok_int(ctx.Index, ARRAYSIZE(test_data));
351 }
352
353 deinit_sym();
354 }
355
356
357 START_TEST(pdb)
358 {
359 char szDllName[MAX_PATH];
360 //create_compressed_files();
361
362 DWORD Options = SymGetOptions();
363 Options &= ~(SYMOPT_UNDNAME);
364 //Options |= SYMOPT_DEBUG;
365 SymSetOptions(Options);
366
367 if (!extract_msvc_exe(szDllName))
368 {
369 ok(0, "Failed extracting files\n");
370 return;
371 }
372
373 test_SymFromName(proc(), szDllName);
374 test_SymFromAddr(proc(), szDllName);
375 test_SymEnumSymbols(proc(), szDllName);
376
377 cleanup_msvc_exe();
378 }