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