1 /* 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) 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 36 // data.c 37 void dump_rsym(const char* filename); 38 int extract_gcc_dll(char szFile[MAX_PATH]); 39 void cleanup_gcc_dll(); 40 41 static HANDLE proc() 42 { 43 return GetCurrentProcess(); 44 } 45 46 static BOOL init_sym_imp(BOOL fInvadeProcess, const char* file, int line) 47 { 48 if (!SymInitialize(proc(), NULL, fInvadeProcess)) 49 { 50 DWORD err = GetLastError(); 51 ok_(file, line)(0, "Failed to init: 0x%x\n", err); 52 return FALSE; 53 } 54 return TRUE; 55 } 56 57 static void deinit_sym() 58 { 59 SymCleanup(proc()); 60 } 61 62 #define init_sym(fInvadeProcess) init_sym_imp(fInvadeProcess, __FILE__, __LINE__) 63 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; \ 68 } while (0) 69 70 static BOOL supports_rsym(HANDLE hProc, DWORD64 BaseAddress) 71 { 72 IMAGEHLP_MODULE64 ModuleInfo; 73 BOOL Ret; 74 75 memset(&ModuleInfo, 0, sizeof(ModuleInfo)); 76 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); 77 Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo); 78 79 return Ret && 80 ModuleInfo.SymType == SymDia && 81 ModuleInfo.CVSig == ('R' | ('S' << 8) | ('Y' << 16) | ('M' << 24)); 82 } 83 84 85 static void test_SymFromName(HANDLE hProc, DWORD64 BaseAddress) 86 { 87 BOOL Ret; 88 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; 89 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; 90 91 if (!supports_rsym(hProc, BaseAddress)) 92 { 93 skip("dbghelp.dll cannot parse rsym\n"); 94 } 95 else 96 { 97 INIT_PSYM(buffer); 98 Ret = SymFromName(hProc, "DllMain", pSymbol); 99 ok_int(Ret, TRUE); 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"); 105 106 INIT_PSYM(buffer); 107 Ret = SymFromName(hProc, "FfsChkdsk", pSymbol); 108 ok_int(Ret, TRUE); 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"); 114 115 INIT_PSYM(buffer); 116 Ret = SymFromName(hProc, "FfsFormat", pSymbol); 117 ok_int(Ret, TRUE); 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"); 123 } 124 } 125 126 static void test_SymFromAddr(HANDLE hProc, DWORD64 BaseAddress) 127 { 128 BOOL Ret; 129 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; 130 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; 131 132 DWORD64 Displacement; 133 DWORD dwErr; 134 135 if (!supports_rsym(hProc, BaseAddress)) 136 { 137 skip("dbghelp.dll cannot parse rsym\n"); 138 } 139 else 140 { 141 /* No address found before load address of module */ 142 Displacement = 0; 143 INIT_PSYM(buffer); 144 Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol); 145 dwErr = GetLastError(); 146 ok_int(Ret, FALSE); 147 ok_hex(dwErr, ERROR_MOD_NOT_FOUND); 148 149 /* Right at the start of the module is recognized as the first symbol found */ 150 Displacement = 0; 151 INIT_PSYM(buffer); 152 Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol); 153 /* Our dbghelp.dll does not recognize this yet */ 154 todo_if(!Ret) 155 { 156 ok_int(Ret, TRUE); 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"); 163 } 164 165 /* The actual first instruction of the function */ 166 Displacement = 0; 167 INIT_PSYM(buffer); 168 Ret = SymFromAddr(hProc, BaseAddress + 0x1000, &Displacement, pSymbol); 169 ok_int(Ret, TRUE); 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"); 176 177 /* The last instruction in the function */ 178 Displacement = 0; 179 INIT_PSYM(buffer); 180 Ret = SymFromAddr(hProc, BaseAddress + 0x1009, &Displacement, pSymbol); 181 ok_int(Ret, TRUE); 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"); 188 189 /* First byte of the next function */ 190 Displacement = 0; 191 INIT_PSYM(buffer); 192 Ret = SymFromAddr(hProc, BaseAddress + 0x103F, &Displacement, pSymbol); 193 ok_int(Ret, TRUE); 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"); 200 201 /* .idata */ 202 Displacement = 0; 203 INIT_PSYM(buffer); 204 Ret = SymFromAddr(hProc, BaseAddress + 0x4000, &Displacement, pSymbol); 205 ok_int(Ret, TRUE); 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"); 212 } 213 } 214 215 typedef struct _test_context 216 { 217 DWORD64 BaseAddress; 218 SIZE_T Index; 219 } test_context; 220 221 static struct _test_data { 222 DWORD64 AddressOffset; 223 ULONG Size; 224 ULONG Tag; 225 const char* Name; 226 int Line; 227 } test_data[] = { 228 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__ }, 240 241 242 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__ }, 250 }; 251 252 static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext) 253 { 254 test_context* ctx = UserContext; 255 256 if (ctx->Index < ARRAYSIZE(test_data)) 257 { 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); 261 else 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); 265 266 ctx->Index++; 267 } 268 else 269 { 270 ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data)); 271 } 272 273 return TRUE; 274 } 275 276 static void test_SymEnumSymbols(HANDLE hProc, DWORD64 BaseAddress) 277 { 278 BOOL Ret; 279 test_context ctx; 280 281 ctx.Index = 0; 282 ctx.BaseAddress = BaseAddress; 283 284 if (!supports_rsym(hProc, ctx.BaseAddress)) 285 { 286 skip("dbghelp.dll cannot parse rsym\n"); 287 } 288 else 289 { 290 Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx); 291 ok_int(Ret, TRUE); 292 ok_int(ctx.Index, ARRAYSIZE(test_data)); 293 } 294 } 295 296 297 START_TEST(rsym) 298 { 299 char szDllName[MAX_PATH]; 300 #ifdef _M_IX86 301 HMODULE hMod; 302 #endif 303 DWORD64 BaseAddress; 304 DWORD dwErr, Options; 305 306 Options = SymGetOptions(); 307 Options &= ~(SYMOPT_UNDNAME); 308 //Options |= SYMOPT_DEBUG; 309 SymSetOptions(Options); 310 311 if (!extract_gcc_dll(szDllName)) 312 { 313 ok(0, "Failed extracting files\n"); 314 return; 315 } 316 317 if (init_sym(FALSE)) 318 { 319 SetLastError(ERROR_SUCCESS); 320 BaseAddress = SymLoadModule64(proc(), NULL, szDllName, NULL, 0x600000, 0); 321 dwErr = GetLastError(); 322 323 ok_ulonglong(BaseAddress, 0x600000); 324 ok(dwErr == ERROR_SUCCESS || dwErr == ERROR_FILE_NOT_FOUND, "Got 0x%x\n", dwErr); 325 326 if (BaseAddress == 0x600000) 327 { 328 trace("Module loaded by SymLoadModule64\n"); 329 test_SymFromName(proc(), BaseAddress); 330 test_SymFromAddr(proc(), BaseAddress); 331 test_SymEnumSymbols(proc(), BaseAddress); 332 } 333 334 deinit_sym(); 335 } 336 337 #ifdef _M_IX86 338 hMod = LoadLibraryA(szDllName); 339 if (hMod) 340 { 341 BaseAddress = (DWORD64)(DWORD_PTR)hMod; 342 /* Invade process */ 343 if (init_sym(TRUE)) 344 { 345 trace("Module loaded by LoadLibraryA\n"); 346 test_SymFromName(proc(), BaseAddress); 347 test_SymFromAddr(proc(), BaseAddress); 348 test_SymEnumSymbols(proc(), BaseAddress); 349 350 deinit_sym(); 351 } 352 353 FreeLibrary(hMod); 354 } 355 #endif 356 cleanup_gcc_dll(); 357 } 358