Reactos
1/*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Runtime library stack trace test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8#define KMT_EMULATE_KERNEL
9#include <kmt_test.h>
10
11static PVOID ReturnAddresses[4];
12
13static
14VOID
15TestStackWalk3(VOID);
16
17DECLSPEC_NOINLINE
18static
19VOID
20TestStackWalk4(VOID)
21{
22 PVOID Frames[5];
23 ULONG Ret;
24 ULONG Hash;
25 ULONG ExpectedHash;
26 ULONG i;
27 const ULONG FunctionSizeGuess = 0x1000;
28 NTSTATUS ExceptionStatus = STATUS_SUCCESS;
29
30 ReturnAddresses[3] = _ReturnAddress();
31
32 Ret = RtlWalkFrameChain(NULL, 5, 0);
33 ok_eq_ulong(Ret, 0);
34
35 RtlFillMemory(Frames, sizeof(Frames), 0x55);
36 Ret = RtlWalkFrameChain(Frames, 0, 0);
37 ok_eq_ulong(Ret, 0);
38 ok_eq_pointer(Frames[0], (PVOID)(ULONG_PTR)0x5555555555555555);
39
40 RtlFillMemory(Frames, sizeof(Frames), 0x55);
41 Ret = RtlWalkFrameChain(Frames, 5, 0);
42 ok_eq_ulong(Ret, 5);
43 ok((ULONG_PTR)Frames[0] > (ULONG_PTR)TestStackWalk4, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
44 ok((ULONG_PTR)Frames[0] < (ULONG_PTR)TestStackWalk4 + FunctionSizeGuess, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
45 ok_eq_pointer(Frames[1], ReturnAddresses[3]);
46 ok_eq_pointer(Frames[2], ReturnAddresses[2]);
47 ok_eq_pointer(Frames[3], ReturnAddresses[1]);
48 ok_eq_pointer(Frames[4], ReturnAddresses[0]);
49
50 RtlFillMemory(Frames, sizeof(Frames), 0x55);
51 Ret = RtlWalkFrameChain(Frames, 4, 0);
52 ok_eq_ulong(Ret, 4);
53 ok((ULONG_PTR)Frames[0] > (ULONG_PTR)TestStackWalk4, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
54 ok((ULONG_PTR)Frames[0] < (ULONG_PTR)TestStackWalk4 + FunctionSizeGuess, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
55 ok_eq_pointer(Frames[1], ReturnAddresses[3]);
56 ok_eq_pointer(Frames[2], ReturnAddresses[2]);
57 ok_eq_pointer(Frames[3], ReturnAddresses[1]);
58 ok_eq_pointer(Frames[4], (PVOID)(ULONG_PTR)0x5555555555555555);
59
60 _SEH2_TRY
61 {
62 RtlCaptureStackBackTrace(0, 5, NULL, NULL);
63 }
64 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
65 {
66 ExceptionStatus = _SEH2_GetExceptionCode();
67 }
68 _SEH2_END;
69 if (GetNTVersion() == _WIN32_WINNT_WS03)
70 ok_eq_hex(ExceptionStatus, STATUS_ACCESS_VIOLATION);
71 else
72 ok_eq_hex(ExceptionStatus, STATUS_SUCCESS);
73
74 RtlFillMemory(Frames, sizeof(Frames), 0x55);
75 Hash = 0x55555555;
76 Ret = RtlCaptureStackBackTrace(0, 0, Frames, &Hash);
77 ok_eq_ulong(Ret, 0);
78 ok_eq_hex(Hash, 0x55555555);
79 ok_eq_pointer(Frames[0], (PVOID)(ULONG_PTR)0x5555555555555555);
80
81 RtlFillMemory(Frames, sizeof(Frames), 0x55);
82 Hash = 0x55555555;
83 Ret = RtlCaptureStackBackTrace(0, 1, Frames, NULL);
84 ok_eq_ulong(Ret, 1);
85 ok((ULONG_PTR)Frames[0] > (ULONG_PTR)TestStackWalk4, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
86 ok((ULONG_PTR)Frames[0] < (ULONG_PTR)TestStackWalk4 + FunctionSizeGuess, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
87 ok_eq_pointer(Frames[1], (PVOID)(ULONG_PTR)0x5555555555555555);
88
89 RtlFillMemory(Frames, sizeof(Frames), 0x55);
90 Ret = RtlCaptureStackBackTrace(0, 5, Frames, &Hash);
91 ok_eq_ulong(Ret, 5);
92 ExpectedHash = 0;
93 for (i = 0; i < 5; i++)
94 ExpectedHash += (ULONG)(ULONG_PTR)Frames[i];
95 ok_eq_hex(Hash, ExpectedHash);
96 ok((ULONG_PTR)Frames[0] > (ULONG_PTR)TestStackWalk4, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
97 ok((ULONG_PTR)Frames[0] < (ULONG_PTR)TestStackWalk4 + FunctionSizeGuess, "Frame is %p, function is %p\n", Frames[0], TestStackWalk4);
98 ok_eq_pointer(Frames[1], ReturnAddresses[3]);
99 ok_eq_pointer(Frames[2], ReturnAddresses[2]);
100 ok_eq_pointer(Frames[3], ReturnAddresses[1]);
101 ok_eq_pointer(Frames[4], ReturnAddresses[0]);
102
103 RtlFillMemory(Frames, sizeof(Frames), 0x55);
104 Ret = RtlCaptureStackBackTrace(1, 4, Frames, &Hash);
105 ok_eq_ulong(Ret, 4);
106 ExpectedHash = 0;
107 for (i = 0; i < 4; i++)
108 ExpectedHash += (ULONG)(ULONG_PTR)Frames[i];
109 ok_eq_hex(Hash, ExpectedHash);
110 ok_eq_pointer(Frames[0], ReturnAddresses[3]);
111 ok_eq_pointer(Frames[1], ReturnAddresses[2]);
112 ok_eq_pointer(Frames[2], ReturnAddresses[1]);
113 ok_eq_pointer(Frames[3], ReturnAddresses[0]);
114 ok_eq_pointer(Frames[4], (PVOID)(ULONG_PTR)0x5555555555555555);
115}
116
117DECLSPEC_NOINLINE
118static
119VOID
120TestStackWalk3(VOID)
121{
122 ReturnAddresses[2] = _ReturnAddress();
123 TestStackWalk4();
124}
125
126DECLSPEC_NOINLINE
127static
128VOID
129TestStackWalk2(VOID)
130{
131 ReturnAddresses[1] = _ReturnAddress();
132 TestStackWalk3();
133}
134
135DECLSPEC_NOINLINE
136static
137VOID
138TestStackWalk1(VOID)
139{
140 ReturnAddresses[0] = _ReturnAddress();
141 TestStackWalk2();
142}
143
144#ifdef _M_AMD64
145NTSYSAPI
146PVOID
147NTAPI
148RtlPcToFileHeader(
149 _In_ PVOID PcValue,
150 _Out_ PVOID *BaseOfImage);
151
152extern char __ImageBase;
153
154DECLSPEC_NOINLINE
155static
156VOID
157TestRtlPcToFileHeader(VOID)
158{
159 PVOID ImageBase, Result;
160 PTEB Teb;
161 PPEB Peb;
162
163 /* First test a function from this image */
164 Result = RtlPcToFileHeader(&TestRtlPcToFileHeader, &ImageBase);
165 ok_eq_pointer(Result, ImageBase);
166 ok_eq_pointer(ImageBase, &__ImageBase);
167
168#ifdef NTOS_MODE_USER
169 Teb = NtCurrentTeb();
170#else
171 Teb = PsGetCurrentThreadTeb();
172#endif
173 ok(Teb != NULL, "Teb is NULL!\n");
174 if (Teb == NULL)
175 {
176 return;
177 }
178
179 _SEH2_TRY
180 {
181 Peb = Teb->ProcessEnvironmentBlock;
182 ok(Peb != NULL, "Peb is NULL!\n");
183 if (Peb == NULL)
184 {
185 return;
186 }
187
188 /* Test an address somewhere within the main image of the current process */
189 Result = RtlPcToFileHeader((PUCHAR)Peb->ImageBaseAddress + 0x1000, &ImageBase);
190 ok_eq_pointer(Result, ImageBase);
191#ifdef NTOS_MODE_USER
192 ok_eq_pointer(ImageBase, Peb->ImageBaseAddress);
193#else
194 ok_eq_pointer(ImageBase, NULL);
195#endif
196 }
197 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
198 {
199 ok(FALSE, "Got an exception!\n");
200 }
201 _SEH2_END
202}
203#endif // _M_AMD64
204
205START_TEST(RtlStack)
206{
207 TestStackWalk1();
208#ifdef _M_AMD64
209 TestRtlPcToFileHeader();
210#endif // _M_AMD64
211}