Index: rostests/apitests/CMakeLists.txt =================================================================== --- rostests/apitests/CMakeLists.txt (revision 73802) +++ rostests/apitests/CMakeLists.txt (working copy) @@ -7,6 +7,7 @@ add_subdirectory(browseui) add_subdirectory(com) add_subdirectory(crt) +add_subdirectory(dbghelp) add_subdirectory(dciman32) add_subdirectory(dnsapi) add_subdirectory(gdi32) Index: rostests/apitests/dbghelp/CMakeLists.txt =================================================================== --- rostests/apitests/dbghelp/CMakeLists.txt (nonexistent) +++ rostests/apitests/dbghelp/CMakeLists.txt (working copy) @@ -0,0 +1,16 @@ + +add_definitions(-D__ROS_LONG64__ -DWINETEST_USE_DBGSTR_LONGLONG) +include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib) + +list(APPEND SOURCE + pdb.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) Index: rostests/apitests/dbghelp/data.c =================================================================== --- rostests/apitests/dbghelp/data.c (nonexistent) +++ rostests/apitests/dbghelp/data.c (working copy) @@ -0,0 +1,151 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Support functions for dbghelp api test + * PROGRAMMER: Mark Jansen + */ + +#include +#include +#include + +#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; + DWORD size, dstsize; + 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); + ret = WriteFile(file, decompressed, dstsize, &size, NULL); + CloseHandle(file); + free(decompressed); + return ret && dstsize == size; +} + + +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()); +} + +#if 0 +static int compress_one(const char* src, const char* dest) +{ + DWORD dwRead; + HANDLE file = CreateFileA(src, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD size = GetFileSize(file, NULL), size2; + Bytef* buffer = malloc(size), *buffer2; + BOOL ret = ReadFile(file, buffer, size, &dwRead, NULL); + DWORD dwErr = GetLastError(); + + CloseHandle(file); + + if (!ret || dwRead != size) + { + printf("Could not read file: 0x%x\n", dwErr); + free(buffer); + CloseHandle(file); + return 0; + } + size2 = size *2; + buffer2 = malloc(size2); + ret = compress(buffer2, &size2, buffer, size); + + free(buffer); + + if (Z_OK != ret) + { + free(buffer2); + return 0; + } + + file = CreateFileA(dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ret = WriteFile(file, buffer2, size2, &dwRead, NULL); + CloseHandle(file); + free(buffer2); + + return ret && size2 == dwRead; +} + +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 Index: rostests/apitests/dbghelp/pdb.c =================================================================== --- rostests/apitests/dbghelp/pdb.c (nonexistent) +++ rostests/apitests/dbghelp/pdb.c (working copy) @@ -0,0 +1,339 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for dbghelp PDB functions + * PROGRAMMER: Mark Jansen + */ + + +#include +#define WIN32_NO_STATUS +#include +#include +#include // SymTagXXX +#include + +#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) + + +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; + + BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0); + dwErr = GetLastError(); + + 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, 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; + + 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"); + + /* .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[] = { + { 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" }, +}; + +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 (%i), 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; + ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0); + dwErr = GetLastError(); + + ok_ulonglong(ctx.BaseAddress, 0x600000); + ok_hex(dwErr, ERROR_SUCCESS); + + Ret = SymEnumSymbols(hProc, ctx.BaseAddress, "*", EnumSymProc, &ctx); + ok_int(Ret, TRUE); + + deinit_sym(); +} + + + + +START_TEST(pdb) +{ + char szDllName[MAX_PATH]; + //create_compressed_files(); + + SymSetOptions(SYMOPT_DEFERRED_LOADS/* | SYMOPT_DEBUG*/); + + 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(); +} Index: rostests/apitests/dbghelp/resource.rc =================================================================== --- rostests/apitests/dbghelp/resource.rc (nonexistent) +++ rostests/apitests/dbghelp/resource.rc (working copy) @@ -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 Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testlist.c =================================================================== --- rostests/apitests/dbghelp/testlist.c (nonexistent) +++ rostests/apitests/dbghelp/testlist.c (working copy) @@ -0,0 +1,12 @@ + +#define STANDALONE +#include +#include + +extern void func_pdb(void); + +const struct test winetest_testlist[] = +{ + { "pdb", func_pdb }, + { 0, 0 } +}; Index: rostests/apitests/dbghelp/CMakeLists.txt =================================================================== --- rostests/apitests/dbghelp/CMakeLists.txt (nonexistent) +++ rostests/apitests/dbghelp/CMakeLists.txt (working copy) @@ -0,0 +1,16 @@ + +add_definitions(-D__ROS_LONG64__ -DWINETEST_USE_DBGSTR_LONGLONG) +include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib) + +list(APPEND SOURCE + pdb.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) Index: rostests/apitests/dbghelp/data.c =================================================================== --- rostests/apitests/dbghelp/data.c (nonexistent) +++ rostests/apitests/dbghelp/data.c (working copy) @@ -0,0 +1,151 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Support functions for dbghelp api test + * PROGRAMMER: Mark Jansen + */ + +#include +#include +#include + +#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; + DWORD size, dstsize; + 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); + ret = WriteFile(file, decompressed, dstsize, &size, NULL); + CloseHandle(file); + free(decompressed); + return ret && dstsize == size; +} + + +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()); +} + +#if 0 +static int compress_one(const char* src, const char* dest) +{ + DWORD dwRead; + HANDLE file = CreateFileA(src, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD size = GetFileSize(file, NULL), size2; + Bytef* buffer = malloc(size), *buffer2; + BOOL ret = ReadFile(file, buffer, size, &dwRead, NULL); + DWORD dwErr = GetLastError(); + + CloseHandle(file); + + if (!ret || dwRead != size) + { + printf("Could not read file: 0x%x\n", dwErr); + free(buffer); + CloseHandle(file); + return 0; + } + size2 = size *2; + buffer2 = malloc(size2); + ret = compress(buffer2, &size2, buffer, size); + + free(buffer); + + if (Z_OK != ret) + { + free(buffer2); + return 0; + } + + file = CreateFileA(dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ret = WriteFile(file, buffer2, size2, &dwRead, NULL); + CloseHandle(file); + free(buffer2); + + return ret && size2 == dwRead; +} + +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 Index: rostests/apitests/dbghelp/pdb.c =================================================================== --- rostests/apitests/dbghelp/pdb.c (nonexistent) +++ rostests/apitests/dbghelp/pdb.c (working copy) @@ -0,0 +1,339 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for dbghelp PDB functions + * PROGRAMMER: Mark Jansen + */ + + +#include +#define WIN32_NO_STATUS +#include +#include +#include // SymTagXXX +#include + +#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) + + +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; + + BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0); + dwErr = GetLastError(); + + 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, 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; + + 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"); + + /* .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[] = { + { 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" }, +}; + +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 (%i), 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; + ctx.BaseAddress = SymLoadModule64(hProc, NULL, szModuleName, NULL, 0x600000, 0); + dwErr = GetLastError(); + + ok_ulonglong(ctx.BaseAddress, 0x600000); + ok_hex(dwErr, ERROR_SUCCESS); + + Ret = SymEnumSymbols(hProc, ctx.BaseAddress, "*", EnumSymProc, &ctx); + ok_int(Ret, TRUE); + + deinit_sym(); +} + + + + +START_TEST(pdb) +{ + char szDllName[MAX_PATH]; + //create_compressed_files(); + + SymSetOptions(SYMOPT_DEFERRED_LOADS/* | SYMOPT_DEBUG*/); + + 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(); +} Index: rostests/apitests/dbghelp/resource.rc =================================================================== --- rostests/apitests/dbghelp/resource.rc (nonexistent) +++ rostests/apitests/dbghelp/resource.rc (working copy) @@ -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 Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/gcc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.dll.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr =================================================================== --- rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (nonexistent) +++ rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr (working copy) Property changes on: rostests/apitests/dbghelp/testdata/msvc_uffs.pdb.compr ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rostests/apitests/dbghelp/testlist.c =================================================================== --- rostests/apitests/dbghelp/testlist.c (nonexistent) +++ rostests/apitests/dbghelp/testlist.c (working copy) @@ -0,0 +1,12 @@ + +#define STANDALONE +#include +#include + +extern void func_pdb(void); + +const struct test winetest_testlist[] = +{ + { "pdb", func_pdb }, + { 0, 0 } +};