1 /* 2 * Copyright 2018 Zebediah Figura 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "windef.h" 20 #include "verrsrc.h" 21 #include "dbghelp.h" 22 #include "wine/test.h" 23 24 #if defined(__i386__) || defined(__x86_64__) 25 26 static DWORD CALLBACK stack_walk_thread(void *arg) 27 { 28 DWORD count = SuspendThread(GetCurrentThread()); 29 ok(!count, "got %d\n", count); 30 return 0; 31 } 32 33 static void test_stack_walk(void) 34 { 35 char si_buf[sizeof(SYMBOL_INFO) + 200]; 36 SYMBOL_INFO *si = (SYMBOL_INFO *)si_buf; 37 STACKFRAME64 frame = {{0}}, frame0; 38 BOOL found_our_frame = FALSE; 39 DWORD machine; 40 HANDLE thread; 41 DWORD64 disp; 42 CONTEXT ctx; 43 DWORD count; 44 BOOL ret; 45 46 thread = CreateThread(NULL, 0, stack_walk_thread, NULL, 0, NULL); 47 48 /* wait for the thread to suspend itself */ 49 do 50 { 51 Sleep(50); 52 count = SuspendThread(thread); 53 ResumeThread(thread); 54 } 55 while (!count); 56 57 ctx.ContextFlags = CONTEXT_CONTROL; 58 ret = GetThreadContext(thread, &ctx); 59 ok(ret, "got error %u\n", ret); 60 61 frame.AddrPC.Mode = AddrModeFlat; 62 frame.AddrFrame.Mode = AddrModeFlat; 63 frame.AddrStack.Mode = AddrModeFlat; 64 65 #ifdef __i386__ 66 machine = IMAGE_FILE_MACHINE_I386; 67 68 frame.AddrPC.Segment = ctx.SegCs; 69 frame.AddrPC.Offset = ctx.Eip; 70 frame.AddrFrame.Segment = ctx.SegSs; 71 frame.AddrFrame.Offset = ctx.Ebp; 72 frame.AddrStack.Segment = ctx.SegSs; 73 frame.AddrStack.Offset = ctx.Esp; 74 #elif defined(__x86_64__) 75 machine = IMAGE_FILE_MACHINE_AMD64; 76 77 frame.AddrPC.Segment = ctx.SegCs; 78 frame.AddrPC.Offset = ctx.Rip; 79 frame.AddrFrame.Segment = ctx.SegSs; 80 frame.AddrFrame.Offset = ctx.Rbp; 81 frame.AddrStack.Segment = ctx.SegSs; 82 frame.AddrStack.Offset = ctx.Rsp; 83 #endif 84 frame0 = frame; 85 86 /* first invocation just calculates the return address */ 87 ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, 88 SymFunctionTableAccess64, SymGetModuleBase64, NULL); 89 ok(ret, "StackWalk64() failed: %u\n", GetLastError()); 90 ok(frame.AddrPC.Offset == frame0.AddrPC.Offset, "expected %s, got %s\n", 91 wine_dbgstr_longlong(frame0.AddrPC.Offset), 92 wine_dbgstr_longlong(frame.AddrPC.Offset)); 93 ok(frame.AddrStack.Offset == frame0.AddrStack.Offset, "expected %s, got %s\n", 94 wine_dbgstr_longlong(frame0.AddrStack.Offset), 95 wine_dbgstr_longlong(frame.AddrStack.Offset)); 96 ok(frame.AddrReturn.Offset && frame.AddrReturn.Offset != frame.AddrPC.Offset, 97 "got bad return address %s\n", wine_dbgstr_longlong(frame.AddrReturn.Offset)); 98 99 while (frame.AddrReturn.Offset) 100 { 101 char *addr; 102 103 ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, 104 SymFunctionTableAccess64, SymGetModuleBase64, NULL); 105 ok(ret, "StackWalk64() failed: %u\n", GetLastError()); 106 107 addr = (void *)(DWORD_PTR)frame.AddrPC.Offset; 108 109 if (addr > (char *)stack_walk_thread && addr < (char *)stack_walk_thread + 0x100) 110 { 111 found_our_frame = TRUE; 112 113 si->SizeOfStruct = sizeof(SYMBOL_INFO); 114 si->MaxNameLen = 200; 115 if (SymFromAddr(GetCurrentProcess(), frame.AddrPC.Offset, &disp, si)) 116 ok(!strcmp(si->Name, "stack_walk_thread"), "got wrong name %s\n", si->Name); 117 } 118 } 119 120 ret = StackWalk64(machine, GetCurrentProcess(), thread, &frame, &ctx, NULL, 121 SymFunctionTableAccess64, SymGetModuleBase64, NULL); 122 ok(!ret, "StackWalk64() should have failed\n"); 123 124 ok(found_our_frame, "didn't find stack_walk_thread frame\n"); 125 } 126 127 #else /* __i386__ || __x86_64__ */ 128 129 static void test_stack_walk(void) 130 { 131 } 132 133 #endif /* __i386__ || __x86_64__ */ 134 135 START_TEST(dbghelp) 136 { 137 BOOL ret = SymInitialize(GetCurrentProcess(), NULL, TRUE); 138 ok(ret, "got error %u\n", GetLastError()); 139 140 test_stack_walk(); 141 142 ret = SymCleanup(GetCurrentProcess()); 143 ok(ret, "got error %u\n", GetLastError()); 144 } 145