[DBGHELP_APITEST] Add tests for pdb and rsym parsing. CORE-12773

svn path=/trunk/; revision=73816
This commit is contained in:
Mark Jansen 2017-02-17 16:15:49 +00:00
parent 17a622f506
commit e2c97e602f
10 changed files with 1063 additions and 0 deletions

View file

@ -7,6 +7,7 @@ add_subdirectory(atl)
add_subdirectory(browseui)
add_subdirectory(com)
add_subdirectory(crt)
add_subdirectory(dbghelp)
add_subdirectory(dciman32)
add_subdirectory(dnsapi)
add_subdirectory(gdi32)

View file

@ -0,0 +1,20 @@
add_definitions(-D__ROS_LONG64__ -DWINETEST_USE_DBGSTR_LONGLONG)
include_directories(
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib
${REACTOS_SOURCE_DIR}/sdk/tools/rsym
)
list(APPEND SOURCE
pdb.c
rsym.c
data.c
testlist.c)
add_executable(dbghelp_apitest ${SOURCE} resource.rc)
set_module_type(dbghelp_apitest win32cui)
target_link_libraries(dbghelp_apitest zlib)
add_delay_importlibs(dbghelp_apitest dbghelp)
add_importlibs(dbghelp_apitest msvcrt kernel32 ntdll)
add_rostests_file(TARGET dbghelp_apitest)

View file

