2 * Copyright 2018 Zebediah Figura
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.
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.
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
22 #include "wine/test.h"
24 #if defined(__i386__) || defined(__x86_64__)
26 static DWORD CALLBACK
stack_walk_thread(void *arg
)
28 DWORD count
= SuspendThread(GetCurrentThread());
29 ok(!count
, "got %d\n", count
);
33 static void test_stack_walk(void)
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
;
46 thread
= CreateThread(NULL
, 0, stack_walk_thread
, NULL
, 0, NULL
);
48 /* wait for the thread to suspend itself */
52 count
= SuspendThread(thread
);
57 ctx
.ContextFlags
= CONTEXT_CONTROL
;
58 ret
= GetThreadContext(thread
, &ctx
);
59 ok(ret
, "got error %u\n", ret
);
61 frame
.AddrPC
.Mode
= AddrModeFlat
;
62 frame
.AddrFrame
.Mode
= AddrModeFlat
;
63 frame
.AddrStack
.Mode
= AddrModeFlat
;
66 machine
= IMAGE_FILE_MACHINE_I386
;
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
;
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
;
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
));
99 while (frame
.AddrReturn
.Offset
)
103 ret
= StackWalk64(machine
, GetCurrentProcess(), thread
, &frame
, &ctx
, NULL
,
104 SymFunctionTableAccess64
, SymGetModuleBase64
, NULL
);
105 ok(ret
, "StackWalk64() failed: %u\n", GetLastError());
107 addr
= (void *)(DWORD_PTR
)frame
.AddrPC
.Offset
;
109 if (addr
> (char *)stack_walk_thread
&& addr
< (char *)stack_walk_thread
+ 0x100)
111 found_our_frame
= TRUE
;
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
);
120 ret
= StackWalk64(machine
, GetCurrentProcess(), thread
, &frame
, &ctx
, NULL
,
121 SymFunctionTableAccess64
, SymGetModuleBase64
, NULL
);
122 ok(!ret
, "StackWalk64() should have failed\n");
124 ok(found_our_frame
, "didn't find stack_walk_thread frame\n");
127 #else /* __i386__ || __x86_64__ */
129 static void test_stack_walk(void)
133 #endif /* __i386__ || __x86_64__ */
137 BOOL ret
= SymInitialize(GetCurrentProcess(), NULL
, TRUE
);
138 ok(ret
, "got error %u\n", GetLastError());
142 ret
= SymCleanup(GetCurrentProcess());
143 ok(ret
, "got error %u\n", GetLastError());