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 } 370