diff --git a/configure b/configure index 2ca572ddbfc..431d56d0738 100755 --- a/configure +++ b/configure @@ -18687,6 +18687,7 @@ wine_fn_config_makefile dlls/d3dxof/tests enable_tests wine_fn_config_makefile dlls/davclnt enable_davclnt wine_fn_config_makefile dlls/dbgeng enable_dbgeng wine_fn_config_makefile dlls/dbghelp enable_dbghelp +wine_fn_config_makefile dlls/dbghelp/tests enable_tests wine_fn_config_makefile dlls/dciman32 enable_dciman32 wine_fn_config_makefile dlls/ddeml.dll16 enable_win16 wine_fn_config_makefile dlls/ddraw enable_ddraw diff --git a/configure.ac b/configure.ac index d10acde146f..1db5a407fa7 100644 --- a/configure.ac +++ b/configure.ac @@ -3186,6 +3186,7 @@ WINE_CONFIG_MAKEFILE(dlls/d3dxof/tests) WINE_CONFIG_MAKEFILE(dlls/davclnt) WINE_CONFIG_MAKEFILE(dlls/dbgeng) WINE_CONFIG_MAKEFILE(dlls/dbghelp) +WINE_CONFIG_MAKEFILE(dlls/dbghelp/tests) WINE_CONFIG_MAKEFILE(dlls/dciman32) WINE_CONFIG_MAKEFILE(dlls/ddeml.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/ddraw) diff --git a/dlls/dbghelp/tests/Makefile.in b/dlls/dbghelp/tests/Makefile.in new file mode 100644 index 00000000000..31e5b01e8a8 --- /dev/null +++ b/dlls/dbghelp/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = dbghelp.dll +IMPORTS = dbghelp + +C_SRCS = \ + dbghelp.c diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c new file mode 100644 index 00000000000..1292b667032 --- /dev/null +++ b/dlls/dbghelp/tests/dbghelp.c @@ -0,0 +1,144 @@ +/* + * Copyright 2018 Zebediah Figura + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" +#include "verrsrc.h" +#include "dbghelp.h" +#include "wine/test.h" + +#if defined(__i386__) || defined(__x86_64__) + +DWORD CALLBACK stack_walk_thread(void *arg) +{ + DWORD count = SuspendThread(GetCurrentThread()); + ok(!count, "got %d\n", count); + return 0; +} + +static void test_stack_walk(void) +{ + 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); + ok(ret, "got error %u\n", ret); + + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + +#ifdef __i386__ + machine = IMAGE_FILE_MACHINE_I386; + + frame.AddrPC.Segment = ctx.SegCs; + frame.AddrPC.Offset = ctx.Eip; + frame.AddrFrame.Segment = ctx.SegSs; + frame.AddrFrame.Offset = ctx.Ebp; + frame.AddrStack.Segment = ctx.SegSs; + frame.AddrStack.Offset = ctx.Esp; +#elif defined(__x86_64__) + machine = IMAGE_FILE_MACHINE_AMD64; + + frame.AddrPC.Segment = ctx.SegCs; + frame.AddrPC.Offset = ctx.Rip; + frame.AddrFrame.Segment = ctx.SegSs; + frame.AddrFrame.Offset = ctx.Rbp; + frame.AddrStack.Segment = ctx.SegSs; + frame.AddrStack.Offset = ctx.Rsp; +#endif + frame0 = frame; + + /* first invocation just calculates the return address */ + ret = StackWalk64(machine, GetCurrentProcess(), thread, &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", + wine_dbgstr_longlong(frame0.AddrPC.Offset), + wine_dbgstr_longlong(frame.AddrPC.Offset)); + ok(frame.AddrStack.Offset == frame0.AddrStack.Offset, "expected %s, got %s\n", + wine_dbgstr_longlong(frame0.AddrStack.Offset), + wine_dbgstr_longlong(frame.AddrStack.Offset)); + ok(frame.AddrReturn.Offset && frame.AddrReturn.Offset != frame.AddrPC.Offset, + "got bad return address %s\n", wine_dbgstr_longlong(frame.AddrReturn.Offset)); + + while (frame.AddrReturn.Offset) + { + char *addr; + + ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL); + ok(ret, "StackWalk64() failed: %u\n", GetLastError()); + + addr = (void *)(DWORD_PTR)frame.AddrPC.Offset; + + if (addr > (char *)stack_walk_thread && addr < (char *)stack_walk_thread + 0x100) + { + found_our_frame = TRUE; + + si->SizeOfStruct = sizeof(SYMBOL_INFO); + si->MaxNameLen = 200; + if (SymFromAddr(GetCurrentProcess(), 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, + SymFunctionTableAccess64, SymGetModuleBase64, NULL); + ok(!ret, "StackWalk64() should have failed\n"); + + ok(found_our_frame, "didn't find stack_walk_thread frame\n"); +} + +#else /* __i386__ || __x86_64__ */ + +static void test_stack_walk(void) +{ +} + +#endif /* __i386__ || __x86_64__ */ + +START_TEST(dbghelp) +{ + BOOL ret = SymInitialize(GetCurrentProcess(), NULL, TRUE); + ok(ret, "got error %u\n", GetLastError()); + + test_stack_walk(); + + ret = SymCleanup(GetCurrentProcess()); + ok(ret, "got error %u\n", GetLastError()); +}