2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Test for dbghelp rsym functions
5 * COPYRIGHT: Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org)
7 * These tests are based on the PDB tests.
11 #define WIN32_NO_STATUS
14 #include <cvconst.h> // SymTagXXX
17 #include "wine/test.h"
19 #define ok_ulonglong(expression, result) \
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)); \
27 #define ok_ulonglong_(file, line, expression, result) \
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)); \
37 void dump_rsym(const char* filename
);
38 int extract_gcc_dll(char szFile
[MAX_PATH
]);
39 void cleanup_gcc_dll();
43 return GetCurrentProcess();
46 static BOOL
init_sym_imp(BOOL fInvadeProcess
, const char* file
, int line
)
48 if (!SymInitialize(proc(), NULL
, fInvadeProcess
))
50 DWORD err
= GetLastError();
51 ok_(file
, line
)(0, "Failed to init: 0x%x\n", err
);
57 static void deinit_sym()
62 #define init_sym(fInvadeProcess) init_sym_imp(fInvadeProcess, __FILE__, __LINE__)
64 #define INIT_PSYM(buff) do { \
65 memset((buff), 0, sizeof((buff))); \
66 ((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
67 ((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
70 static BOOL
supports_rsym(HANDLE hProc
, DWORD64 BaseAddress
)
72 IMAGEHLP_MODULE64 ModuleInfo
;
75 memset(&ModuleInfo
, 0, sizeof(ModuleInfo
));
76 ModuleInfo
.SizeOfStruct
= sizeof(ModuleInfo
);
77 Ret
= SymGetModuleInfo64(hProc
, BaseAddress
, &ModuleInfo
);
80 ModuleInfo
.SymType
== SymDia
&&
81 ModuleInfo
.CVSig
== ('R' | ('S' << 8) | ('Y' << 16) | ('M' << 24));
85 static void test_SymFromName(HANDLE hProc
, DWORD64 BaseAddress
)
88 char buffer
[sizeof(SYMBOL_INFO
) + MAX_SYM_NAME
* sizeof(TCHAR
)];
89 PSYMBOL_INFO pSymbol
= (PSYMBOL_INFO
)buffer
;
91 if (!supports_rsym(hProc
, BaseAddress
))
93 skip("dbghelp.dll cannot parse rsym\n");
98 Ret
= SymFromName(hProc
, "DllMain", pSymbol
);
100 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
101 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
102 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1000);
103 ok_hex(pSymbol
->Tag
, SymTagFunction
);
104 ok_str(pSymbol
->Name
, "DllMain");
107 Ret
= SymFromName(hProc
, "FfsChkdsk", pSymbol
);
109 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
110 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
111 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x103F);
112 ok_hex(pSymbol
->Tag
, SymTagFunction
);
113 ok_str(pSymbol
->Name
, "FfsChkdsk");
116 Ret
= SymFromName(hProc
, "FfsFormat", pSymbol
);
118 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
119 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
120 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x100C);
121 ok_hex(pSymbol
->Tag
, SymTagFunction
);
122 ok_str(pSymbol
->Name
, "FfsFormat");
126 static void test_SymFromAddr(HANDLE hProc
, DWORD64 BaseAddress
)
129 char buffer
[sizeof(SYMBOL_INFO
) + MAX_SYM_NAME
* sizeof(TCHAR
)];
130 PSYMBOL_INFO pSymbol
= (PSYMBOL_INFO
)buffer
;
132 DWORD64 Displacement
;
135 if (!supports_rsym(hProc
, BaseAddress
))
137 skip("dbghelp.dll cannot parse rsym\n");
141 /* No address found before load address of module */
144 Ret
= SymFromAddr(hProc
, BaseAddress
-1, &Displacement
, pSymbol
);
145 dwErr
= GetLastError();
147 ok_hex(dwErr
, ERROR_MOD_NOT_FOUND
);
149 /* Right at the start of the module is recognized as the first symbol found */
152 Ret
= SymFromAddr(hProc
, BaseAddress
, &Displacement
, pSymbol
);
153 /* Our dbghelp.dll does not recognize this yet */
157 ok_ulonglong(Displacement
, 0xffffffffffffffff);
158 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
159 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
160 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1000);
161 ok_hex(pSymbol
->Tag
, SymTagFunction
);
162 ok_str(pSymbol
->Name
, "DllMain");
165 /* The actual first instruction of the function */
168 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x1000, &Displacement
, pSymbol
);
170 ok_ulonglong(Displacement
, 0);
171 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
172 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
173 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1000);
174 ok_hex(pSymbol
->Tag
, SymTagFunction
);
175 ok_str(pSymbol
->Name
, "DllMain");
177 /* The last instruction in the function */
180 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x1009, &Displacement
, pSymbol
);
182 ok_ulonglong(Displacement
, 0x9);
183 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
184 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
185 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x1000);
186 ok_hex(pSymbol
->Tag
, SymTagFunction
);
187 ok_str(pSymbol
->Name
, "DllMain");
189 /* First byte of the next function */
192 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x103F, &Displacement
, pSymbol
);
194 ok_ulonglong(Displacement
, 0);
195 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
196 ok_hex(pSymbol
->Flags
, SYMFLAG_FUNCTION
);
197 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x103F);
198 ok_hex(pSymbol
->Tag
, SymTagFunction
);
199 ok_str(pSymbol
->Name
, "FfsChkdsk");
204 Ret
= SymFromAddr(hProc
, BaseAddress
+ 0x4000, &Displacement
, pSymbol
);
206 ok_ulonglong(Displacement
, 0);
207 ok_ulonglong(pSymbol
->ModBase
, BaseAddress
);
208 ok_hex(pSymbol
->Flags
, SYMFLAG_EXPORT
);
209 ok_ulonglong(pSymbol
->Address
, BaseAddress
+ 0x4000);
210 ok_hex(pSymbol
->Tag
, SymTagPublicSymbol
);
211 ok_str(pSymbol
->Name
, "_head_dll_ntdll_libntdll_a");
215 typedef struct _test_context
221 static struct _test_data
{
222 DWORD64 AddressOffset
;
229 /* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
230 { 0x107c, 0, SymTagPublicSymbol
, "__CTOR_LIST__", __LINE__
},
231 { 0x2074, 0, SymTagPublicSymbol
, "__RUNTIME_PSEUDO_RELOC_LIST_END__", __LINE__
},
232 { 0x1000, 12, SymTagPublicSymbol
, "EntryPoint", __LINE__
},
233 { 0x100c, 51, SymTagFunction
, "FfsFormat", __LINE__
},
234 { 0x4030, 0, SymTagPublicSymbol
, "_imp__DbgPrint", __LINE__
},
235 { 0x1084, 0, SymTagPublicSymbol
, "__DTOR_LIST__", __LINE__
},
236 { 0x103f, 53, SymTagFunction
, "FfsChkdsk", __LINE__
},
237 { 0x2074, 0, SymTagPublicSymbol
, "_rt_psrelocs_end", __LINE__
},
238 { 0x103f, 53, SymTagPublicSymbol
, "ChkdskEx", __LINE__
},
239 { 0x4048, 0, SymTagPublicSymbol
, "_dll_ntdll_libntdll_a_iname", __LINE__
},
243 { 0x2074, 0, SymTagPublicSymbol
, "_rt_psrelocs_start", __LINE__
},
244 { 0x1000, 12, SymTagFunction
, "DllMain", __LINE__
},
245 { 0x100c, 0, SymTagPublicSymbol
, "FormatEx", __LINE__
},
246 { 0x1074, 0, SymTagPublicSymbol
, "DbgPrint", __LINE__
},
247 { 0x68900000, 0, SymTagPublicSymbol
, "__ImageBase", __LINE__
},
248 { 0x68902074, 0, SymTagPublicSymbol
, "__RUNTIME_PSEUDO_RELOC_LIST__", __LINE__
},
249 { 0x4000, 0, SymTagPublicSymbol
, "_head_dll_ntdll_libntdll_a", __LINE__
},
252 static BOOL CALLBACK
EnumSymProc(PSYMBOL_INFO pSymInfo
, ULONG SymbolSize
, PVOID UserContext
)
254 test_context
* ctx
= UserContext
;
256 if (ctx
->Index
< ARRAYSIZE(test_data
))
258 ok_ulonglong_(__FILE__
, test_data
[ctx
->Index
].Line
, pSymInfo
->ModBase
, ctx
->BaseAddress
);
259 if (test_data
[ctx
->Index
].AddressOffset
> 0x100000)
260 ok_ulonglong_(__FILE__
, test_data
[ctx
->Index
].Line
, pSymInfo
->Address
, test_data
[ctx
->Index
].AddressOffset
);
262 ok_ulonglong_(__FILE__
, test_data
[ctx
->Index
].Line
, pSymInfo
->Address
, ctx
->BaseAddress
+ test_data
[ctx
->Index
].AddressOffset
);
263 ok_hex_(__FILE__
, test_data
[ctx
->Index
].Line
, pSymInfo
->Tag
, test_data
[ctx
->Index
].Tag
);
264 ok_str_(__FILE__
, test_data
[ctx
->Index
].Line
, pSymInfo
->Name
, test_data
[ctx
->Index
].Name
);
270 ok(0, "Out of bounds (%lu), max is: %i!\n", ctx
->Index
, ARRAYSIZE(test_data
));
276 static void test_SymEnumSymbols(HANDLE hProc
, DWORD64 BaseAddress
)
282 ctx
.BaseAddress
= BaseAddress
;
284 if (!supports_rsym(hProc
, ctx
.BaseAddress
))
286 skip("dbghelp.dll cannot parse rsym\n");
290 Ret
= SymEnumSymbols(hProc
, ctx
.BaseAddress
, NULL
, EnumSymProc
, &ctx
);
292 ok_int(ctx
.Index
, ARRAYSIZE(test_data
));
299 char szDllName
[MAX_PATH
];
304 DWORD dwErr
, Options
;
306 Options
= SymGetOptions();
307 Options
&= ~(SYMOPT_UNDNAME
);
308 //Options |= SYMOPT_DEBUG;
309 SymSetOptions(Options
);
311 if (!extract_gcc_dll(szDllName
))
313 ok(0, "Failed extracting files\n");
319 SetLastError(ERROR_SUCCESS
);
320 BaseAddress
= SymLoadModule64(proc(), NULL
, szDllName
, NULL
, 0x600000, 0);
321 dwErr
= GetLastError();
323 ok_ulonglong(BaseAddress
, 0x600000);
324 ok_hex(dwErr
, ERROR_SUCCESS
);
326 if (BaseAddress
== 0x600000)
328 trace("Module loaded by SymLoadModule64\n");
329 test_SymFromName(proc(), BaseAddress
);
330 test_SymFromAddr(proc(), BaseAddress
);
331 test_SymEnumSymbols(proc(), BaseAddress
);
338 hMod
= LoadLibraryA(szDllName
);
341 BaseAddress
= (DWORD64
)(DWORD_PTR
)hMod
;
345 trace("Module loaded by LoadLibraryA\n");
346 test_SymFromName(proc(), BaseAddress
);
347 test_SymFromAddr(proc(), BaseAddress
);
348 test_SymEnumSymbols(proc(), BaseAddress
);