[RAPPS] Stopped GCC whining (fixed GCC build)
[reactos.git] / rostests / apitests / dbghelp / rsym.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for dbghelp rsym functions
5 * PROGRAMMER: Mark Jansen
6 *
7 * These tests are based on the PDB tests.
8 */
9
10 #include <ntstatus.h>
11 #define WIN32_NO_STATUS
12 #include <windows.h>
13 #include <dbghelp.h>
14 #include <cvconst.h> // SymTagXXX
15 #include <stdio.h>
16
17 #include "wine/test.h"
18
19 #define ok_ulonglong(expression, result) \
20 do { \
21 ULONG64 _value = (expression); \
22 ULONG64 _result = (result); \
23 ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
24 #expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
25 } while (0)
26
27 #define ok_ulonglong_(file, line, expression, result) \
28 do { \
29 ULONG64 _value = (expression); \
30 ULONG64 _result = (result); \
31 ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
32 #expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
33 } while (0)
34
35 #define ok_hex_(file, line, expression, result) \
36 do { \
37 int _value = (expression); \
38 ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (0x%x), got: 0x%x\n", \
39 #expression, (int)(result), _value); \
40 } while (0)
41
42 #define ok_str_(file, line, x, y) \
43 ok_(file, line)(strcmp(x, y) == 0, "Wrong string. Expected '%s', got '%s'\n", y, x)
44
45
46 // data.c
47 void dump_rsym(const char* filename);
48 int extract_gcc_exe(char szFile[MAX_PATH]);
49 void cleanup_gcc_exe();
50
51 static HANDLE proc()
52 {
53 return GetCurrentProcess();
54 }
55
56 static BOOL init_sym_imp(const char* file, int line)
57 {
58 if (!SymInitialize(proc(), NULL, FALSE))
59 {
60 DWORD err = GetLastError();
61 ok_(file, line)(0, "Failed to init: 0x%x\n", err);
62 return FALSE;
63 }
64 return TRUE;
65 }
66
67 static void deinit_sym()
68 {
69 SymCleanup(proc());
70 }
71
72 static BOOL supports_rsym(HANDLE hProc, DWORD64 BaseAddress)
73 {
74 IMAGEHLP_MODULE64 ModuleInfo;
75 BOOL Ret;
76
77 memset(&ModuleInfo, 0, sizeof(ModuleInfo));
78 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
79 Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
80
81 return Ret &&
82 ModuleInfo.SymType == SymDia &&
83 ModuleInfo.CVSig == ('R' | ('S' << 8) | ('Y' << 16) | ('M' << 24));
84 }
85
86 #define init_sym() init_sym_imp(__FILE__, __LINE__)
87
88 #define INIT_PSYM(buff) do { \
89 memset((buff), 0, sizeof((buff))); \
90 ((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
91 ((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
92 } while (0)
93
94
95 static void test_SymFromName(HANDLE hProc, const char* szModuleName)
96 {
97 BOOL Ret;
98 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
99 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
100
101 DWORD64 BaseAddress;
102 DWORD dwErr;
103
104 if (!init_sym())
105 return;
106
107 SetLastError(ERROR_SUCCESS);
108 BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
109 dwErr = GetLastError();
110
111 if (supports_rsym(hProc, BaseAddress))
112 {
113 ok_ulonglong(BaseAddress, 0x600000);
114 ok_hex(dwErr, ERROR_SUCCESS);
115
116 INIT_PSYM(buffer);
117 Ret = SymFromName(hProc, "DllMain", pSymbol);
118 ok_int(Ret, TRUE);
119 ok_ulonglong(pSymbol->ModBase, BaseAddress);
120 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
121 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
122 ok_hex(pSymbol->Tag, SymTagFunction);
123 ok_str(pSymbol->Name, "DllMain");
124
125 INIT_PSYM(buffer);
126 Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
127 ok_int(Ret, TRUE);
128 ok_ulonglong(pSymbol->ModBase, BaseAddress);
129 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
130 ok_ulonglong(pSymbol->Address, BaseAddress + 0x103F);
131 ok_hex(pSymbol->Tag, SymTagFunction);
132 ok_str(pSymbol->Name, "FfsChkdsk");
133
134 INIT_PSYM(buffer);
135 Ret = SymFromName(hProc, "FfsFormat", pSymbol);
136 ok_int(Ret, TRUE);
137 ok_ulonglong(pSymbol->ModBase, BaseAddress);
138 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
139 ok_ulonglong(pSymbol->Address, BaseAddress + 0x100C);
140 ok_hex(pSymbol->Tag, SymTagFunction);
141 ok_str(pSymbol->Name, "FfsFormat");
142 }
143 else
144 {
145 skip("dbghelp.dll cannot parse rsym\n");
146 }
147
148 deinit_sym();
149 }
150
151 static void test_SymFromAddr(HANDLE hProc, const char* szModuleName)
152 {
153 BOOL Ret;
154 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
155 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
156
157 DWORD64 BaseAddress, Displacement;
158 DWORD dwErr;
159
160 if (!init_sym())
161 return;
162
163 SetLastError(ERROR_SUCCESS);
164 BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
165 dwErr = GetLastError();
166
167 if (supports_rsym(hProc, BaseAddress))
168 {
169 ok_ulonglong(BaseAddress, 0x600000);
170 ok_hex(dwErr, ERROR_SUCCESS);
171
172 /* No address found before load address of module */
173 Displacement = 0;
174 INIT_PSYM(buffer);
175 Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
176 dwErr = GetLastError();
177 ok_int(Ret, FALSE);
178 ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
179
180 /* Right at the start of the module is recognized as the first symbol found */
181 Displacement = 0;
182 INIT_PSYM(buffer);
183 Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
184 /* Our dbghelp.dll does not recognize this yet */
185 todo_if(!Ret)
186 {
187 ok_int(Ret, TRUE);
188 ok_ulonglong(Displacement, 0xffffffffffffffff);
189 ok_ulonglong(pSymbol->ModBase, BaseAddress);
190 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
191 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
192 ok_hex(pSymbol->Tag, SymTagFunction);
193 ok_str(pSymbol->Name, "DllMain");
194 }
195
196 /* The actual first instruction of the function */
197 Displacement = 0;
198 INIT_PSYM(buffer);
199 Ret = SymFromAddr(hProc, BaseAddress + 0x1000, &Displacement, pSymbol);
200 ok_int(Ret, TRUE);
201 ok_ulonglong(Displacement, 0);
202 ok_ulonglong(pSymbol->ModBase, BaseAddress);
203 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
204 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
205 ok_hex(pSymbol->Tag, SymTagFunction);
206 ok_str(pSymbol->Name, "DllMain");
207
208 /* The last instruction in the function */
209 Displacement = 0;
210 INIT_PSYM(buffer);
211 Ret = SymFromAddr(hProc, BaseAddress + 0x1009, &Displacement, pSymbol);
212 ok_int(Ret, TRUE);
213 ok_ulonglong(Displacement, 0x9);
214 ok_ulonglong(pSymbol->ModBase, BaseAddress);
215 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
216 ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
217 ok_hex(pSymbol->Tag, SymTagFunction);
218 ok_str(pSymbol->Name, "DllMain");
219
220 /* First byte of the next function */
221 Displacement = 0;
222 INIT_PSYM(buffer);
223 Ret = SymFromAddr(hProc, BaseAddress + 0x103F, &Displacement, pSymbol);
224 ok_int(Ret, TRUE);
225 ok_ulonglong(Displacement, 0);
226 ok_ulonglong(pSymbol->ModBase, BaseAddress);
227 ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
228 ok_ulonglong(pSymbol->Address, BaseAddress + 0x103F);
229 ok_hex(pSymbol->Tag, SymTagFunction);
230 ok_str(pSymbol->Name, "FfsChkdsk");
231
232 /* .idata */
233 Displacement = 0;
234 INIT_PSYM(buffer);
235 Ret = SymFromAddr(hProc, BaseAddress + 0x4000, &Displacement, pSymbol);
236 ok_int(Ret, TRUE);
237 ok_ulonglong(Displacement, 0);
238 ok_ulonglong(pSymbol->ModBase, BaseAddress);
239 ok_hex(pSymbol->Flags, SYMFLAG_EXPORT);
240 ok_ulonglong(pSymbol->Address, BaseAddress + 0x4000);
241 ok_hex(pSymbol->Tag, SymTagPublicSymbol);
242 ok_str(pSymbol->Name, "_head_dll_ntdll_libntdll_a");
243 }
244 else
245 {
246 skip("dbghelp.dll cannot parse rsym\n");
247 }
248
249 deinit_sym();
250 }
251
252 typedef struct _test_context
253 {
254 DWORD64 BaseAddress;
255 SIZE_T Index;
256 } test_context;
257
258 static struct _test_data {
259 DWORD64 AddressOffset;
260 ULONG Size;
261 ULONG Tag;
262 const char* Name;
263 int Line;
264 } test_data[] = {
265
266 /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
267 { 0x107c, 0, SymTagPublicSymbol, "__CTOR_LIST__", __LINE__ },
268 { 0x2074, 0, SymTagPublicSymbol, "__RUNTIME_PSEUDO_RELOC_LIST_END__", __LINE__ },
269 { 0x1000, 12, SymTagPublicSymbol, "EntryPoint", __LINE__ },
270 { 0x100c, 51, SymTagFunction, "FfsFormat", __LINE__ },
271 { 0x4030, 0, SymTagPublicSymbol, "_imp__DbgPrint", __LINE__ },
272 { 0x1084, 0, SymTagPublicSymbol, "__DTOR_LIST__", __LINE__ },
273 { 0x103f, 53, SymTagFunction, "FfsChkdsk", __LINE__ },
274 { 0x2074, 0, SymTagPublicSymbol, "_rt_psrelocs_end", __LINE__ },
275 { 0x103f, 53, SymTagPublicSymbol, "ChkdskEx", __LINE__ },
276 { 0x4048, 0, SymTagPublicSymbol, "_dll_ntdll_libntdll_a_iname", __LINE__ },
277
278
279
280 { 0x2074, 0, SymTagPublicSymbol, "_rt_psrelocs_start", __LINE__ },
281 { 0x1000, 12, SymTagFunction, "DllMain", __LINE__ },
282 { 0x100c, 0, SymTagPublicSymbol, "FormatEx", __LINE__ },
283 { 0x1074, 0, SymTagPublicSymbol, "DbgPrint", __LINE__ },
284 { 0x68900000, 0, SymTagPublicSymbol, "__ImageBase", __LINE__ },
285 { 0x68902074, 0, SymTagPublicSymbol, "__RUNTIME_PSEUDO_RELOC_LIST__", __LINE__ },
286 { 0x4000, 0, SymTagPublicSymbol, "_head_dll_ntdll_libntdll_a", __LINE__ },
287 };
288
289 BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
290 {
291 test_context* ctx = UserContext;
292
293 if (ctx->Index < ARRAYSIZE(test_data))
294 {
295 ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->ModBase, ctx->BaseAddress);
296 if (test_data[ctx->Index].AddressOffset > 0x100000)
297 ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Address, test_data[ctx->Index].AddressOffset);
298 else
299 ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
300 ok_hex_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Tag, test_data[ctx->Index].Tag);
301 ok_str_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Name, test_data[ctx->Index].Name);
302
303 ctx->Index++;
304 }
305 else
306 {
307 ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
308 }
309
310 return TRUE;
311 }
312
313 static void test_SymEnumSymbols(HANDLE hProc, const char* szModuleName)
314 {
315 BOOL Ret;
316 DWORD dwErr;
317
318 test_context ctx;
319
320 if (!init_sym())
321 return;
322
323 ctx.Index = 0;
324 SetLastError(ERROR_SUCCESS);
325 ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
326 dwErr = GetLastError();
327
328 if (supports_rsym(hProc, ctx.BaseAddress))
329 {
330 ok_ulonglong(ctx.BaseAddress, 0x600000);
331 ok_hex(dwErr, ERROR_SUCCESS);
332
333 Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
334 ok_int(Ret, TRUE);
335 ok_int(ctx.Index, ARRAYSIZE(test_data));
336 }
337 else
338 {
339 skip("dbghelp.dll cannot parse rsym\n");
340 }
341
342 deinit_sym();
343 }
344
345
346
347
348 START_TEST(rsym)
349 {
350 char szDllName[MAX_PATH];
351 //dump_rsym("R:\\src\\trunk\\reactos\\modules\\rostests\\apitests\\dbghelp\\testdata\\gcc_uffs.dll");
352
353 DWORD Options = SymGetOptions();
354 Options &= ~(SYMOPT_UNDNAME);
355 //Options |= SYMOPT_DEBUG;
356 SymSetOptions(Options);
357
358 if (!extract_gcc_exe(szDllName))
359 {
360 ok(0, "Failed extracting files\n");
361 return;
362 }
363
364 test_SymFromName(proc(), szDllName);
365 test_SymFromAddr(proc(), szDllName);
366 test_SymEnumSymbols(proc(), szDllName);
367
368 cleanup_gcc_exe();
369 }