The following series beefs up the tests about dbghelp DLL and fixes a couple of bugs in dbghelp.
The idea is to have a set of files to get debug info from (debuggee*.*).
This is supported in two different ways: A) to be compiled directly inside dbghelp_test: the default tools and options used in Wine will be covered (now: cross compile + dwarf version 2 debug format) B) but also the ability to run the same tests on an external process + image (made mainly out of the debuggee*.* only files). The idea is of course to use different compilers, debug format, options, 32/64bit targets... Those alternate images **ARE NOT** part (for now) of winetest.
Unfortunately, with Winetest Bot, the A) won't work under windows: debug format of dbghelp_test.exe is dwarf2, while native dbghelp doesn't support it. So the tests are skipped. Anyway, most of the Windows setup:s don't have native dbghelp.dll installed <g>, so that shouldn't change much.
I locally test every patch with: - A) on 32bit Wine (mingw + dwarf2) - A) on 64bit Wine (mingw + dwarf2) - A) on Windows10 as PE64 (msc + pdb) - B) image: mingw + dwarf2 + target=PE64bit + option -O1 on 64bit Wine - B) image: mingw + dwarf2 + target=PE32bit + option -O1 on 32bit Wine - B) image: ms compiler + pdb + target=PE64bit + option /O1 on 64 bit Wine
This serie will be continued with: 1) more tests (and more fixes) (around 20+ patches to come) 2) support of dwarf3 and 4 (around 70+ patches to come)
I also plan to add more local tests (dwarf3 and dwarf4; WoW; PE32 + pdb on Wine, cross 32/64 bit between tester and debuggee, other options O2).
A+
---
Eric Pouech (9): dbghelp/tests: Added dedicated structure to control the debuggee dbghelp/tests: Added ability to launch an external process instead of debugging self dbghelp/tests: Now properly getting base of main module inside debuggee structure dbghelp/tests: Added two new compilation units (debuggee1.c and debuggee2.c) dbghelp/tests: now building inside each debuggee a manifest dbghelp/tests: StackWalk64 testing now support external process dbghelp/tests: Added tests about getting symbol information dbghelp: returns name of compiland in SymGetTypeInfo dbghelp: handling of complex location in dwarf
dlls/dbghelp/dwarf.c | 1 - dlls/dbghelp/tests/Makefile.in | 4 +- dlls/dbghelp/tests/dbghelp.c | 505 +++++++++++++++++++++++++++++++-- dlls/dbghelp/tests/debuggee.h | 30 ++ dlls/dbghelp/tests/debuggee1.c | 115 ++++++++ dlls/dbghelp/tests/debuggee2.c | 7 + dlls/dbghelp/type.c | 3 +- 7 files changed, 644 insertions(+), 21 deletions(-) create mode 100644 dlls/dbghelp/tests/debuggee.h create mode 100644 dlls/dbghelp/tests/debuggee1.c create mode 100644 dlls/dbghelp/tests/debuggee2.c
- for now, it's purely inside the tests/dbghelp.c - the goal is to also allow an external process
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 57 +++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index a243d047d18..c9bbd90deb4 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -21,6 +21,13 @@ #include "dbghelp.h" #include "wine/test.h"
+struct debuggee +{ + const char* name; /* name of main module */ + HANDLE hProcess; + HANDLE hThread; /* either new thread calling stack_walk_thread, or main thread */ +}; + #if defined(__i386__) || defined(__x86_64__)
static DWORD CALLBACK stack_walk_thread(void *arg) @@ -30,32 +37,19 @@ static DWORD CALLBACK stack_walk_thread(void *arg) return 0; }
-static void test_stack_walk(void) +static void test_stack_walk(const struct debuggee* dbg) { char si_buf[sizeof(SYMBOL_INFO) + 200]; SYMBOL_INFO *si = (SYMBOL_INFO *)si_buf; STACKFRAME64 frame = {{0}}, frame0; BOOL found_our_frame = FALSE; DWORD machine; - HANDLE thread; DWORD64 disp; CONTEXT ctx; - DWORD count; BOOL ret;
- thread = CreateThread(NULL, 0, stack_walk_thread, NULL, 0, NULL); - - /* wait for the thread to suspend itself */ - do - { - Sleep(50); - count = SuspendThread(thread); - ResumeThread(thread); - } - while (!count); - ctx.ContextFlags = CONTEXT_CONTROL; - ret = GetThreadContext(thread, &ctx); + ret = GetThreadContext(dbg->hThread, &ctx); ok(ret, "got error %u\n", ret);
frame.AddrPC.Mode = AddrModeFlat; @@ -84,7 +78,7 @@ static void test_stack_walk(void) frame0 = frame;
/* first invocation just calculates the return address */ - ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, + ret = StackWalk64(machine, dbg->hProcess, dbg->hThread, &frame, &ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); ok(ret, "StackWalk64() failed: %u\n", GetLastError()); ok(frame.AddrPC.Offset == frame0.AddrPC.Offset, "expected %s, got %s\n", @@ -100,7 +94,7 @@ static void test_stack_walk(void) { char *addr;
- ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, + ret = StackWalk64(machine, dbg->hProcess, dbg->hThread, &frame, &ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); ok(ret, "StackWalk64() failed: %u\n", GetLastError());
@@ -112,12 +106,12 @@ static void test_stack_walk(void)
si->SizeOfStruct = sizeof(SYMBOL_INFO); si->MaxNameLen = 200; - if (SymFromAddr(GetCurrentProcess(), frame.AddrPC.Offset, &disp, si)) + if (SymFromAddr(dbg->hProcess, frame.AddrPC.Offset, &disp, si)) ok(!strcmp(si->Name, "stack_walk_thread"), "got wrong name %s\n", si->Name); } }
- ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, + ret = StackWalk64(machine, dbg->hProcess, dbg->hThread, &frame, &ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); ok(!ret, "StackWalk64() should have failed\n");
@@ -126,7 +120,7 @@ static void test_stack_walk(void)
#else /* __i386__ || __x86_64__ */
-static void test_stack_walk(void) +static void test_stack_walk(const struct debuggee* dbg) { }
@@ -134,11 +128,28 @@ static void test_stack_walk(void)
START_TEST(dbghelp) { - BOOL ret = SymInitialize(GetCurrentProcess(), NULL, TRUE); + struct debuggee dbg; + DWORD count; + BOOL ret; + + dbg.name = "self"; + dbg.hProcess = GetCurrentProcess(); + dbg.hThread = CreateThread(NULL, 0, stack_walk_thread, NULL, 0, NULL); + + /* wait for the thread to suspend itself */ + do + { + Sleep(50); + count = SuspendThread(dbg.hThread); + ResumeThread(dbg.hThread); + } + while (!count); + + ret = SymInitialize(dbg.hProcess, NULL, TRUE); ok(ret, "got error %u\n", GetLastError());
- test_stack_walk(); + test_stack_walk(&dbg);
- ret = SymCleanup(GetCurrentProcess()); + ret = SymCleanup(dbg.hProcess); ok(ret, "got error %u\n", GetLastError()); }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 77 +++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 12 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index c9bbd90deb4..b0302b85ad1 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -24,6 +24,7 @@ struct debuggee { const char* name; /* name of main module */ + BOOL external_process; HANDLE hProcess; HANDLE hThread; /* either new thread calling stack_walk_thread, or main thread */ }; @@ -126,30 +127,82 @@ static void test_stack_walk(const struct debuggee* dbg)
#endif /* __i386__ || __x86_64__ */
-START_TEST(dbghelp) +static BOOL start_process(struct debuggee* dbg, const char* other) { - struct debuggee dbg; DWORD count; - BOOL ret;
- dbg.name = "self"; - dbg.hProcess = GetCurrentProcess(); - dbg.hThread = CreateThread(NULL, 0, stack_walk_thread, NULL, 0, NULL); + memset(dbg, 0, sizeof(*dbg)); + if (other) + { + STARTUPINFOA siA; + PROCESS_INFORMATION pi; + memset(&siA, 0, sizeof(siA)); + siA.cb = sizeof(siA); + memset(&pi, 0, sizeof(pi)); + + if (!CreateProcessA(other, NULL, NULL, NULL, FALSE, + NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL, &siA, &pi)) + { + skip("Cannot launch %s\n", other); + return FALSE; + } + dbg->name = other; + dbg->external_process = TRUE; + dbg->hProcess = pi.hProcess; + dbg->hThread = pi.hThread; + } + else + { + char** argv; + winetest_get_mainargs(&argv); + dbg->name = argv[0]; + dbg->external_process = FALSE; + dbg->hProcess = GetCurrentProcess(); + dbg->hThread = CreateThread(NULL, 0, stack_walk_thread, NULL, 0, NULL); + } + + if (!SymInitialize(dbg->hProcess, NULL, TRUE)) + { + skip("Cannot init dbghelp on %s\n", dbg->name); + return FALSE; + }
/* wait for the thread to suspend itself */ do { Sleep(50); - count = SuspendThread(dbg.hThread); - ResumeThread(dbg.hThread); + count = SuspendThread(dbg->hThread); + ResumeThread(dbg->hThread); } while (!count);
- ret = SymInitialize(dbg.hProcess, NULL, TRUE); - ok(ret, "got error %u\n", GetLastError()); + return TRUE; +}
- test_stack_walk(&dbg); +static void close_process(const struct debuggee* dbg) +{ + BOOL ret;
- ret = SymCleanup(dbg.hProcess); + ret = SymCleanup(dbg->hProcess); ok(ret, "got error %u\n", GetLastError()); + + if (dbg->external_process) + { + ok(TerminateProcess(dbg->hProcess, 1), "Couldn't terminate debuggee %u\n", GetLastError()); + CloseHandle(dbg->hProcess); + CloseHandle(dbg->hThread); + } +} + +START_TEST(dbghelp) +{ + struct debuggee dbg; + const char* other = getenv("WINETEST_DBGHELP_OTHER"); + + if (start_process(&dbg, other)) + { + test_stack_walk(&dbg); + + close_process(&dbg); + } }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index b0302b85ad1..a6c524177bf 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -27,6 +27,8 @@ struct debuggee BOOL external_process; HANDLE hProcess; HANDLE hThread; /* either new thread calling stack_walk_thread, or main thread */ + DWORD64 base; + DWORD64 size; };
#if defined(__i386__) || defined(__x86_64__) @@ -127,9 +129,44 @@ static void test_stack_walk(const struct debuggee* dbg)
#endif /* __i386__ || __x86_64__ */
+static BOOL CALLBACK find_main_module_cb(PCSTR name, DWORD64 base, PVOID in_user) +{ + struct debuggee* dbg = in_user; + IMAGEHLP_MODULE im; + + memset(&im, 0, sizeof(im)); + im.SizeOfStruct = sizeof(im); + ok(SymGetModuleInfo(dbg->hProcess, base, &im), "SymGetModuleInfo failed: %u\n", GetLastError()); + + if (dbg->external_process) + { + /* lookup external exec path as module name */ + const char* ff; + const char* fb; + const char* ext; + + if (!(ff = strrchr(dbg->name, '/'))) ff = dbg->name; else ++ff; + if (!(fb = strrchr(ff, '\'))) fb = ff; else ++fb; + + ext = strchr(fb, '.'); + if ((!ext || !_strcmpi(ext, ".exe")) && !_strnicmp(fb, im.ModuleName, ext ? ext - fb : strlen(fb))) + { + dbg->base = im.BaseOfImage; + dbg->size = im.ImageSize; + } + } + else + { + dbg->base = im.BaseOfImage; + dbg->size = im.ImageSize; + } + return TRUE; +} + static BOOL start_process(struct debuggee* dbg, const char* other) { DWORD count; + BOOL ret;
memset(dbg, 0, sizeof(*dbg)); if (other) @@ -176,6 +213,21 @@ static BOOL start_process(struct debuggee* dbg, const char* other) } while (!count);
+ /* init base and size fields */ + if (dbg->external_process) + { + dbg->base = dbg->size = 0; + ret = SymEnumerateModules64(dbg->hProcess, find_main_module_cb, dbg); + ok(ret && dbg->base != 0, "No base for main module: %u\n", GetLastError()); + if (!ret || dbg->base == 0) + return FALSE; + } + else + { + /* force the main module */ + find_main_module_cb(dbg->name, (DWORD_PTR)&start_process, dbg); + } + return TRUE; }
All the debuggee*.* files are supposed to hold all the source code for the debug information we'll gather
Next patches will actually do the reading of debug information
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/Makefile.in | 4 ++- dlls/dbghelp/tests/dbghelp.c | 3 ++ dlls/dbghelp/tests/debuggee.h | 23 ++++++++++++++ dlls/dbghelp/tests/debuggee1.c | 64 ++++++++++++++++++++++++++++++++++++++++ dlls/dbghelp/tests/debuggee2.c | 7 ++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 dlls/dbghelp/tests/debuggee.h create mode 100644 dlls/dbghelp/tests/debuggee1.c create mode 100644 dlls/dbghelp/tests/debuggee2.c
diff --git a/dlls/dbghelp/tests/Makefile.in b/dlls/dbghelp/tests/Makefile.in index 31e5b01e8a8..e87f1abf504 100644 --- a/dlls/dbghelp/tests/Makefile.in +++ b/dlls/dbghelp/tests/Makefile.in @@ -2,4 +2,6 @@ TESTDLL = dbghelp.dll IMPORTS = dbghelp
C_SRCS = \ - dbghelp.c + dbghelp.c \ + debuggee1.c \ + debuggee2.c diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index a6c524177bf..123989442bf 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -258,3 +258,6 @@ START_TEST(dbghelp) close_process(&dbg); } } + +START_TEST(debuggee1) {} +START_TEST(debuggee2) {} diff --git a/dlls/dbghelp/tests/debuggee.h b/dlls/dbghelp/tests/debuggee.h new file mode 100644 index 00000000000..9e181f1ba17 --- /dev/null +++ b/dlls/dbghelp/tests/debuggee.h @@ -0,0 +1,23 @@ +/* avoid including standard headers, just to keep debug information as lean as possible */ +typedef void* HANDLE; +typedef unsigned long DWORD; +typedef unsigned long long DWORD64; + +extern HANDLE __stdcall GetCurrentThread(void); +extern HANDLE __stdcall GetCurrentProcess(void); +extern DWORD __stdcall SuspendThread(HANDLE h); + +#define UNREFERENCED_PARAMETER(u) (void)(u) + +/* end of standard definitions */ + +#if defined(__GNUC__) +#define NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE +#endif + +extern DWORD trucmuche(DWORD*); +extern DWORD stack_walk_bottom(void); diff --git a/dlls/dbghelp/tests/debuggee1.c b/dlls/dbghelp/tests/debuggee1.c new file mode 100644 index 00000000000..e73f36759e2 --- /dev/null +++ b/dlls/dbghelp/tests/debuggee1.c @@ -0,0 +1,64 @@ +#include "debuggee.h" + +inline DWORD verify1(HANDLE ht) +{ + if (ht == (HANDLE)1) return 15; + return SuspendThread(ht); +} + +inline DWORD verify2(HANDLE ht) +{ + if (ht == (HANDLE)2) return 16; + if (ht) return verify1(ht); + return 0; +} + +inline DWORD verify3(HANDLE ht) +{ + if (ht == (HANDLE)3) return 17; + if (ht) return verify2(ht); + return 0; +} + +#ifdef INLINE_OFF +#pragma auto_inline(off) +#endif +NOINLINE DWORD stack_walk_bottom(void) +{ + return verify3(GetCurrentThread()); +} +#ifdef INLINE_OFF +#pragma auto_inline(on) +#endif + +struct foobar +{ + char ch; + char* array[12]; + unsigned bf1 : 3, bf2 : 7, bf3 : 2; + unsigned u; +}; + +static struct foobar myfoobar; + +/* this complicated function serves mainly to fool the compiler + * for keeping it inside the debug information + * not 100% bullet proof + */ +NOINLINE unsigned function_AA(struct foobar* fb, DWORD64 base) +{ + DWORD other = (DWORD)base; +scaramouche: + other = (other * 57) + 127 * ++fb->ch + fb->u * (fb->bf1 += 2); + if ((other = trucmuche(&other)) != 0) goto scaramouche; + return ((other * base) & (1UL << 18)) != 0; +} + +int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + return function_AA(&myfoobar, nCmdShow ? 0 : 123) + stack_walk_bottom(); +} diff --git a/dlls/dbghelp/tests/debuggee2.c b/dlls/dbghelp/tests/debuggee2.c new file mode 100644 index 00000000000..e4d53a38c0e --- /dev/null +++ b/dlls/dbghelp/tests/debuggee2.c @@ -0,0 +1,7 @@ +#include "debuggee.h" + +unsigned mysdff = 12; +DWORD trucmuche(DWORD* a) +{ + return 0 * *a; +}
This manifest will hold target (compiler, cpu, 32/64 exec...) related information
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 34 +++++++++++++++++++++++++++ dlls/dbghelp/tests/debuggee.h | 7 +++++ dlls/dbghelp/tests/debuggee1.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 123989442bf..4e8907ac26b 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -21,6 +21,9 @@ #include "dbghelp.h" #include "wine/test.h"
+#define DEBUGGEE_NODEFINE +#include "debuggee.h" + struct debuggee { const char* name; /* name of main module */ @@ -29,6 +32,12 @@ struct debuggee HANDLE hThread; /* either new thread calling stack_walk_thread, or main thread */ DWORD64 base; DWORD64 size; + unsigned char* manifest; + /* 0 : version (1) + 1 : sizeof foobar + 2 : for each field of foobar (ch, array, bf1, bf2, fb3, u), 3 values + 20 | offset, size, bit position (255 if not a bitfield) + */ };
#if defined(__i386__) || defined(__x86_64__) @@ -167,6 +176,9 @@ static BOOL start_process(struct debuggee* dbg, const char* other) { DWORD count; BOOL ret; + char si_buf[sizeof(SYMBOL_INFO) + 200]; + SYMBOL_INFO *si = (SYMBOL_INFO *)si_buf; + SIZE_T nread;
memset(dbg, 0, sizeof(*dbg)); if (other) @@ -226,6 +238,27 @@ static BOOL start_process(struct debuggee* dbg, const char* other) { /* force the main module */ find_main_module_cb(dbg->name, (DWORD_PTR)&start_process, dbg); + ok(build_manifest(), "Couldn't build debuggee manifest\n"); + } + + si->SizeOfStruct = sizeof(*si); + si->MaxNameLen = 200; + ret = SymFromName(dbg->hProcess, "debuggee_manifest", si); + + if (!ret) + { + skip("Couldn't get debug information out of %s: %u\n", dbg->name, GetLastError()); + return FALSE; + } + if ((dbg->manifest = HeapAlloc(GetProcessHeap(), 0, si->Size)) == NULL || + si->Size != DEBUGGEE_MANIFEST_SIZE || + !ReadProcessMemory(dbg->hProcess, (void*)(DWORD_PTR)si->Address, dbg->manifest, si->Size, &nread) || + nread != si->Size || + dbg->manifest[0] != DEBUGGEE_MANIFEST_VERSION) + { + skip("Couldn't access the debuggee manifest %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, dbg->manifest); + return FALSE; }
return TRUE; @@ -244,6 +277,7 @@ static void close_process(const struct debuggee* dbg) CloseHandle(dbg->hProcess); CloseHandle(dbg->hThread); } + HeapFree(GetProcessHeap(), 0, dbg->manifest); }
START_TEST(dbghelp) diff --git a/dlls/dbghelp/tests/debuggee.h b/dlls/dbghelp/tests/debuggee.h index 9e181f1ba17..239a5085ae7 100644 --- a/dlls/dbghelp/tests/debuggee.h +++ b/dlls/dbghelp/tests/debuggee.h @@ -1,3 +1,4 @@ +#ifndef DEBUGGEE_NODEFINE /* avoid including standard headers, just to keep debug information as lean as possible */ typedef void* HANDLE; typedef unsigned long DWORD; @@ -10,6 +11,7 @@ extern DWORD __stdcall SuspendThread(HANDLE h); #define UNREFERENCED_PARAMETER(u) (void)(u)
/* end of standard definitions */ +#endif
#if defined(__GNUC__) #define NOINLINE __attribute__((noinline)) @@ -21,3 +23,8 @@ extern DWORD __stdcall SuspendThread(HANDLE h);
extern DWORD trucmuche(DWORD*); extern DWORD stack_walk_bottom(void); + +#define DEBUGGEE_MANIFEST_VERSION 1 +#define DEBUGGEE_MANIFEST_SIZE 20 + +extern DWORD build_manifest(void); diff --git a/dlls/dbghelp/tests/debuggee1.c b/dlls/dbghelp/tests/debuggee1.c index e73f36759e2..8a8f613eddb 100644 --- a/dlls/dbghelp/tests/debuggee1.c +++ b/dlls/dbghelp/tests/debuggee1.c @@ -54,11 +54,62 @@ scaramouche: return ((other * base) & (1UL << 18)) != 0; }
+unsigned char debuggee_manifest[DEBUGGEE_MANIFEST_SIZE]; + +#define FIELD_OFFSET(s,f) ((unsigned char)((char*)(&((struct s*)0)->f)-(char*)0)) + +DWORD build_manifest(void) +{ + unsigned i = 0; + + myfoobar.bf1 = 1; + myfoobar.bf2 = 1; + myfoobar.bf3 = 1; + + if (FIELD_OFFSET(foobar, array) + sizeof(myfoobar.array) + sizeof(unsigned) == FIELD_OFFSET(foobar, u) && + ((unsigned*)&myfoobar)[(FIELD_OFFSET(foobar, array) + sizeof(myfoobar.array)) / sizeof(unsigned)] == 0x409u) + { + debuggee_manifest[i++] = DEBUGGEE_MANIFEST_VERSION; + debuggee_manifest[i++] = sizeof(myfoobar); + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, ch); + debuggee_manifest[i++] = sizeof(myfoobar.ch); + debuggee_manifest[i++] = 255u; + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, array); + debuggee_manifest[i++] = sizeof(myfoobar.array); + debuggee_manifest[i++] = 255u; + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, array) + sizeof(myfoobar.array); + debuggee_manifest[i++] = sizeof(unsigned); + debuggee_manifest[i++] = 0; + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, array) + sizeof(myfoobar.array); + debuggee_manifest[i++] = sizeof(unsigned); + debuggee_manifest[i++] = 3; + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, array) + sizeof(myfoobar.array); + debuggee_manifest[i++] = sizeof(unsigned); + debuggee_manifest[i++] = 10; + + debuggee_manifest[i++] = FIELD_OFFSET(foobar, u); + debuggee_manifest[i++] = sizeof(myfoobar.u); + debuggee_manifest[i++] = 255u; + + if (i != sizeof(debuggee_manifest)) + debuggee_manifest[0] = 0; + } + else /* unsupported alignment or bitfield disposition */ + debuggee_manifest[0] = 0; + return debuggee_manifest[0]; +} + int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine);
+ build_manifest(); return function_AA(&myfoobar, nCmdShow ? 0 : 123) + stack_walk_bottom(); }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 4e8907ac26b..be3418b9ff5 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -40,6 +40,8 @@ struct debuggee */ };
+extern DWORD stack_walk_bottom(void); + #if defined(__i386__) || defined(__x86_64__)
static DWORD CALLBACK stack_walk_thread(void *arg) @@ -56,7 +58,7 @@ static void test_stack_walk(const struct debuggee* dbg) STACKFRAME64 frame = {{0}}, frame0; BOOL found_our_frame = FALSE; DWORD machine; - DWORD64 disp; + DWORD64 disp, stack_walk_thread_addr; CONTEXT ctx; BOOL ret;
@@ -102,24 +104,31 @@ static void test_stack_walk(const struct debuggee* dbg) ok(frame.AddrReturn.Offset && frame.AddrReturn.Offset != frame.AddrPC.Offset, "got bad return address %s\n", wine_dbgstr_longlong(frame.AddrReturn.Offset));
+ if (dbg->external_process) + { + si->SizeOfStruct = sizeof(*si); + si->MaxNameLen = 200; + ret = SymFromName(dbg->hProcess, "stack_walk_bottom", si); + ok(ret, "SymFromName failed\n"); + stack_walk_thread_addr = si->Address; + } + else + stack_walk_thread_addr = (DWORD_PTR)&stack_walk_thread; while (frame.AddrReturn.Offset) { - char *addr; - ret = StackWalk64(machine, dbg->hProcess, dbg->hThread, &frame, &ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); ok(ret, "StackWalk64() failed: %u\n", GetLastError());
- addr = (void *)(DWORD_PTR)frame.AddrPC.Offset; - - if (!found_our_frame && addr > (char *)stack_walk_thread && addr < (char *)stack_walk_thread + 0x100) + if (!found_our_frame && frame.AddrPC.Offset > stack_walk_thread_addr && frame.AddrPC.Offset < stack_walk_thread_addr + 0x100) { found_our_frame = TRUE;
si->SizeOfStruct = sizeof(SYMBOL_INFO); si->MaxNameLen = 200; if (SymFromAddr(dbg->hProcess, frame.AddrPC.Offset, &disp, si)) - ok(!strcmp(si->Name, "stack_walk_thread"), "got wrong name %s\n", si->Name); + ok(dbg->external_process ? !strcmp(si->Name, "stack_walk_bottom") : !strcmp(si->Name, "stack_walk_thread"), + "got wrong name %s\n", si->Name); } }
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 318 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+), 1 deletion(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index be3418b9ff5..b43acf2dda9 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -16,9 +16,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <stdarg.h> + #include "windef.h" +#include "winbase.h" +#include "winnls.h" #include "verrsrc.h" #include "dbghelp.h" +#include "cvconst.h" #include "wine/test.h"
#define DEBUGGEE_NODEFINE @@ -147,6 +152,317 @@ static void test_stack_walk(const struct debuggee* dbg)
#endif /* __i386__ || __x86_64__ */
+static BOOL endswithW(const WCHAR* in, const WCHAR* with) +{ + SIZE_T inlen = lstrlenW(in); + SIZE_T withlen = lstrlenW(with); + + if (inlen < withlen) return FALSE; + return _wcsnicmp(in + inlen - withlen, with, withlen) == 0; +} + +static BOOL isobjfile(const char* str, WCHAR* name) +{ + DWORD sz = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + WCHAR* nameW; + BOOL ret = FALSE; + if ((nameW = HeapAlloc(GetProcessHeap(), 0, (sz + 4) * sizeof(WCHAR))) != NULL) + { + MultiByteToWideChar(CP_ACP, 0, str, -1, nameW, sz); + nameW[sz - 1] = '.'; + nameW[sz + 0] = 'o'; + nameW[sz + 1] = '\0'; + ret = endswithW(name, nameW); + if (!ret) + { + nameW[sz + 1] = 'b'; + nameW[sz + 2] = 'j'; + nameW[sz + 3] = '\0'; + ret = endswithW(name, nameW); + } + HeapFree(GetProcessHeap(), 0, nameW); + } + return ret; +} + +/* When looking at a typedef (like DWORD), compilers & debug formats differ: + * - some use the type of the typedef + * - some others use the target of the typedef (especially, when it's a well defined + * type for the debug format) + * Cope with this by removing all typedef:s from the debug info to get to the + * target type. + */ +static DWORD untypedef(const struct debuggee* dbg, DWORD type) +{ + DWORD tag; + BOOL ret = TRUE; + + while (ret && + SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag) && + tag == SymTagTypedef) + { + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + } + return type; +} + +static TI_FINDCHILDREN_PARAMS* retrieve_children(const struct debuggee* dbg, DWORD id) +{ + DWORD count; + BOOL ret; + + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, id, TI_GET_CHILDRENCOUNT, &count); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + + if (ret) + { + TI_FINDCHILDREN_PARAMS* tfp; + + tfp = HeapAlloc(GetProcessHeap(), 0, sizeof(*tfp) + count * sizeof(tfp->ChildId[0])); + if (tfp) + { + tfp->Count = count; + tfp->Start = 0; + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, id, TI_FINDCHILDREN, tfp); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) return tfp; + HeapFree(GetProcessHeap(), 0, tfp); + } + } + return NULL; +} + +static void test_symbols(const struct debuggee* dbg) +{ + /* we inspect (with dbghelp) all those local variables & function parameters + * so check out the code below when changing those variables + */ + char si_buf[sizeof(SYMBOL_INFO) + 200]; + SYMBOL_INFO* si = (SYMBOL_INFO*)si_buf; + BOOL ret; + DWORD type, tag, bt, kind; + ULONG64 len; + WCHAR* name; + TI_FINDCHILDREN_PARAMS* tfp; + + memset(si, 0, sizeof(*si)); + si->SizeOfStruct = sizeof(SYMBOL_INFO); + si->MaxNameLen = 200; + + ret = SymFromName(dbg->hProcess, "function_AA", si); + ok(ret, "SymFromName failed: %u\n", GetLastError()); + ok(si->NameLen == 11, "Wrong name len %u\n", si->NameLen); + ok(!strcmp(si->Name, "function_AA"), "Wrong name %s\n", si->Name); + ok(si->Size, "Should have a size\n"); + ok(si->ModBase == dbg->base, "Wrong module base: expecting 0x%s but got 0x%s\n", + wine_dbgstr_longlong(dbg->base), wine_dbgstr_longlong(si->ModBase)); + // FIXME on W10, we get 0 in Flags... + ok(si->Tag == SymTagFunction, "Wrong tag %u\n", si->Tag); + + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_TYPEID, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(type == si->TypeIndex, "wrong typeid %u (expecting %u)\n", type, si->TypeIndex); + + /* checking return type in signature */ + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->TypeIndex, TI_GET_TYPEID, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagBaseType, "wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + todo_wine + ok(!ret, "SymGetTypeInfo should fail\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_BASETYPE, &bt); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(bt == btUInt, "Wrong base-type %u\n", bt); + + /* checking return parameters's type in signature */ + tfp = retrieve_children(dbg, si->TypeIndex); + if (tfp) + { + ok(tfp->Count == 2, "Wrong number of parameters' type\n"); + + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[0], TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagFunctionArgType, "wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[0], TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + ok(!ret, "SymGetTypeInfo should fail\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagPointerType, "Wrong base-type %u\n", bt); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagUDT, "wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) + { + ok(!lstrcmpW(name, L"foobar"), "UDT name is %ls\n", name); + HeapFree(GetProcessHeap(), 0, name); + } + + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[1], TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagFunctionArgType, "wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[1], TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + type = untypedef(dbg, type); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + todo_wine + ok(!ret, "SymGetTypeInfo should fail\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_BASETYPE, &bt); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(bt == btUInt, "Wrong base-type %u\n", bt); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_LENGTH, &len); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(len == sizeof(DWORD64), "Wrong length %su (expecting %u)\n", + wine_dbgstr_longlong(len), sizeof(DWORD64)); + + HeapFree(GetProcessHeap(), 0, tfp); + } + + /* Checking children (params, local variables) */ + tfp = retrieve_children(dbg, si->Index); + if (tfp) + { + DWORD i, j; + static struct + { + const WCHAR* name; + SIZE_T size; + enum DataKind kind; + enum DataKind other_kind; /* appears with CL.EXE /O2 (but not with CL.EXE; maybe a bug?) */ + } locpmts[] = + { + // we assume we have same size on this exec and children process + {L"base", sizeof(DWORD64), DataIsParam, DataIsLocal}, + {L"other", sizeof(DWORD), DataIsLocal, DataIsLocal}, + }; + BOOL labelfound = FALSE; + + /* 4 made of: 2 parameters, one local, one label */ + todo_wine_if(sizeof(void*)==4) + ok(tfp->Count >= 4, "Wrong number of parameters+local variables' type %u\n", tfp->Count); + + /* there are other children than parameters / local variables, so need to lookup */ + for (j = 0; j < ARRAYSIZE(locpmts); ++j) + { + BOOL found = FALSE; + for (i = 0; i < tfp->Count; ++i) + { + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + switch (tag) + { + case SymTagData: /* the parameters and local variables */ + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_SYMNAME, &name); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) + { + if (!lstrcmpW(name, locpmts[j].name)) + { + found = TRUE; + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo in #%u failed: %u\n", j, GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_LENGTH, &len); + ok(ret, "SymGetTypeInfo in #%u failed: %u\n", j, GetLastError()); + ok(len == locpmts[j].size, "Local variable/parameter %ls's size is wrong 0x%s (expecting 0x%s)\n", + name, wine_dbgstr_longlong(len), wine_dbgstr_longlong(locpmts[j].size)); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_OFFSET, &len); + ok(ret, "SymGetTypeInfo in #%u failed: %u\n", j, GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_DATAKIND, &kind); + ok(ret, "SymGetTypeInfo in #%u failed: %u\n", j, GetLastError()); + ok((enum DataKind)kind == locpmts[j].kind || (enum DataKind)kind == locpmts[j].other_kind, + "Local variable/parameter %ls's kind is wrong %u (expecting %u)\n", name, kind, locpmts[j].kind); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_LEXICALPARENT, &type); + ok(ret, "SymGetTypeInfo in #%u failed: %u\n", j, GetLastError()); + ok(type == si->Index, "wrong lexical parent %u\n", type); + } + HeapFree(GetProcessHeap(), 0, name); + } + break; + case SymTagLabel: /* labels inside the function */ + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, tfp->ChildId[i], TI_GET_SYMNAME, &name); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) + { + labelfound |= endswithW(name, L"scaramouche"); /* CL.EXE prepends a '$' to the name of the label */ + HeapFree(GetProcessHeap(), 0, name); + } + break; + default: + break; + } + } + if (!found) todo_wine + ok(found, "Couldn't find local variable/parameter %ls\n", locpmts[j].name); + } + ok(labelfound, "Couldn't find the label scaramouche\n"); + HeapFree(GetProcessHeap(), 0, tfp); + } + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_ADDRESS, &len); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(dbg->base <= si->Address && si->Address < dbg->base + dbg->size, "Wrong address\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_LEXICALPARENT, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagCompiland, "Wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + todo_wine + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) + { + todo_wine + ok(isobjfile("debuggee1", name), "Wrong compiland name %ls\n", name); + HeapFree(GetProcessHeap(), 0, name); + } + + memset(si, 0, sizeof(*si)); + si->SizeOfStruct = sizeof(SYMBOL_INFO); + si->MaxNameLen = 200; + + ret = SymFromName(dbg->hProcess, "myfoobar", si); + ok(ret, "SymFromName failed: %u\n", GetLastError()); + ok(si->NameLen == 8, "Wrong name len %u\n", si->NameLen); + ok(!strcmp(si->Name, "myfoobar"), "Wrong name %s\n", si->Name); + ok(si->Size == dbg->manifest[1], "Wrong size %u\n", si->Size); + ok(si->ModBase == dbg->base, "Wrong module base: expecting 0x%s but got 0x%s\n", + wine_dbgstr_longlong(dbg->base), wine_dbgstr_longlong(si->ModBase)); + // FIXME on W10, we get 0 in Flags... + ok(dbg->base <= si->Address && si->Address < dbg->base + dbg->size, "Wrong address\n"); + ok(si->Tag == SymTagData, "Wrong tag %u\n", si->Tag); + + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_ADDRESS, &len); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(dbg->base <= si->Address && si->Address < dbg->base + dbg->size, "Wrong address\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_TYPE, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(type == si->TypeIndex, "Wrong type\n"); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->TypeIndex, TI_GET_LENGTH, &len); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(len == dbg->manifest[1], "Wrong size 0x%s\n", wine_dbgstr_longlong(len)); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, si->Index, TI_GET_LEXICALPARENT, &type); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMTAG, &tag); + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + ok(tag == SymTagCompiland, "Wrong tag %u\n", tag); + ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); + todo_wine + ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); + if (ret) + { + todo_wine + ok(isobjfile("debuggee1", name), "Wrong compiland name %ls\n", name); + HeapFree(GetProcessHeap(), 0, name); + } +} + static BOOL CALLBACK find_main_module_cb(PCSTR name, DWORD64 base, PVOID in_user) { struct debuggee* dbg = in_user; @@ -297,7 +613,7 @@ START_TEST(dbghelp) if (start_process(&dbg, other)) { test_stack_walk(&dbg); - + test_symbols(&dbg); close_process(&dbg); } }
Note that most of UNIX debug formats store the source filename, whereas the PDB format stores the object filename (and returns it in SymGetTypeInfo)
As of today, dbghelp stores either the object or the source filename of a compiland, depending on the debug format used.
There's not enough data (for example in dwarf) to reconstruct the real object filename, so I'd rather let native dbghelp return a source filename instead of an object filename.
dbghelp's tests have been adjusted accordingly.
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/tests/dbghelp.c | 20 ++++++++++++-------- dlls/dbghelp/type.c | 3 ++- 2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index b43acf2dda9..141b1bdadd8 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -168,17 +168,25 @@ static BOOL isobjfile(const char* str, WCHAR* name) BOOL ret = FALSE; if ((nameW = HeapAlloc(GetProcessHeap(), 0, (sz + 4) * sizeof(WCHAR))) != NULL) { + /* native dbghelp (incorrectly) returns source filename instead of object filename here */ MultiByteToWideChar(CP_ACP, 0, str, -1, nameW, sz); nameW[sz - 1] = '.'; - nameW[sz + 0] = 'o'; + nameW[sz + 0] = 'c'; nameW[sz + 1] = '\0'; ret = endswithW(name, nameW); if (!ret) { - nameW[sz + 1] = 'b'; - nameW[sz + 2] = 'j'; - nameW[sz + 3] = '\0'; + nameW[sz - 1] = '.'; + nameW[sz + 0] = 'o'; + nameW[sz + 1] = '\0'; ret = endswithW(name, nameW); + if (!ret) + { + nameW[sz + 1] = 'b'; + nameW[sz + 2] = 'j'; + nameW[sz + 3] = '\0'; + ret = endswithW(name, nameW); + } } HeapFree(GetProcessHeap(), 0, nameW); } @@ -414,11 +422,9 @@ static void test_symbols(const struct debuggee* dbg) ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); ok(tag == SymTagCompiland, "Wrong tag %u\n", tag); ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); - todo_wine ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); if (ret) { - todo_wine ok(isobjfile("debuggee1", name), "Wrong compiland name %ls\n", name); HeapFree(GetProcessHeap(), 0, name); } @@ -453,11 +459,9 @@ static void test_symbols(const struct debuggee* dbg) ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); ok(tag == SymTagCompiland, "Wrong tag %u\n", tag); ret = SymGetTypeInfo(dbg->hProcess, dbg->base, type, TI_GET_SYMNAME, &name); - todo_wine ok(ret, "SymGetTypeInfo failed: %u\n", GetLastError()); if (ret) { - todo_wine ok(isobjfile("debuggee1", name), "Wrong compiland name %ls\n", name); HeapFree(GetProcessHeap(), 0, name); } diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index 374b69aeb08..e6d0ad3e927 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -761,7 +761,8 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
case TI_GET_SYMNAME: { - const char* name = symt_get_name(type); + const char* name = (type->tag == SymTagCompiland) ? + source_get(module, ((const struct symt_compiland*)type)->source) : symt_get_name(type); if (!name) return FALSE; len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); X(WCHAR*) = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
Don't recompute the location when we need to store a location block for later recomputation.
It had also the bad side effect of letting the location to be absolute, which wasn't expected at all.
Signed-off-by: Eric Pouech eric.pouech@gmail.com
--- dlls/dbghelp/dwarf.c | 1 - dlls/dbghelp/tests/dbghelp.c | 2 -- 2 files changed, 3 deletions(-)
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 53274c4f597..a4f426ca6a0 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -930,7 +930,6 @@ static BOOL dwarf2_compute_location_attr(dwarf2_parse_context_t* ctx, *ptr = xloc.u.block.size; memcpy(ptr + 1, xloc.u.block.ptr, xloc.u.block.size); loc->offset = (ULONG_PTR)ptr; - compute_location(ctx->module, &lctx, loc, NULL, frame); } } return TRUE; diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 141b1bdadd8..b73ee020374 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -354,7 +354,6 @@ static void test_symbols(const struct debuggee* dbg) BOOL labelfound = FALSE;
/* 4 made of: 2 parameters, one local, one label */ - todo_wine_if(sizeof(void*)==4) ok(tfp->Count >= 4, "Wrong number of parameters+local variables' type %u\n", tfp->Count);
/* there are other children than parameters / local variables, so need to lookup */ @@ -407,7 +406,6 @@ static void test_symbols(const struct debuggee* dbg) break; } } - if (!found) todo_wine ok(found, "Couldn't find local variable/parameter %ls\n", locpmts[j].name); } ok(labelfound, "Couldn't find the label scaramouche\n");