mirror of
https://github.com/reactos/reactos.git
synced 2025-05-31 15:08:14 +00:00
[DBGHELP_APITEST] Add tests for pdb and rsym parsing. CORE-12773
svn path=/trunk/; revision=73816
This commit is contained in:
parent
17a622f506
commit
e2c97e602f
10 changed files with 1063 additions and 0 deletions
|
@ -7,6 +7,7 @@ add_subdirectory(atl)
|
||||||
add_subdirectory(browseui)
|
add_subdirectory(browseui)
|
||||||
add_subdirectory(com)
|
add_subdirectory(com)
|
||||||
add_subdirectory(crt)
|
add_subdirectory(crt)
|
||||||
|
add_subdirectory(dbghelp)
|
||||||
add_subdirectory(dciman32)
|
add_subdirectory(dciman32)
|
||||||
add_subdirectory(dnsapi)
|
add_subdirectory(dnsapi)
|
||||||
add_subdirectory(gdi32)
|
add_subdirectory(gdi32)
|
||||||
|
|
20
rostests/apitests/dbghelp/CMakeLists.txt
Normal file
20
rostests/apitests/dbghelp/CMakeLists.txt
Normal 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)
|
277
rostests/apitests/dbghelp/data.c
Normal file
277
rostests/apitests/dbghelp/data.c
Normal 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
|
378
rostests/apitests/dbghelp/pdb.c
Normal file
378
rostests/apitests/dbghelp/pdb.c
Normal 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();
|
||||||
|
}
|
5
rostests/apitests/dbghelp/resource.rc
Normal file
5
rostests/apitests/dbghelp/resource.rc
Normal 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
|
369
rostests/apitests/dbghelp/rsym.c
Normal file
369
rostests/apitests/dbghelp/rsym.c
Normal 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();
|
||||||
|
}
|
BIN
rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr
vendored
Normal file
BIN
rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr
vendored
Normal file
Binary file not shown.
BIN
rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr
vendored
Normal file
BIN
rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr
vendored
Normal file
Binary file not shown.
BIN
rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr
vendored
Normal file
BIN
rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr
vendored
Normal file
Binary file not shown.
13
rostests/apitests/dbghelp/testlist.c
Normal file
13
rostests/apitests/dbghelp/testlist.c
Normal 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 }
|
||||||
|
};
|
Loading…
Reference in a new issue