@ -0,0 +1,277 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Support functions for dbghelp api test
* PROGRAMMER: Mark Jansen
*/
#include <windows.h>
#include <stdio.h>
#include <zlib.h>
#include "wine/test.h"
extern IMAGE_DOS_HEADER __ImageBase;
static char szTempPath[MAX_PATH];
static const char* tmpdir()
{
if (szTempPath[0] == '\0')
{
GetTempPathA(MAX_PATH, szTempPath);
lstrcatA(szTempPath, "dbghelp_tst");
}
return szTempPath;
}
static int extract_one(const char* filename, const char* resid)
{
HMODULE mod = (HMODULE)&__ImageBase;
HGLOBAL glob;
PVOID data, decompressed;
uLongf size, dstsize;
DWORD gccSize, dwErr;
HANDLE file;
int ret;
HRSRC rsrc = FindResourceA(mod, resid, MAKEINTRESOURCEA(RT_RCDATA));
ok(rsrc != 0, "Failed finding '%s' res\n", resid);
if (!rsrc)
return 0;
size = SizeofResource(mod, rsrc);
glob = LoadResource(mod, rsrc);
ok(glob != NULL, "Failed loading '%s' res\n", resid);
if (!glob)
return 0;
data = LockResource(glob);
dstsize = 1024 * 256;
decompressed = malloc(dstsize);
if (uncompress(decompressed, &dstsize, data, size) != Z_OK)
{
ok(0, "uncompress failed for %s\n", resid);
free(decompressed);
return 0;
}
file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
gccSize = size;
ret = WriteFile(file, decompressed, dstsize, &gccSize, NULL);
dwErr = GetLastError();
CloseHandle(file);
free(decompressed);
ok(ret, "WriteFile failed (%d)\n", dwErr);
return ret && dstsize == gccSize;
}
int extract_msvc_exe(char szFile[MAX_PATH])
{
const char* dir = tmpdir();
BOOL ret = CreateDirectoryA(dir, NULL);
ok(ret, "CreateDirectoryA failed(%d)\n", GetLastError());
sprintf(szFile, "%s\\uffs.pdb", dir);
if (!extract_one(szFile, "msvc_uffs.pdb"))
return 0;
sprintf(szFile, "%s\\uffs.dll", dir);
if (!extract_one(szFile, "msvc_uffs.dll"))
return 0;
return 1;
}
void cleanup_msvc_exe()
{
char szFile[MAX_PATH];
BOOL ret;
const char* dir = tmpdir();
sprintf(szFile, "%s\\uffs.pdb", dir);
ret = DeleteFileA(szFile);
ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
sprintf(szFile, "%s\\uffs.dll", dir);
ret = DeleteFileA(szFile);
ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
ret = RemoveDirectoryA(dir);
ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
}
int extract_gcc_exe(char szFile[MAX_PATH])
{
const char* dir = tmpdir();
BOOL ret = CreateDirectoryA(dir, NULL);
ok(ret, "CreateDirectoryA failed(%d)\n", GetLastError());
sprintf(szFile, "%s\\uffs.dll", dir);
if (!extract_one(szFile, "gcc_uffs.dll"))
return 0;
return 1;
}
void cleanup_gcc_exe()
{
char szFile[MAX_PATH];
BOOL ret;
const char* dir = tmpdir();
sprintf(szFile, "%s\\uffs.dll", dir);
ret = DeleteFileA(szFile);
ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
ret = RemoveDirectoryA(dir);
ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
}
#if 0
static int compress_one(const char* src, const char* dest)
{
DWORD size, size2, res;
FILE* file = fopen(src, "rb");
fseek(file, 0, SEEK_END);
size = ftell(file);
fseek(file, 0, SEEK_SET);
Bytef* buffer, *buffer2;
DWORD dwErr = GetLastError();
buffer = malloc(size);
res = fread(buffer, 1, size, file);
fclose(file);
if (res != size)
{
printf("Could not read file: 0x%x\n", dwErr);
free(buffer);
CloseHandle(file);
return 0;
}
size2 = size *2;
buffer2 = malloc(size2);
res = compress(buffer2, &size2, buffer, size);
free(buffer);
if (Z_OK != res)
{
free(buffer2);
return 0;
}
file = fopen(dest, "wb");
res = fwrite(buffer2, 1, size2, file);
fclose(file);
free(buffer2);
return size2 == res;
}
void create_compressed_files()
{
SetCurrentDirectoryA("R:/src/trunk/reactos/modules/rostests/apitests/dbghelp");
if (!compress_one("testdata/msvc_uffs.dll", "testdata/msvc_uffs.dll.compr"))
printf("msvc_uffs.dll failed\n");
if (!compress_one("testdata/msvc_uffs.pdb", "testdata/msvc_uffs.pdb.compr"))
printf("msvc_uffs.pdb failed\n");
if (!compress_one("testdata/gcc_uffs.dll", "testdata/gcc_uffs.dll.compr"))
printf("gcc_uffs.dll failed\n");
}
#endif
#if 0
typedef struct _SYMBOLFILE_HEADER {
ULONG SymbolsOffset;
ULONG SymbolsLength;
ULONG StringsOffset;
ULONG StringsLength;
} SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
typedef struct _ROSSYM_ENTRY {
ULONG Address;
ULONG FunctionOffset;
ULONG FileOffset;
ULONG SourceLine;
} ROSSYM_ENTRY, *PROSSYM_ENTRY;
static int is_metadata(const char* name)
{
size_t len = name ? strlen(name) : 0;
return len > 3 && name[0] == '_' && name[1] != '_' && name[len-1] == '_' && name[len-2] == '_';
};
static void dump_rsym_internal(void* data)
{
PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data;
PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char *)data + RosSymHeader->SymbolsOffset);
size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
size_t i;
char *Strings = (char *)data + RosSymHeader->StringsOffset;
for (i = 0; i < symbols; i++)
{
PROSSYM_ENTRY Entry = Entries + i;
if (!Entry->FileOffset)
{
if (Entry->SourceLine)
printf("ERR: SOURCELINE (%D) ", Entry->SourceLine);
if (is_metadata(Strings + Entry->FunctionOffset))
printf("metadata: %s: 0x%x\n", Strings + Entry->FunctionOffset, Entry->Address);
else
printf("0x%x: %s\n", Entry->Address, Strings + Entry->FunctionOffset);
}
else
{
printf("0x%x: %s (%s:%u)\n", Entry->Address,
Strings + Entry->FunctionOffset,
Strings + Entry->FileOffset,
Entry->SourceLine);
}
}
}
void dump_rsym(const char* filename)
{
char* data;
long size, res;
PIMAGE_FILE_HEADER PEFileHeader;
PIMAGE_OPTIONAL_HEADER PEOptHeader;
PIMAGE_SECTION_HEADER PESectionHeaders;
WORD i;
FILE* f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
data = malloc(size);
res = fread(data, 1, size, f);
fclose(f);
PEFileHeader = (PIMAGE_FILE_HEADER)((char *)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew + sizeof(ULONG));
PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *)PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
for (i = 0; i < PEFileHeader->NumberOfSections; i++)
{
if (!strcmp((char *)PESectionHeaders[i].Name, ".rossym"))
{
dump_rsym_internal(data + PESectionHeaders[i].PointerToRawData);
break;
}
}
free(data);
}
#endif

