[PATCH 0/5] MR5204: DbgHelp and debug info lookup (Part I)
This is the first part of a larger serie to cover module loading and debug info file lookup in dbghelp. This first part covers: - a bunch of new tests - ensuring correct behavior of native some errors pointed out by tests (64 bit modules can be loaded on 32 bit programs, and whether the fullpath is used in some API). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/dbghelp/tests/path.c | 287 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 781df3dd771..791064d05bb 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -926,6 +926,292 @@ static void test_srvgetindexes_dbg(void) } } +static void make_path(WCHAR file[MAX_PATH], const WCHAR* topdir, const WCHAR* subdir, const WCHAR* base) +{ + wcscpy(file, topdir); + if (subdir) + { + if (file[wcslen(file) - 1] != '\\') wcscat(file, L"\\"); + wcscat(file, subdir); + } + if (base) + { + if (file[wcslen(file) - 1] != '\\') wcscat(file, L"\\"); + wcscat(file, base); + } +} + +struct path_validate +{ + DWORD timestamp; + DWORD size_of_image; + unsigned cb_count; +}; + +static BOOL CALLBACK path_cb(PCWSTR filename, void* _usr) +{ + struct path_validate* pv = _usr; + SYMSRV_INDEX_INFOW ssii; + BOOL ret; + + pv->cb_count++; + /* wine returns paths in relative form, but relative to search path... + * fail (== continue search) until it's fixed + */ + todo_wine_if(!filename[0] || filename[1] != ':') + ok(filename[0] && filename[1] == ':', "Expecting full path, but got %ls\n", filename); + if (!filename[0] || filename[1] != ':') return TRUE; + + memset(&ssii, 0, sizeof(ssii)); + ssii.sizeofstruct = sizeof(ssii); + ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0); + ok(ret, "SymSrvGetFileIndexInfo failed: %lu %ls\n", GetLastError(), filename); + return !(ret && ssii.timestamp == pv->timestamp && ssii.size == pv->size_of_image); +} + +static unsigned char2index(char ch) +{ + unsigned val; + if (ch >= '0' && ch <= '9') + val = ch - '0'; + else if (ch >= 'a' && ch <= 'z') + val = 10 + ch - 'a'; + else val = ~0u; + return val; +} + +/* Despite what MS documentation states, option EXACT_SYMBOLS doesn't always work + * (it looks like it's only enabled when symsrv.dll is loaded). + * So, we don't test with EXACT_SYMBOLS set, nor with a NULL callback, and defer + * to our own custom callback the testing. + * (We always end when a full matched is found). + */ +static void test_find_in_path_pe(void) +{ + HANDLE proc = (HANDLE)(DWORD_PTR)0x666002; + WCHAR topdir[MAX_PATH]; + WCHAR search[MAX_PATH]; + WCHAR file[MAX_PATH]; + WCHAR found[MAX_PATH]; + struct path_validate pv; + DWORD len; + BOOL ret; + int i; + union nt_header hdr; + + static const struct file_tests + { + unsigned bitness; /* 32 or 64 */ + DWORD timestamp; + DWORD size_of_image; + const WCHAR* module_path; + } + file_tests[] = + { + /* 0 */ { 64, 0x12345678, 0x0030cafe, L"foobar.dll" }, + /* 1 */ { 64, 0x12345678, 0x0030cafe, L"A\\foobar.dll" }, + /* 2 */ { 64, 0x12345678, 0x0030cafe, L"B\\foobar.dll" }, + /* 3 */ { 64, 0x56781234, 0x0010f00d, L"foobar.dll" }, + /* 4 */ { 64, 0x56781234, 0x0010f00d, L"A\\foobar.dll" }, + /* 5 */ { 64, 0x56781234, 0x0010f00d, L"B\\foobar.dll" }, + /* 6 */ { 32, 0x12345678, 0x0030cafe, L"foobar.dll" }, + /* 7 */ { 32, 0x12345678, 0x0030cafe, L"A\\foobar.dll" }, + /* 8 */ { 32, 0x12345678, 0x0030cafe, L"B\\foobar.dll" }, + /* 9 */ { 32, 0x56781234, 0x0010f00d, L"foobar.dll" }, + /* a */ { 32, 0x56781234, 0x0010f00d, L"A\\foobar.dll" }, + /* b */ { 32, 0x56781234, 0x0010f00d, L"B\\foobar.dll" }, + }; + static const struct image_tests + { + /* files to generate */ + const char* files; + /* parameters for lookup */ + DWORD lookup_timestamp; + DWORD lookup_size_of_image; + const char* search; /* several of ., A, B to link to directories */ + const WCHAR* module; + /* expected results */ + const WCHAR* found_subdir; + DWORD expected_cb_count; + } + image_tests[] = + { + /* all files 64 bit */ + /* the passed timestamp & size are not checked before calling the callback! */ + /* 0 */ { "0", 0x00000000, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 1 */ { "0", 0x12345678, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 2 */ { "0", 0x00000000, 0x0030cafe, ".", L"foobar.dll", NULL, 1}, + /* 3 */ { "0", 0x12345678, 0x0030cafe, ".", L"foobar.dll", L"", 1}, + /* no recursion into subdirectories */ + /* 4 */ { "1", 0x12345678, 0x0030cafe, ".", L"foobar.dll", NULL, 0}, + /* directories are searched in order */ + /* 5 */ { "15", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 6 */ { "15", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\\", 2}, + /* 7 */ { "12", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 8 */ { "12", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\\", 1}, + + /* all files 32 bit */ + /* the passed timestamp & size is not checked ! */ + /* 9 */ { "6", 0x00000000, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 10 */ { "6", 0x12345678, 0x00000000, ".", L"foobar.dll", NULL, 1}, + /* 11 */ { "6", 0x00000000, 0x0030cafe, ".", L"foobar.dll", NULL, 1}, + /* 12 */ { "6", 0x12345678, 0x0030cafe, ".", L"foobar.dll", L"", 1}, + /* no recursion into subdirectories */ + /* 13 */ { "7", 0x12345678, 0x0030cafe, ".", L"foobar.dll", NULL, 0}, + /* directories are searched in order */ + /* 14 */ { "7b", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 15 */ { "7b", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\\", 2}, + /* 16 */ { "78", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 17 */ { "78", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\\", 1}, + + /* machine and bitness is not used */ + /* 18 */ { "1b", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 19 */ { "1b", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\\", 2}, + /* 20 */ { "18", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 21 */ { "18", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\\", 1}, + /* 22 */ { "75", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 23 */ { "75", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"A\\", 2}, + /* 24 */ { "72", 0x12345678, 0x0030cafe, "AB", L"foobar.dll", L"A\\", 1}, + /* 25 */ { "72", 0x12345678, 0x0030cafe, "BA", L"foobar.dll", L"B\\", 1}, + + /* specifying a full path to module isn't taken into account */ + /* 26 */ { "0", 0x12345678, 0x0030cafe, "AB", L"@foobar.dll", NULL, 0}, + /* 27 */ { "6", 0x12345678, 0x0030cafe, "AB", L"@foobar.dll", NULL, 0}, + + }; + static const WCHAR* list_directories[] = {L"A", L"B", L"dll", L"symbols", L"symbols\\dll", L"acm", L"symbols\\acm"}; + + ret = SymInitializeW(proc, NULL, FALSE); + ok(ret, "Couldn't init dbghelp\n"); + + len = GetTempPathW(ARRAY_SIZE(topdir), topdir); + ok(len && len < ARRAY_SIZE(topdir), "Unexpected length\n"); + wcscat(topdir, L"dh.tmp\\"); + ret = CreateDirectoryW(topdir, NULL); + ok(ret, "Couldn't create directory\n"); + for (i = 0; i < ARRAY_SIZE(list_directories); i++) + { + make_path(file, topdir, list_directories[i], NULL); + ret = CreateDirectoryW(file, NULL); + ok(ret, "Couldn't create directory %u %ls\n", i, list_directories[i]); + } + + for (i = 0; i < ARRAY_SIZE(image_tests); ++i) + { + const char* ptr; + winetest_push_context("%u", i); + + for (ptr = image_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(file_tests)) + { + const struct file_tests* ft = &file_tests[val]; + struct debug_directory_blob* ds_blob; + + make_path(file, topdir, NULL, ft->module_path); + /* all modules created with ds pdb reference so that SymSrvGetFileInfoInfo() succeeds */ + ds_blob = make_pdb_ds_blob(ft->timestamp, &guid1, 124, "pdbds.pdb"); + if (ft->bitness == 64) + { + init_headers64(&hdr.nt_header64, ft->timestamp, ft->size_of_image, 0); + create_test_dll(&hdr, sizeof(hdr.nt_header64), &ds_blob, 1, file); + } + else + { + init_headers32(&hdr.nt_header32, ft->timestamp, ft->size_of_image, 0); + create_test_dll(&hdr, sizeof(hdr.nt_header32), &ds_blob, 1, file); + } + free(ds_blob); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + search[0] = L'\0'; + for (ptr = image_tests[i].search; *ptr; ptr++) + { + if (*search) wcscat(search, L";"); + wcscat(search, topdir); + if (*ptr == '.') + ; + else if (*ptr == 'A') + wcscat(search, L"A"); + else if (*ptr == 'B') + wcscat(search, L"B"); + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + if (image_tests[i].module[0] == L'@') + make_path(file, topdir, NULL, &image_tests[i].module[1]); + else + wcscpy(file, image_tests[i].module); + + pv.timestamp = image_tests[i].lookup_timestamp; + pv.size_of_image = image_tests[i].lookup_size_of_image; + pv.cb_count = 0; + memset(found, 0, sizeof(found)); + + ret = SymFindFileInPathW(proc, search, file, + (void*)&image_tests[i].lookup_timestamp, + image_tests[i].lookup_size_of_image, 0, + SSRVOPT_DWORDPTR, found, path_cb, &pv); + + todo_wine + ok(pv.cb_count == image_tests[i].expected_cb_count, + "Mismatch in cb count, got %u (expected %lu)\n", + pv.cb_count, image_tests[i].expected_cb_count); + if (image_tests[i].found_subdir) + { + size_t l1, l2, l3; + + ok(ret, "Couldn't find file: %ls %lu\n", search, GetLastError()); + + l1 = wcslen(topdir); + l2 = wcslen(image_tests[i].found_subdir); + l3 = wcslen(image_tests[i].module); + + ok(l1 + l2 + l3 == wcslen(found) && + !memcmp(found, topdir, l1 * sizeof(WCHAR)) && + !memcmp(&found[l1], image_tests[i].found_subdir, l2 * sizeof(WCHAR)) && + !memcmp(&found[l1 + l2], image_tests[i].module, l3 * sizeof(WCHAR)), + "Mismatch in found file %ls (expecting %ls)\n", + found, image_tests[i].found_subdir); + } + else + { + todo_wine_if(i == 26 || i == 27) + ok(!ret, "File reported found, while failure is expected\n"); + todo_wine_if(i == 26 || i == 27 || (GetLastError() != ERROR_FILE_NOT_FOUND)) + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Unexpected error %lu\n", GetLastError()); + } + for (ptr = image_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(file_tests)) + { + const struct file_tests* ft = &file_tests[val]; + make_path(file, topdir, NULL, ft->module_path); + ret = DeleteFileW(file); + ok(ret, "Couldn't delete file %c %ls\n", *ptr, file); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + winetest_pop_context(); + } + + SymCleanup(proc); + + for (i = ARRAY_SIZE(list_directories) - 1; i >= 0; i--) + { + make_path(file, topdir, list_directories[i], NULL); + ret = RemoveDirectoryW(file); + ok(ret, "Couldn't remove directory %u %ls\n", i, list_directories[i]); + } + + ret = RemoveDirectoryW(topdir); + ok(ret, "Couldn't remove directory\n"); +} + START_TEST(path) { /* cleanup env variables that affect dbghelp's behavior */ @@ -935,4 +1221,5 @@ START_TEST(path) test_srvgetindexes_pe(); test_srvgetindexes_pdb(); test_srvgetindexes_dbg(); + test_find_in_path_pe(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/dbghelp/tests/path.c | 230 +++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 3 deletions(-) diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 791064d05bb..1e057a206ab 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -943,6 +943,8 @@ static void make_path(WCHAR file[MAX_PATH], const WCHAR* topdir, const WCHAR* su struct path_validate { + GUID guid; + DWORD age; DWORD timestamp; DWORD size_of_image; unsigned cb_count; @@ -966,7 +968,8 @@ static BOOL CALLBACK path_cb(PCWSTR filename, void* _usr) ssii.sizeofstruct = sizeof(ssii); ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0); ok(ret, "SymSrvGetFileIndexInfo failed: %lu %ls\n", GetLastError(), filename); - return !(ret && ssii.timestamp == pv->timestamp && ssii.size == pv->size_of_image); + return !(ret && !memcmp(&ssii.guid, &pv->guid, sizeof(GUID)) && + ssii.age == pv->age && ssii.timestamp == pv->timestamp && ssii.size == pv->size_of_image); } static unsigned char2index(char ch) @@ -1111,7 +1114,7 @@ static void test_find_in_path_pe(void) make_path(file, topdir, NULL, ft->module_path); /* all modules created with ds pdb reference so that SymSrvGetFileInfoInfo() succeeds */ - ds_blob = make_pdb_ds_blob(ft->timestamp, &guid1, 124, "pdbds.pdb"); + ds_blob = make_pdb_ds_blob(ft->timestamp, &guid1, 124 + i, "pdbds.pdb"); if (ft->bitness == 64) { init_headers64(&hdr.nt_header64, ft->timestamp, ft->size_of_image, 0); @@ -1146,9 +1149,11 @@ static void test_find_in_path_pe(void) else wcscpy(file, image_tests[i].module); + memset(&pv, 0, sizeof(pv)); + pv.age = 124 + i; + pv.guid = guid1; pv.timestamp = image_tests[i].lookup_timestamp; pv.size_of_image = image_tests[i].lookup_size_of_image; - pv.cb_count = 0; memset(found, 0, sizeof(found)); ret = SymFindFileInPathW(proc, search, file, @@ -1212,6 +1217,224 @@ static void test_find_in_path_pe(void) ok(ret, "Couldn't remove directory\n"); } +/* Comment on top of test_find_in_path_pe() also applies here */ +static void test_find_in_path_pdb(void) +{ + HANDLE proc = (HANDLE)(DWORD_PTR)0x666002; + WCHAR topdir[MAX_PATH]; + WCHAR search[MAX_PATH]; + WCHAR file[MAX_PATH]; + WCHAR found[MAX_PATH]; + struct path_validate pv; + DWORD len; + BOOL ret; + int i; + + static const struct debug_info_file + { + const GUID* guid; + DWORD age; + const WCHAR*module_path; + } + test_files[] = + { + /* 0 */ { &guid1, 0x0030cafe, L"foobar.pdb" }, + /* 1 */ { &guid1, 0x0030cafe, L"A\\foobar.pdb" }, + /* 2 */ { &guid1, 0x0030cafe, L"B\\foobar.pdb" }, + /* 3 */ { &guid2, 0x0010f00d, L"foobar.pdb" }, + /* 4 */ { &guid2, 0x0010f00d, L"A\\foobar.pdb" }, + /* 5 */ { &guid2, 0x0010f00d, L"B\\foobar.pdb" }, + /* 6 */ { &guid1, 0x0030cafe, L"foobar.pdb" }, + /* 7 */ { &guid1, 0x0030cafe, L"A\\foobar.pdb" }, + /* 8 */ { &guid1, 0x0030cafe, L"B\\foobar.pdb" }, + /* 9 */ { &guid2, 0x0010f00d, L"foobar.pdb" }, + /* a */ { &guid2, 0x0010f00d, L"A\\foobar.pdb" }, + /* b */ { &guid2, 0x0010f00d, L"B\\foobar.pdb" }, + /* c */ { &guid1, 0x0030cafe, L"dll\\foobar.pdb" }, + /* d */ { &guid1, 0x0030cafe, L"symbols\\dll\\foobar.pdb" }, + }; + static const struct image_tests + { + /* files to generate */ + const char* files; + /* parameters for lookup */ + const GUID* lookup_guid; + DWORD lookup_age; + const char* search; /* several of ., A, B to link to directories */ + const WCHAR* module; + /* expected results */ + const WCHAR* found_subdir; + DWORD expected_cb_count; + } + pdb_tests[] = + { + /* all files 64 bit */ + /* the passed timestamp & size are not checked before calling the callback! */ + /* 0 */ { "0", NULL, 0x00000000, ".", L"foobar.pdb", NULL, 1}, + /* 1 */ { "0", &guid1, 0x00000000, ".", L"foobar.pdb", NULL, 1}, + /* 2 */ { "0", NULL, 0x0030cafe, ".", L"foobar.pdb", NULL, 1}, + /* 3 */ { "0", &guid1, 0x0030cafe, ".", L"foobar.pdb", L"", 1}, + /* no recursion into subdirectories */ + /* 4 */ { "1", &guid1, 0x0030cafe, ".", L"foobar.pdb", NULL, 0}, + /* directories are searched in order */ + /* 5 */ { "15", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 6 */ { "15", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"A\\", 2}, + /* 7 */ { "12", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 8 */ { "12", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"B\\", 1}, + + /* all files 32 bit */ + /* the passed timestamp & size is not checked ! */ + /* 9 */ { "6", NULL, 0x00000000, ".", L"foobar.pdb", NULL, 1}, + /* 10 */ { "6", &guid1, 0x00000000, ".", L"foobar.pdb", NULL, 1}, + /* 11 */ { "6", NULL, 0x0030cafe, ".", L"foobar.pdb", NULL, 1}, + /* 12 */ { "6", &guid1, 0x0030cafe, ".", L"foobar.pdb", L"", 1}, + /* no recursion into subdirectories */ + /* 13 */ { "7", &guid1, 0x0030cafe, ".", L"foobar.pdb", NULL, 0}, + /* directories are searched in order */ + /* 14 */ { "7b", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 15 */ { "7b", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"A\\", 2}, + /* 16 */ { "78", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 17 */ { "78", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"B\\", 1}, + + /* machine and bitness is not used */ + /* 18 */ { "1b", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 19 */ { "1b", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"A\\", 2}, + /* 20 */ { "18", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 21 */ { "18", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"B\\", 1}, + /* 22 */ { "75", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 23 */ { "75", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"A\\", 2}, + /* 24 */ { "72", &guid1, 0x0030cafe, "AB", L"foobar.pdb", L"A\\", 1}, + /* 25 */ { "72", &guid1, 0x0030cafe, "BA", L"foobar.pdb", L"B\\", 1}, + + /* specifying a full path to module isn't taken into account */ + /* 26 */ { "0", &guid1, 0x0030cafe, "AB", L"@foobar.pdb", NULL, 0}, + /* 27 */ { "6", &guid1, 0x0030cafe, "AB", L"@foobar.pdb", NULL, 0}, + + /* subdirectories searched by SymLoadModule*() are not covered implicitely */ + /* 28 */ { "c", &guid1, 0x0030cafe, ".", L"foobar.pdb", NULL, 0}, + /* 28 */ { "d", &guid1, 0x0030cafe, ".", L"foobar.pdb", NULL, 0}, + + }; + static const WCHAR* list_directories[] = {L"A", L"B", L"dll", L"symbols", L"symbols\\dll", L"acm", L"symbols\\acm"}; + + ret = SymInitializeW(proc, NULL, FALSE); + ok(ret, "Couldn't init dbghelp\n"); + + len = GetTempPathW(ARRAY_SIZE(topdir), topdir); + ok(len && len < ARRAY_SIZE(topdir), "Unexpected length\n"); + wcscat(topdir, L"dh.tmp\\"); + ret = CreateDirectoryW(topdir, NULL); + ok(ret, "Couldn't create directory\n"); + for (i = 0; i < ARRAY_SIZE(list_directories); i++) + { + make_path(file, topdir, list_directories[i], NULL); + ret = CreateDirectoryW(file, NULL); + ok(ret, "Couldn't create directory %u %ls\n", i, list_directories[i]); + } + + for (i = 0; i < ARRAY_SIZE(pdb_tests); ++i) + { + const char* ptr; + winetest_push_context("path_pdb_%u", i); + + for (ptr = pdb_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(test_files)) + { + make_path(file, topdir, NULL, test_files[val].module_path); + create_test_pdb_ds(file, test_files[val].guid, test_files[val].age); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + search[0] = L'\0'; + for (ptr = pdb_tests[i].search; *ptr; ptr++) + { + if (*search) wcscat(search, L";"); + wcscat(search, topdir); + if (*ptr == '.') + ; + else if (*ptr == 'A') + wcscat(search, L"A"); + else if (*ptr == 'B') + wcscat(search, L"B"); + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + if (pdb_tests[i].module[0] == L'@') + make_path(file, topdir, NULL, &pdb_tests[i].module[1]); + else + wcscpy(file, pdb_tests[i].module); + + memset(&pv, 0, sizeof(pv)); + if (pdb_tests[i].lookup_guid) + pv.guid = *pdb_tests[i].lookup_guid; + pv.age = pdb_tests[i].lookup_age; + memset(found, 0, sizeof(found)); + + ret = SymFindFileInPathW(proc, search, file, + (void*)pdb_tests[i].lookup_guid, + 0, pdb_tests[i].lookup_age, + SSRVOPT_GUIDPTR, found, path_cb, &pv); + + todo_wine + ok(pv.cb_count == pdb_tests[i].expected_cb_count, + "Mismatch in cb count, got %u (expected %lu)\n", + pv.cb_count, pdb_tests[i].expected_cb_count); + if (pdb_tests[i].found_subdir) + { + size_t l1, l2, l3; + + ok(ret, "Couldn't find file: %ls %lu\n", search, GetLastError()); + + l1 = wcslen(topdir); + l2 = wcslen(pdb_tests[i].found_subdir); + l3 = wcslen(pdb_tests[i].module); + + ok(l1 + l2 + l3 == wcslen(found) && + !memcmp(found, topdir, l1 * sizeof(WCHAR)) && + !memcmp(&found[l1], pdb_tests[i].found_subdir, l2 * sizeof(WCHAR)) && + !memcmp(&found[l1 + l2], pdb_tests[i].module, l3 * sizeof(WCHAR)), + "Mismatch in found file %ls (expecting %ls)\n", + found, pdb_tests[i].found_subdir); + } + else + { + todo_wine_if(i == 26 || i == 27) + ok(!ret, "File reported found, while failure is expected\n"); + todo_wine + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Unexpected error %lu\n", GetLastError()); + } + + for (ptr = pdb_tests[i].files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(test_files)) + { + make_path(file, topdir, NULL, test_files[val].module_path); + ret = DeleteFileW(file); + ok(ret, "Couldn't delete file %c %ls\n", *ptr, file); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + winetest_pop_context(); + } + + SymCleanup(proc); + + for (i = ARRAY_SIZE(list_directories) - 1; i >= 0; i--) + { + make_path(file, topdir, list_directories[i], NULL); + ret = RemoveDirectoryW(file); + ok(ret, "Couldn't remove directory %u %ls\n", i, list_directories[i]); + } + + ret = RemoveDirectoryW(topdir); + ok(ret, "Couldn't remove directory\n"); +} + START_TEST(path) { /* cleanup env variables that affect dbghelp's behavior */ @@ -1222,4 +1445,5 @@ START_TEST(path) test_srvgetindexes_pdb(); test_srvgetindexes_dbg(); test_find_in_path_pe(); + test_find_in_path_pdb(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/dbghelp/tests/path.c | 233 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 1e057a206ab..479985d1c7e 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -1435,6 +1435,232 @@ static void test_find_in_path_pdb(void) ok(ret, "Couldn't remove directory\n"); } +static void test_load_modules_path(void) +{ + static const WCHAR* top_subdirs[] = {L"mismatch", + L"search.tmp", L"search.tmp\\dll", L"search.tmp\\symbols", L"search.tmp\\symbols\\dll", L"search.tmp\\dummy"}; + static const struct debug_info_file + { + const GUID* guid; /* non-NULL means PDB/DS, DBG otherwise */ + DWORD age_or_timestamp; /* age for PDB, timestamp for DBG */ + const WCHAR*module_path; + } + test_files[] = + { + /* 0 */ { &guid1, 0x0030cafe, L"bar.pdb" }, + /* 1 */ { &guid1, 0x0030cafe, L"search.tmp\\bar.pdb" }, + /* 2 */ { &guid1, 0x0030cafe, L"search.tmp\\dll\\bar.pdb" }, + /* 3 */ { &guid1, 0x0030cafe, L"search.tmp\\symbols\\dll\\bar.pdb" }, + /* 4 */ { &guid1, 0x0030cafe, L"search.tmp\\dummy\\bar.pdb" }, + /* 5 */ { &guid1, 0x0031cafe, L"mismatch\\bar.pdb" }, + /* 6 */ { &guid1, 0x0032cafe, L"search.tmp\\bar.pdb" }, + /* 7 */ { &guid1, 0x0033cafe, L"search.tmp\\dll\\bar.pdb" }, + }; + + static const struct module_path_test + { + /* input parameters */ + DWORD options; + const char *search; /* search path in SymInitialize (s=search, t=top=dll's dir, m=mismatch) */ + const char *test_files; /* various test_files to be created */ + /* output parameters */ + int found_file; + } + module_path_tests[] = + { +/* 0*/ {0, NULL, "0", 0}, + /* matching pdb, various directories searched */ + {0, "s", "0", 0}, + {0, "s", "01", 1}, + {0, "s", "1", 1}, + {0, "s", "2", 2}, +/* 5*/ {0, "s", "3", 3}, + {0, "s", "1234", 1}, + {0, "s", "234", 2}, + {0, "s", "34", 3}, + {0, "s", "4", -1}, + /* no matching pdb, impact of options */ +/*10*/ {0, "s", "7", -1}, + {SYMOPT_LOAD_ANYTHING, "s", "7", 7}, + {SYMOPT_LOAD_ANYTHING, "s", "67", 6}, + {SYMOPT_EXACT_SYMBOLS, "s", "7", -1}, /* doesn't seem effective on path search */ + /* mismatch and several search directories */ + {0, "ms", "51", 1}, +/*15*/ {0, "sm", "51", 1}, + {SYMOPT_LOAD_ANYTHING, "ms", "51", 1}, + {SYMOPT_LOAD_ANYTHING, "sm", "51", 1}, + {0, "ms", "57", -1}, + {0, "sm", "57", -1}, +/*20*/ {SYMOPT_LOAD_ANYTHING, "ms", "57", 5}, + {SYMOPT_LOAD_ANYTHING, "sm", "57", 7}, + }; + + int i; + HANDLE dummy = (HANDLE)(ULONG_PTR)0xc4fef00d; + DWORD old_options; + IMAGEHLP_MODULEW64 im; + BOOL ret; + DWORD64 base; + WCHAR topdir[MAX_PATH]; + WCHAR filename[MAX_PATH]; + DWORD len; + union nt_header h; + struct debug_directory_blob* blob_ref; + + old_options = SymGetOptions(); + im.SizeOfStruct = sizeof(im); + + len = GetTempPathW(ARRAY_SIZE(topdir), topdir); + ok(len && len < ARRAY_SIZE(topdir), "Unexpected length\n"); + wcscat(topdir, L"dh.tmp\\"); + ret = CreateDirectoryW(topdir, NULL); + ok(ret, "Couldn't create directory\n"); + for (i = 0; i < ARRAY_SIZE(top_subdirs); i++) + { + make_path(filename, topdir, top_subdirs[i], NULL); + ret = CreateDirectoryW(filename, NULL); + ok(ret, "Couldn't create directory %ls\n", filename); + } + + init_headers64(&h.nt_header64, 12324, 3242, 0); + blob_ref = make_pdb_ds_blob(12324, &guid1, 0x0030cafe, "bar.pdb"); + make_path(filename, topdir, NULL, L"bar.dll"); + create_test_dll(&h, sizeof(h.nt_header64), &blob_ref, 1, filename); + + for (i = 0; i < ARRAY_SIZE(module_path_tests); i++) + { + const struct module_path_test *test = module_path_tests + i; + const char* ptr; + + winetest_push_context("module_path_test %d", i); + + /* setup debug info files */ + for (ptr = test->test_files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(test_files)) + { + make_path(filename, topdir, NULL, test_files[val].module_path); + if (test_files[val].guid) + create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp); + else + create_test_dbg(filename, IMAGE_FILE_MACHINE_AMD64 /* FIXME */, test_files[val].age_or_timestamp, 0x40000 * val * 0x20000); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + + if (test->search) + { + filename[0]= L'\0'; + for (ptr = test->search; *ptr; ptr++) + { + if (*filename) wcscat(filename, L";"); + wcscat(filename, topdir); + switch (*ptr) + { + case 'm': + wcscat(filename, L"mismatch\\"); + break; + case 's': + wcscat(filename, L"search.tmp\\"); + break; + case 't': + break; + default: assert(0); + } + } + } + SymSetOptions((SymGetOptions() & ~(SYMOPT_EXACT_SYMBOLS | SYMOPT_LOAD_ANYTHING)) | test->options); + ret = SymInitializeW(dummy, test->search ? filename : NULL, FALSE); + ok(ret, "SymInitialize failed: %lu\n", GetLastError()); + make_path(filename, topdir, NULL, L"bar.dll"); + base = SymLoadModuleExW(dummy, NULL, filename, NULL, 0x4000, 0x6666, NULL, 0); + todo_wine_if(sizeof(void*) == 4) + ok(base == 0x4000, "SymLoadModuleExW failed: %lu\n", GetLastError()); + if (base == 0x4000 && sizeof(void*) != 4) { /* temp */ + im.SizeOfStruct = sizeof(im); + ret = SymGetModuleInfoW64(dummy, base, &im); + ok(ret, "SymGetModuleInfow64 failed: %lu\n", GetLastError()); + + make_path(filename, topdir, NULL, L"bar.dll"); + ok(!wcscmp(im.LoadedImageName, filename), + "Expected %ls as loaded image file, got '%ls' instead\n", L"bar.dll", im.LoadedImageName); + if (test->found_file == -1) + { + todo_wine + ok(im.SymType == SymNone, "Unexpected symtype %x\n", im.SymType); + ok(!im.LoadedPdbName[0], "Expected empty loaded pdb file, got '%ls' instead\n", im.LoadedPdbName); + todo_wine + ok(im.PdbAge == 0x0030cafe, "Expected %x as pdb-age, got %lx instead\n", 0x0030cafe, im.PdbAge); + ok(!im.PdbUnmatched, "Expecting matched PDB\n"); + } + else + { + todo_wine + ok(im.SymType == SymPdb, "Unexpected symtype %x\n", im.SymType); + make_path(filename, topdir, NULL, test_files[test->found_file].module_path); + todo_wine + ok(!wcscmp(im.LoadedPdbName, filename), + "Expected %ls as loaded pdb file, got '%ls' instead\n", test_files[test->found_file].module_path, im.LoadedPdbName); + todo_wine + ok(im.PdbAge == test_files[test->found_file].age_or_timestamp, + "Expected %lx as pdb-age, got %lx instead\n", test_files[test->found_file].age_or_timestamp, im.PdbAge); + todo_wine_if(i == 11 || i == 16 || i == 17) + ok(im.PdbUnmatched == !(test_files[test->found_file].age_or_timestamp == 0x0030cafe), "Expecting matched PDB\n"); + } + todo_wine + ok(IsEqualGUID(&im.PdbSig70, &guid1), "Unexpected PDB GUID\n"); + } /* temp */ + ret = SymCleanup(dummy); + ok(ret, "SymCleanup failed: %lu\n", GetLastError()); + for (ptr = test->test_files; *ptr; ptr++) + { + unsigned val = char2index(*ptr); + if (val < ARRAY_SIZE(test_files)) + { + make_path(filename, topdir, NULL, test_files[val].module_path); + ret = DeleteFileW(filename); + ok(ret, "Couldn't delete file %c %ls\n", *ptr, filename); + } + else ok(0, "Unrecognized file reference %c\n", *ptr); + } + winetest_pop_context(); + } + SymSetOptions(old_options); + free(blob_ref); + make_path(filename, topdir, NULL, L"bar.dll"); + ret = DeleteFileW(filename); + ok(ret, "Couldn't delete file %ls\n", filename); + for (i = ARRAY_SIZE(top_subdirs) - 1; i >= 0; i--) + { + make_path(filename, topdir, top_subdirs[i], NULL); + ret = RemoveDirectoryW(filename); + ok(ret, "Couldn't create directory %ls\n", filename); + } + ret = RemoveDirectoryW(topdir); + todo_wine /* bug in Wine not closing all mappings */ + ok(ret, "Couldn't remove directory\n"); +} + +static BOOL skip_too_old_dbghelp(void) +{ + IMAGEHLP_MODULEW64 im64 = {sizeof(im64)}; + IMAGEHLP_MODULE im0 = {sizeof(im0)}; + BOOL will_skip = TRUE; + + if (!strcmp(winetest_platform, "wine")) return FALSE; + if (SymInitialize(GetCurrentProcess(), NULL, FALSE)) + { + DWORD64 base = SymLoadModule(GetCurrentProcess(), NULL, "c:\\windows\\system32\\ntdll.dll", NULL, 0x4000, 0); + /* test if get module info succeeds with oldest structure format */ + if (base) + will_skip = !SymGetModuleInfoW64(GetCurrentProcess(), base, &im64) && + SymGetModuleInfo(GetCurrentProcess(), base, &im0); + SymCleanup(GetCurrentProcess()); + } + return will_skip; +} + START_TEST(path) { /* cleanup env variables that affect dbghelp's behavior */ @@ -1446,4 +1672,11 @@ START_TEST(path) test_srvgetindexes_dbg(); test_find_in_path_pe(); test_find_in_path_pdb(); + + if (skip_too_old_dbghelp()) + win_skip("Not testing on too old dbghelp version\n"); + else + { + test_load_modules_path(); + } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/dbghelp/pe_module.c | 3 +-- dlls/dbghelp/tests/path.c | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 909ac794c38..06e70c35037 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -268,12 +268,11 @@ BOOL pe_map_file(HANDLE file, struct image_file_map* fmap) memcpy(&fmap->u.pe.opt.header32, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt.header32)); break; case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - if (sizeof(void*) == 4) return FALSE; fmap->addr_size = 64; memcpy(&fmap->u.pe.opt.header64, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt.header64)); break; default: - return FALSE; + goto error; } fmap->u.pe.builtin = !memcmp((const IMAGE_DOS_HEADER*)mapping + 1, builtin_signature, sizeof(builtin_signature)); diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 479985d1c7e..9074d42ac94 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -1575,9 +1575,7 @@ static void test_load_modules_path(void) ok(ret, "SymInitialize failed: %lu\n", GetLastError()); make_path(filename, topdir, NULL, L"bar.dll"); base = SymLoadModuleExW(dummy, NULL, filename, NULL, 0x4000, 0x6666, NULL, 0); - todo_wine_if(sizeof(void*) == 4) ok(base == 0x4000, "SymLoadModuleExW failed: %lu\n", GetLastError()); - if (base == 0x4000 && sizeof(void*) != 4) { /* temp */ im.SizeOfStruct = sizeof(im); ret = SymGetModuleInfoW64(dummy, base, &im); ok(ret, "SymGetModuleInfow64 failed: %lu\n", GetLastError()); @@ -1610,7 +1608,6 @@ static void test_load_modules_path(void) } todo_wine ok(IsEqualGUID(&im.PdbSig70, &guid1), "Unexpected PDB GUID\n"); - } /* temp */ ret = SymCleanup(dummy); ok(ret, "SymCleanup failed: %lu\n", GetLastError()); for (ptr = test->test_files; *ptr; ptr++) @@ -1638,7 +1635,6 @@ static void test_load_modules_path(void) ok(ret, "Couldn't create directory %ls\n", filename); } ret = RemoveDirectoryW(topdir); - todo_wine /* bug in Wine not closing all mappings */ ok(ret, "Couldn't remove directory\n"); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/dbghelp/path.c | 8 +------- dlls/dbghelp/tests/path.c | 11 ----------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c index ec182c969d3..f45807c634f 100644 --- a/dlls/dbghelp/path.c +++ b/dlls/dbghelp/path.c @@ -398,13 +398,6 @@ BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_p filename = file_name(full_path); - /* first check full path to file */ - if (sffip_cb(full_path, &s)) - { - lstrcpyW(buffer, full_path); - return TRUE; - } - while (searchPath) { ptr = wcschr(searchPath, ';'); @@ -425,6 +418,7 @@ BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_p return TRUE; } } + SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } diff --git a/dlls/dbghelp/tests/path.c b/dlls/dbghelp/tests/path.c index 9074d42ac94..0efe55defd2 100644 --- a/dlls/dbghelp/tests/path.c +++ b/dlls/dbghelp/tests/path.c @@ -957,12 +957,7 @@ static BOOL CALLBACK path_cb(PCWSTR filename, void* _usr) BOOL ret; pv->cb_count++; - /* wine returns paths in relative form, but relative to search path... - * fail (== continue search) until it's fixed - */ - todo_wine_if(!filename[0] || filename[1] != ':') ok(filename[0] && filename[1] == ':', "Expecting full path, but got %ls\n", filename); - if (!filename[0] || filename[1] != ':') return TRUE; memset(&ssii, 0, sizeof(ssii)); ssii.sizeofstruct = sizeof(ssii); @@ -1161,7 +1156,6 @@ static void test_find_in_path_pe(void) image_tests[i].lookup_size_of_image, 0, SSRVOPT_DWORDPTR, found, path_cb, &pv); - todo_wine ok(pv.cb_count == image_tests[i].expected_cb_count, "Mismatch in cb count, got %u (expected %lu)\n", pv.cb_count, image_tests[i].expected_cb_count); @@ -1184,9 +1178,7 @@ static void test_find_in_path_pe(void) } else { - todo_wine_if(i == 26 || i == 27) ok(!ret, "File reported found, while failure is expected\n"); - todo_wine_if(i == 26 || i == 27 || (GetLastError() != ERROR_FILE_NOT_FOUND)) ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Unexpected error %lu\n", GetLastError()); } for (ptr = image_tests[i].files; *ptr; ptr++) @@ -1378,7 +1370,6 @@ static void test_find_in_path_pdb(void) 0, pdb_tests[i].lookup_age, SSRVOPT_GUIDPTR, found, path_cb, &pv); - todo_wine ok(pv.cb_count == pdb_tests[i].expected_cb_count, "Mismatch in cb count, got %u (expected %lu)\n", pv.cb_count, pdb_tests[i].expected_cb_count); @@ -1401,9 +1392,7 @@ static void test_find_in_path_pdb(void) } else { - todo_wine_if(i == 26 || i == 27) ok(!ret, "File reported found, while failure is expected\n"); - todo_wine ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Unexpected error %lu\n", GetLastError()); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5204
participants (2)
-
Eric Pouech -
eric pouech (@epo)