View file

@ -0,0 +1,378 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Test for dbghelp PDB functions
* PROGRAMMER: Mark Jansen
*/
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <dbghelp.h>
#include <cvconst.h> // SymTagXXX
#include <stdio.h>
#include "wine/test.h"
#define ok_ulonglong(expression, result) \
do { \
ULONG64 _value = (expression); \
ULONG64 _result = (result); \
ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
#expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
} while (0)
// data.c
void create_compressed_files();
int extract_msvc_exe(char szFile[MAX_PATH]);
void cleanup_msvc_exe();
static HANDLE proc()
{
return GetCurrentProcess();
}
static BOOL init_sym_imp(const char* file, int line)
{
if (!SymInitialize(proc(), NULL, FALSE))
{
DWORD err = GetLastError();
ok_(file, line)(0, "Failed to init: 0x%x\n", err);
return FALSE;
}
return TRUE;
}
static void deinit_sym()
{
SymCleanup(proc());
}
#define init_sym() init_sym_imp(__FILE__, __LINE__)
#define INIT_PSYM(buff) do { \
memset((buff), 0, sizeof((buff))); \
((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
} while (0)
/* Maybe our dbghelp.dll is too old? */
static BOOL can_enumerate(HANDLE hProc, DWORD64 BaseAddress)
{
IMAGEHLP_MODULE64 ModuleInfo;
BOOL Ret;
memset(&ModuleInfo, 0, sizeof(ModuleInfo));
ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
return Ret && ModuleInfo.SymType == SymPdb;
}
static void test_SymFromName(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
DWORD64 BaseAddress;
DWORD dwErr;
if (!init_sym())
return;
SetLastError(ERROR_SUCCESS);
BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
ok_ulonglong(BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
if (!can_enumerate(hProc, BaseAddress))
{
skip("dbghelp.dll too old or cannot enumerate symbols!\n");
}
else
{
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "DllMain", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "_DllMain@12", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0x400000); // ??
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagPublicSymbol);
ok_str(pSymbol->Name, "_DllMain@12");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsChkdsk");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "_FfsChkdsk@24", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0x400000); // ??
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
ok_hex(pSymbol->Tag, SymTagPublicSymbol);
ok_str(pSymbol->Name, "_FfsChkdsk@24");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "FfsFormat", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsFormat");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "_FfsFormat@24", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0x400000); // ??
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1070);
ok_hex(pSymbol->Tag, SymTagPublicSymbol);
ok_str(pSymbol->Name, "_FfsFormat@24");
}
deinit_sym();
}
static void test_SymFromAddr(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
DWORD64 BaseAddress, Displacement;
DWORD dwErr;
if (!init_sym())
return;
SetLastError(ERROR_SUCCESS);
BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
ok_ulonglong(BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
/* No address found before load address of module */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
dwErr = GetLastError();
ok_int(Ret, FALSE);
ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
/* Right at the start of the module is recognized as the first symbol found */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0xffffffffffffffff);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* The actual first instruction of the function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x1010, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* The last instruction in the function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x102D, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0x1d);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* The padding below the function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x102E, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0x1e);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* One byte before the next function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x103f, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0x2f);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1010);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* First byte of the next function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x1040, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1040);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsChkdsk");
if (!can_enumerate(hProc, BaseAddress))
{
skip("dbghelp.dll too old or cannot read this symbol!\n");
}
else
{
/* .idata */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x2000, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, 0);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x2000);
ok_hex(pSymbol->Tag, SymTagPublicSymbol);
ok_str(pSymbol->Name, "__imp__DbgPrint");
}
deinit_sym();
}
typedef struct _test_context
{
DWORD64 BaseAddress;
SIZE_T Index;
} test_context;
static struct _test_data {
DWORD64 AddressOffset;
ULONG Size;
ULONG Tag;
const char* Name;
} test_data[] = {
/* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
{ 0x1070, 36, SymTagFunction, "FfsFormat" },
{ 0x1010, 32, SymTagFunction, "DllMain" },
{ 0x1040, 36, SymTagFunction, "FfsChkdsk" },
{ 0x2100, 0, SymTagPublicSymbol, "__IMPORT_DESCRIPTOR_ntdll" },
{ 0x109a, 0, SymTagPublicSymbol, "_DbgPrint" },
{ 0x2004, 0, SymTagPublicSymbol, "\x7fntdll_NULL_THUNK_DATA" },
{ 0x2000, 0, SymTagPublicSymbol, "__imp__DbgPrint" },
{ 0x2114, 0, SymTagPublicSymbol, "__NULL_IMPORT_DESCRIPTOR" },
};
static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
test_context* ctx = UserContext;
if (ctx->Index < ARRAYSIZE(test_data))
{
ok_ulonglong(pSymInfo->ModBase, ctx->BaseAddress);
ok_ulonglong(pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
ok_hex(pSymInfo->Tag, test_data[ctx->Index].Tag);
ok_str(pSymInfo->Name, test_data[ctx->Index].Name);
ctx->Index++;
}
else
{
ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
}
return TRUE;
}
static void test_SymEnumSymbols(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
DWORD dwErr;
test_context ctx;
if (!init_sym())
return;
ctx.Index = 0;
SetLastError(ERROR_SUCCESS);
ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
ok_ulonglong(ctx.BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
if (!can_enumerate(hProc, ctx.BaseAddress))
{
skip("dbghelp.dll too old or cannot enumerate symbols!\n");
}
else
{
Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
ok_int(Ret, TRUE);
ok_int(ctx.Index, ARRAYSIZE(test_data));
}
deinit_sym();
}
START_TEST(pdb)
{
char szDllName[MAX_PATH];
//create_compressed_files();
DWORD Options = SymGetOptions();
Options &= ~(SYMOPT_UNDNAME);
//Options |= SYMOPT_DEBUG;
SymSetOptions(Options);
if (!extract_msvc_exe(szDllName))
{
ok(0, "Failed extracting files\n");
return;
}
test_SymFromName(proc(), szDllName);
test_SymFromAddr(proc(), szDllName);
test_SymEnumSymbols(proc(), szDllName);
cleanup_msvc_exe();
}

View file

@ -0,0 +1,5 @@
#include "windef.h"
msvc_uffs.dll RCDATA testdata/msvc_uffs.dll.compr
msvc_uffs.pdb RCDATA testdata/msvc_uffs.pdb.compr
gcc_uffs.dll RCDATA testdata/gcc_uffs.dll.compr

View file

@ -0,0 +1,369 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Test for dbghelp rsym functions
* PROGRAMMER: Mark Jansen
*
* These tests are based on the PDB tests.
*/
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <dbghelp.h>
#include <cvconst.h> // SymTagXXX
#include <stdio.h>
#include "wine/test.h"
#define ok_ulonglong(expression, result) \
do { \
ULONG64 _value = (expression); \
ULONG64 _result = (result); \
ok(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
#expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
} while (0)
#define ok_ulonglong_(file, line, expression, result) \
do { \
ULONG64 _value = (expression); \
ULONG64 _result = (result); \
ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (%s), got: %s\n", \
#expression, wine_dbgstr_longlong(_result), wine_dbgstr_longlong(_value)); \
} while (0)
#define ok_hex_(file, line, expression, result) \
do { \
int _value = (expression); \
ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (0x%x), got: 0x%x\n", \
#expression, (int)(result), _value); \
} while (0)
#define ok_str_(file, line, x, y) \
ok_(file, line)(strcmp(x, y) == 0, "Wrong string. Expected '%s', got '%s'\n", y, x)
// data.c
void dump_rsym(const char* filename);
int extract_gcc_exe(char szFile[MAX_PATH]);
void cleanup_gcc_exe();
static HANDLE proc()
{
return GetCurrentProcess();
}
static BOOL init_sym_imp(const char* file, int line)
{
if (!SymInitialize(proc(), NULL, FALSE))
{
DWORD err = GetLastError();
ok_(file, line)(0, "Failed to init: 0x%x\n", err);
return FALSE;
}
return TRUE;
}
static void deinit_sym()
{
SymCleanup(proc());
}
static BOOL supports_rsym(HANDLE hProc, DWORD64 BaseAddress)
{
IMAGEHLP_MODULE64 ModuleInfo;
BOOL Ret;
memset(&ModuleInfo, 0, sizeof(ModuleInfo));
ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
Ret = SymGetModuleInfo64(hProc, BaseAddress, &ModuleInfo);
return Ret &&
ModuleInfo.SymType == SymDia &&
ModuleInfo.CVSig == ('R' | ('S' << 8) | ('Y' << 16) | ('M' << 24));
}
#define init_sym() init_sym_imp(__FILE__, __LINE__)
#define INIT_PSYM(buff) do { \
memset((buff), 0, sizeof((buff))); \
((PSYMBOL_INFO)(buff))->SizeOfStruct = sizeof(SYMBOL_INFO); \
((PSYMBOL_INFO)(buff))->MaxNameLen = MAX_SYM_NAME; \
} while (0)
static void test_SymFromName(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
DWORD64 BaseAddress;
DWORD dwErr;
if (!init_sym())
return;
SetLastError(ERROR_SUCCESS);
BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
if (supports_rsym(hProc, BaseAddress))
{
ok_ulonglong(BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "DllMain", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "FfsChkdsk", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x103F);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsChkdsk");
INIT_PSYM(buffer);
Ret = SymFromName(hProc, "FfsFormat", pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x100C);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsFormat");
}
else
{
skip("dbghelp.dll cannot parse rsym\n");
}
deinit_sym();
}
static void test_SymFromAddr(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
DWORD64 BaseAddress, Displacement;
DWORD dwErr;
if (!init_sym())
return;
SetLastError(ERROR_SUCCESS);
BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
if (supports_rsym(hProc, BaseAddress))
{
ok_ulonglong(BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
/* No address found before load address of module */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress -1, &Displacement, pSymbol);
dwErr = GetLastError();
ok_int(Ret, FALSE);
ok_hex(dwErr, ERROR_MOD_NOT_FOUND);
/* Right at the start of the module is recognized as the first symbol found */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress, &Displacement, pSymbol);
/* Our dbghelp.dll does not recognize this yet */
todo_if(!Ret)
{
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0xffffffffffffffff);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
}
/* The actual first instruction of the function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x1000, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* The last instruction in the function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x1009, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0x9);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x1000);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "DllMain");
/* First byte of the next function */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x103F, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_FUNCTION);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x103F);
ok_hex(pSymbol->Tag, SymTagFunction);
ok_str(pSymbol->Name, "FfsChkdsk");
/* .idata */
Displacement = 0;
INIT_PSYM(buffer);
Ret = SymFromAddr(hProc, BaseAddress + 0x4000, &Displacement, pSymbol);
ok_int(Ret, TRUE);
ok_ulonglong(Displacement, 0);
ok_ulonglong(pSymbol->ModBase, BaseAddress);
ok_hex(pSymbol->Flags, SYMFLAG_EXPORT);
ok_ulonglong(pSymbol->Address, BaseAddress + 0x4000);
ok_hex(pSymbol->Tag, SymTagPublicSymbol);
ok_str(pSymbol->Name, "_head_dll_ntdll_libntdll_a");
}
else
{
skip("dbghelp.dll cannot parse rsym\n");
}
deinit_sym();
}
typedef struct _test_context
{
DWORD64 BaseAddress;
SIZE_T Index;
} test_context;
static struct _test_data {
DWORD64 AddressOffset;
ULONG Size;
ULONG Tag;
const char* Name;
int Line;
} test_data[] = {
/* TODO: Order is based on magic, should find entries based on name, and mark as 'seen' */
{ 0x107c, 0, SymTagPublicSymbol, "__CTOR_LIST__", __LINE__ },
{ 0x2074, 0, SymTagPublicSymbol, "__RUNTIME_PSEUDO_RELOC_LIST_END__", __LINE__ },
{ 0x1000, 12, SymTagPublicSymbol, "EntryPoint", __LINE__ },
{ 0x100c, 51, SymTagFunction, "FfsFormat", __LINE__ },
{ 0x4030, 0, SymTagPublicSymbol, "_imp__DbgPrint", __LINE__ },
{ 0x1084, 0, SymTagPublicSymbol, "__DTOR_LIST__", __LINE__ },
{ 0x103f, 53, SymTagFunction, "FfsChkdsk", __LINE__ },
{ 0x2074, 0, SymTagPublicSymbol, "_rt_psrelocs_end", __LINE__ },
{ 0x103f, 53, SymTagPublicSymbol, "ChkdskEx", __LINE__ },
{ 0x4048, 0, SymTagPublicSymbol, "_dll_ntdll_libntdll_a_iname", __LINE__ },
{ 0x2074, 0, SymTagPublicSymbol, "_rt_psrelocs_start", __LINE__ },
{ 0x1000, 12, SymTagFunction, "DllMain", __LINE__ },
{ 0x100c, 0, SymTagPublicSymbol, "FormatEx", __LINE__ },
{ 0x1074, 0, SymTagPublicSymbol, "DbgPrint", __LINE__ },
{ 0x68900000, 0, SymTagPublicSymbol, "__ImageBase", __LINE__ },
{ 0x68902074, 0, SymTagPublicSymbol, "__RUNTIME_PSEUDO_RELOC_LIST__", __LINE__ },
{ 0x4000, 0, SymTagPublicSymbol, "_head_dll_ntdll_libntdll_a", __LINE__ },
};
BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
test_context* ctx = UserContext;
if (ctx->Index < ARRAYSIZE(test_data))
{
ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->ModBase, ctx->BaseAddress);
if (test_data[ctx->Index].AddressOffset > 0x100000)
ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Address, test_data[ctx->Index].AddressOffset);
else
ok_ulonglong_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Address, ctx->BaseAddress + test_data[ctx->Index].AddressOffset);
ok_hex_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Tag, test_data[ctx->Index].Tag);
ok_str_(__FILE__, test_data[ctx->Index].Line, pSymInfo->Name, test_data[ctx->Index].Name);
ctx->Index++;
}
else
{
ok(0, "Out of bounds (%lu), max is: %i!\n", ctx->Index, ARRAYSIZE(test_data));
}
return TRUE;
}
static void test_SymEnumSymbols(HANDLE hProc, const char* szModuleName)
{
BOOL Ret;
DWORD dwErr;
test_context ctx;
if (!init_sym())
return;
ctx.Index = 0;
SetLastError(ERROR_SUCCESS);
ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0);
dwErr = GetLastError();
if (supports_rsym(hProc, ctx.BaseAddress))
{
ok_ulonglong(ctx.BaseAddress, 0x600000);
ok_hex(dwErr, ERROR_SUCCESS);
Ret = SymEnumSymbols(hProc, ctx.BaseAddress, NULL, EnumSymProc, &ctx);
ok_int(Ret, TRUE);
ok_int(ctx.Index, ARRAYSIZE(test_data));
}
else
{
skip("dbghelp.dll cannot parse rsym\n");
}
deinit_sym();
}
START_TEST(rsym)
{
char szDllName[MAX_PATH];
//dump_rsym("R:\\src\\trunk\\reactos\\modules\\rostests\\apitests\\dbghelp\\testdata\\gcc_uffs.dll");
DWORD Options = SymGetOptions();
Options &= ~(SYMOPT_UNDNAME);
//Options |= SYMOPT_DEBUG;
SymSetOptions(Options);
if (!extract_gcc_exe(szDllName))
{
ok(0, "Failed extracting files\n");
return;
}
test_SymFromName(proc(), szDllName);
test_SymFromAddr(proc(), szDllName);
test_SymEnumSymbols(proc(), szDllName);
cleanup_gcc_exe();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,13 @@
#define STANDALONE
#include <wine/test.h>
extern void func_pdb(void);
extern void func_rsym(void);
const struct test winetest_testlist[] =
{
{ "pdb", func_pdb },
{ "rsym", func_rsym },
{ 0, 0 }
};