1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Test for x64 RtlCaptureContext
5 * COPYRIGHT: Copyright 2022 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8 #include <rtltests.h>
9
10 VOID
11 RtlCaptureContextWrapper(
12 _Inout_ PCONTEXT InOutContext,
13 _Out_ PCONTEXT CapturedContext);
14
START_TEST(RtlCaptureContext)15 START_TEST(RtlCaptureContext)
16 {
17 CONTEXT OriginalContext, InOutContext, CapturedContext;
18 SIZE_T Index, MaxIndex;
19 PUSHORT Buffer;
20
21 /* Initialize a pattern */
22 MaxIndex = sizeof(OriginalContext) / sizeof(USHORT);
23 Buffer = (PUSHORT)&OriginalContext;
24 for (Index = 0; Index < MaxIndex; Index++)
25 {
26 Buffer[Index] = Index;
27 }
28
29 /* Set all valid bits in EFlags */
30 OriginalContext.EFlags = 0xE7F;
31
32 /* Set up a valid floating point state */
33 OriginalContext.FltSave.ControlWord = 0x27f;
34 OriginalContext.FltSave.StatusWord = 0x1234;
35 OriginalContext.FltSave.TagWord = 0xab;
36 OriginalContext.FltSave.Reserved1 = 0x75;
37 OriginalContext.FltSave.MxCsr = 0x1f80; // Valid Mask is 2FFFF
38 OriginalContext.FltSave.MxCsr_Mask = 0xabcde;
39
40 /* Set up a unique MxCsr. This one will overwrite FltSave.MxCsr */
41 OriginalContext.MxCsr = 0xffff; // Valid Mask is 0xFFFF
42
43 /* Copy the original buffer */
44 InOutContext = OriginalContext;
45
46 /* Fill the output buffer with bogus */
47 RtlFillMemory(&CapturedContext, sizeof(CapturedContext), 0xCC);
48
49 /* Call the wrapper function */
50 RtlCaptureContextWrapper(&InOutContext, &CapturedContext);
51
52 /* These fields are not changed */
53 ok_eq_hex64(CapturedContext.P1Home, 0xccccccccccccccccULL);
54 ok_eq_hex64(CapturedContext.P2Home, 0xccccccccccccccccULL);
55 ok_eq_hex64(CapturedContext.P3Home, 0xccccccccccccccccULL);
56 ok_eq_hex64(CapturedContext.P4Home, 0xccccccccccccccccULL);
57 ok_eq_hex64(CapturedContext.P5Home, 0xccccccccccccccccULL);
58 ok_eq_hex64(CapturedContext.P6Home, 0xccccccccccccccccULL);
59 ok_eq_hex64(CapturedContext.Dr0, 0xccccccccccccccccULL);
60 ok_eq_hex64(CapturedContext.Dr1, 0xccccccccccccccccULL);
61 ok_eq_hex64(CapturedContext.Dr2, 0xccccccccccccccccULL);
62 ok_eq_hex64(CapturedContext.Dr3, 0xccccccccccccccccULL);
63 ok_eq_hex64(CapturedContext.Dr6, 0xccccccccccccccccULL);
64 ok_eq_hex64(CapturedContext.Dr7, 0xccccccccccccccccULL);
65 ok_eq_hex64(CapturedContext.VectorControl, 0xccccccccccccccccULL);
66 ok_eq_hex64(CapturedContext.DebugControl, 0xccccccccccccccccULL);
67 ok_eq_hex64(CapturedContext.LastBranchToRip, 0xccccccccccccccccULL);
68 ok_eq_hex64(CapturedContext.LastBranchFromRip, 0xccccccccccccccccULL);
69 ok_eq_hex64(CapturedContext.LastExceptionToRip, 0xccccccccccccccccULL);
70 ok_eq_hex64(CapturedContext.LastExceptionFromRip, 0xccccccccccccccccULL);
71 for (Index = 0; Index < ARRAYSIZE(CapturedContext.FltSave.Reserved4); Index++)
72 {
73 ok_eq_hex64(CapturedContext.FltSave.Reserved4[Index], 0xcc);
74 }
75 for (Index = 0; Index < ARRAYSIZE(CapturedContext.VectorRegister); Index++)
76 {
77 ok_eq_hex64(CapturedContext.VectorRegister[Index].Low, 0xccccccccccccccccULL);
78 ok_eq_hex64(CapturedContext.VectorRegister[Index].High, 0xccccccccccccccccULL);
79 }
80
81 /* ContextFlags is set */
82 ok_eq_hex(CapturedContext.ContextFlags, CONTEXT_FULL | CONTEXT_SEGMENTS);
83
84 /* These vallues are as passed in */
85 ok_eq_hex(CapturedContext.MxCsr, OriginalContext.MxCsr);
86 ok_eq_hex64(CapturedContext.Rax, OriginalContext.Rax);
87 ok_eq_hex64(CapturedContext.Rcx, (ULONG64)&CapturedContext);
88 ok_eq_hex64(CapturedContext.Rdx, OriginalContext.Rdx);
89 ok_eq_hex64(CapturedContext.Rbx, OriginalContext.Rbx);
90 ok_eq_hex64(CapturedContext.Rbp, OriginalContext.Rbp);
91 ok_eq_hex64(CapturedContext.Rsi, OriginalContext.Rsi);
92 ok_eq_hex64(CapturedContext.Rdi, OriginalContext.Rdi);
93 ok_eq_hex64(CapturedContext.R8, OriginalContext.R8);
94 ok_eq_hex64(CapturedContext.R9, OriginalContext.R9);
95 ok_eq_hex64(CapturedContext.R10, OriginalContext.R10);
96 ok_eq_hex64(CapturedContext.R11, OriginalContext.R11);
97 ok_eq_hex64(CapturedContext.R12, OriginalContext.R12);
98 ok_eq_hex64(CapturedContext.R13, OriginalContext.R13);
99 ok_eq_hex64(CapturedContext.R14, OriginalContext.R14);
100 ok_eq_hex64(CapturedContext.R15, OriginalContext.R15);
101
102 ok_eq_xmm(CapturedContext.Xmm0, OriginalContext.Xmm0);
103 ok_eq_xmm(CapturedContext.Xmm1, OriginalContext.Xmm1);
104 ok_eq_xmm(CapturedContext.Xmm2, OriginalContext.Xmm2);
105 ok_eq_xmm(CapturedContext.Xmm3, OriginalContext.Xmm3);
106 ok_eq_xmm(CapturedContext.Xmm4, OriginalContext.Xmm4);
107 ok_eq_xmm(CapturedContext.Xmm5, OriginalContext.Xmm5);
108 ok_eq_xmm(CapturedContext.Xmm6, OriginalContext.Xmm6);
109 ok_eq_xmm(CapturedContext.Xmm7, OriginalContext.Xmm7);
110 ok_eq_xmm(CapturedContext.Xmm8, OriginalContext.Xmm8);
111 ok_eq_xmm(CapturedContext.Xmm9, OriginalContext.Xmm9);
112 ok_eq_xmm(CapturedContext.Xmm10, OriginalContext.Xmm10);
113 ok_eq_xmm(CapturedContext.Xmm11, OriginalContext.Xmm11);
114 ok_eq_xmm(CapturedContext.Xmm12, OriginalContext.Xmm12);
115 ok_eq_xmm(CapturedContext.Xmm13, OriginalContext.Xmm13);
116 ok_eq_xmm(CapturedContext.Xmm14, OriginalContext.Xmm14);
117 ok_eq_xmm(CapturedContext.Xmm15, OriginalContext.Xmm15);
118
119 /* Some EFlags fields are cleared */
120 ok_eq_hex64(CapturedContext.EFlags, OriginalContext.EFlags & ~0x28);
121
122 #ifndef KMT_KERNEL_MODE // User mode
123 ok_eq_hex(CapturedContext.FltSave.ControlWord, 0x27f);
124 ok_eq_hex(CapturedContext.FltSave.StatusWord, OriginalContext.FltSave.StatusWord);
125 ok_eq_hex(CapturedContext.FltSave.TagWord, OriginalContext.FltSave.TagWord);
126 ok_eq_hex(CapturedContext.FltSave.Reserved1, 0x00);
127 ok_eq_hex(CapturedContext.FltSave.MxCsr_Mask, 0xffff);
128 ok_eq_hex(CapturedContext.FltSave.ErrorOpcode, 0x00000083);
129 ok_eq_hex(CapturedContext.FltSave.ErrorOffset, 0x00850084);
130 ok_eq_hex(CapturedContext.FltSave.ErrorSelector, 0x0086);
131 ok_eq_hex(CapturedContext.FltSave.Reserved2, 0x0000);
132 ok_eq_hex(CapturedContext.FltSave.DataOffset, 0x00890088);
133 ok_eq_hex(CapturedContext.FltSave.DataSelector, 0x008a);
134 ok_eq_hex(CapturedContext.FltSave.Reserved3, 0x0000);
135
136 /* We get the value from OriginalContext.MxCsr, since we set that later in the wrapper */
137 ok_eq_hex(CapturedContext.FltSave.MxCsr, OriginalContext.MxCsr);
138
139 /* Legacy floating point registers are truncated to 10 bytes */
140 ok_eq_hex64(CapturedContext.Legacy[0].Low, OriginalContext.Legacy[0].Low);
141 ok_eq_hex64(CapturedContext.Legacy[0].High, OriginalContext.Legacy[0].High & 0xFF);
142 ok_eq_hex64(CapturedContext.Legacy[1].Low, OriginalContext.Legacy[1].Low);
143 ok_eq_hex64(CapturedContext.Legacy[1].High, OriginalContext.Legacy[1].High & 0xFF);
144 ok_eq_hex64(CapturedContext.Legacy[2].Low, OriginalContext.Legacy[2].Low);
145 ok_eq_hex64(CapturedContext.Legacy[2].High, OriginalContext.Legacy[2].High & 0xFF);
146 ok_eq_hex64(CapturedContext.Legacy[3].Low, OriginalContext.Legacy[3].Low);
147 ok_eq_hex64(CapturedContext.Legacy[3].High, OriginalContext.Legacy[3].High & 0xFF);
148 ok_eq_hex64(CapturedContext.Legacy[4].Low, OriginalContext.Legacy[4].Low);
149 ok_eq_hex64(CapturedContext.Legacy[4].High, OriginalContext.Legacy[4].High & 0xFF);
150 ok_eq_hex64(CapturedContext.Legacy[5].Low, OriginalContext.Legacy[5].Low);
151 ok_eq_hex64(CapturedContext.Legacy[5].High, OriginalContext.Legacy[5].High & 0xFF);
152 ok_eq_hex64(CapturedContext.Legacy[6].Low, OriginalContext.Legacy[6].Low);
153 ok_eq_hex64(CapturedContext.Legacy[6].High, OriginalContext.Legacy[6].High & 0xFF);
154 ok_eq_hex64(CapturedContext.Legacy[7].Low, OriginalContext.Legacy[7].Low);
155 ok_eq_hex64(CapturedContext.Legacy[7].High, OriginalContext.Legacy[7].High & 0xFF);
156 #else
157 ok_eq_hex(CapturedContext.FltSave.ControlWord, 0xcccc);
158 ok_eq_hex(CapturedContext.FltSave.StatusWord, 0xcccc);
159 ok_eq_hex(CapturedContext.FltSave.TagWord, 0xcc);
160 ok_eq_hex(CapturedContext.FltSave.Reserved1, 0xcc);
161 ok_eq_hex(CapturedContext.FltSave.MxCsr_Mask, 0xcccccccc);
162 ok_eq_hex(CapturedContext.FltSave.ErrorOpcode, 0xcccc);
163 ok_eq_hex(CapturedContext.FltSave.ErrorOffset, 0xcccccccc);
164 ok_eq_hex(CapturedContext.FltSave.ErrorSelector, 0xcccc);
165 ok_eq_hex(CapturedContext.FltSave.Reserved2, 0xcccc);
166 ok_eq_hex(CapturedContext.FltSave.DataOffset, 0xcccccccc);
167 ok_eq_hex(CapturedContext.FltSave.DataSelector, 0xcccc);
168 ok_eq_hex(CapturedContext.FltSave.Reserved3, 0xcccc);
169
170 /* We get the value from OriginalContext.MxCsr, since we set that later in the wrapper */
171 ok_eq_hex(CapturedContext.FltSave.MxCsr, 0xcccccccc);
172
173 /* Legacy floating point registers are truncated to 10 bytes */
174 ok_eq_hex64(CapturedContext.Legacy[0].Low, 0xcccccccccccccccc);
175 ok_eq_hex64(CapturedContext.Legacy[0].High, 0xcccccccccccccccc);
176 ok_eq_hex64(CapturedContext.Legacy[1].Low, 0xcccccccccccccccc);
177 ok_eq_hex64(CapturedContext.Legacy[1].High, 0xcccccccccccccccc);
178 ok_eq_hex64(CapturedContext.Legacy[2].Low, 0xcccccccccccccccc);
179 ok_eq_hex64(CapturedContext.Legacy[2].High, 0xcccccccccccccccc);
180 ok_eq_hex64(CapturedContext.Legacy[3].Low, 0xcccccccccccccccc);
181 ok_eq_hex64(CapturedContext.Legacy[3].High, 0xcccccccccccccccc);
182 ok_eq_hex64(CapturedContext.Legacy[4].Low, 0xcccccccccccccccc);
183 ok_eq_hex64(CapturedContext.Legacy[4].High, 0xcccccccccccccccc);
184 ok_eq_hex64(CapturedContext.Legacy[5].Low, 0xcccccccccccccccc);
185 ok_eq_hex64(CapturedContext.Legacy[5].High, 0xcccccccccccccccc);
186 ok_eq_hex64(CapturedContext.Legacy[6].Low, 0xcccccccccccccccc);
187 ok_eq_hex64(CapturedContext.Legacy[6].High, 0xcccccccccccccccc);
188 ok_eq_hex64(CapturedContext.Legacy[7].Low, 0xcccccccccccccccc);
189 ok_eq_hex64(CapturedContext.Legacy[7].High, 0xcccccccccccccccc);
190 #endif
191
192 /* We don't pass in segments, but expect the default values */
193 ok_eq_hex(CapturedContext.SegDs, 0x2b);
194 ok_eq_hex(CapturedContext.SegEs, 0x2b);
195 ok_eq_hex(CapturedContext.SegFs, 0x53);
196 ok_eq_hex(CapturedContext.SegGs, 0x2b);
197 #ifndef KMT_KERNEL_MODE // User mode
198 ok_eq_hex(CapturedContext.SegCs, 0x33);
199 ok_eq_hex(CapturedContext.SegSs, 0x2b);
200 #else
201 ok_eq_hex(CapturedContext.SegCs, 0x10);
202 ok_eq_hex(CapturedContext.SegSs, 0x18);
203 #endif
204
205 /* For Rsp and Rip we get the expected value back from the asm wrapper */
206 ok_eq_hex64(CapturedContext.Rsp, InOutContext.Rsp);
207 ok_eq_hex64(CapturedContext.Rip, InOutContext.Rip);
208
209 /* Check that these registers are not modified by RtlCaptureContext */
210 ok_eq_xmm(InOutContext.Xmm0, OriginalContext.Xmm0);
211 ok_eq_xmm(InOutContext.Xmm1, OriginalContext.Xmm1);
212 ok_eq_xmm(InOutContext.Xmm2, OriginalContext.Xmm2);
213 ok_eq_xmm(InOutContext.Xmm3, OriginalContext.Xmm3);
214 ok_eq_xmm(InOutContext.Xmm4, OriginalContext.Xmm4);
215 ok_eq_xmm(InOutContext.Xmm5, OriginalContext.Xmm5);
216 ok_eq_xmm(InOutContext.Xmm6, OriginalContext.Xmm6);
217 ok_eq_xmm(InOutContext.Xmm7, OriginalContext.Xmm7);
218 ok_eq_xmm(InOutContext.Xmm8, OriginalContext.Xmm8);
219 ok_eq_xmm(InOutContext.Xmm9, OriginalContext.Xmm9);
220 ok_eq_xmm(InOutContext.Xmm10, OriginalContext.Xmm10);
221 ok_eq_xmm(InOutContext.Xmm11, OriginalContext.Xmm11);
222 ok_eq_xmm(InOutContext.Xmm12, OriginalContext.Xmm12);
223 ok_eq_xmm(InOutContext.Xmm13, OriginalContext.Xmm13);
224 ok_eq_xmm(InOutContext.Xmm14, OriginalContext.Xmm14);
225 ok_eq_xmm(InOutContext.Xmm15, OriginalContext.Xmm15);
226 ok_eq_hex64(InOutContext.Rdx, OriginalContext.Rdx);
227 ok_eq_hex64(InOutContext.Rbx, OriginalContext.Rbx);
228 ok_eq_hex64(InOutContext.Rbp, OriginalContext.Rbp);
229 ok_eq_hex64(InOutContext.Rsi, OriginalContext.Rsi);
230 ok_eq_hex64(InOutContext.Rdi, OriginalContext.Rdi);
231 ok_eq_hex64(InOutContext.R8, OriginalContext.R8);
232 ok_eq_hex64(InOutContext.R9, OriginalContext.R9);
233 ok_eq_hex64(InOutContext.R10, OriginalContext.R10);
234 ok_eq_hex64(InOutContext.R11, OriginalContext.R11);
235 ok_eq_hex64(InOutContext.R12, OriginalContext.R12);
236 ok_eq_hex64(InOutContext.R13, OriginalContext.R13);
237 ok_eq_hex64(InOutContext.R14, OriginalContext.R14);
238 ok_eq_hex64(InOutContext.R15, OriginalContext.R15);
239
240 /* Eflags is changed (parity is flaky) */
241 #ifndef KMT_KERNEL_MODE // User mode
242 ok_eq_hex64(InOutContext.EFlags & ~0x04, OriginalContext.EFlags & 0x782);
243 #endif
244
245 /* MxCsr is the one we passed in in OriginalContext.MxCsr */
246 ok_eq_hex(InOutContext.MxCsr, OriginalContext.MxCsr);
247 ok_eq_hex(InOutContext.FltSave.MxCsr, OriginalContext.MxCsr);
248
249 /* Rcx still points to the captured context */
250 ok_eq_hex64(InOutContext.Rcx, (ULONG64)&CapturedContext);
251
252 /* Rax contains eflags */
253 ok_eq_hex64(InOutContext.Rax, CapturedContext.EFlags);
254
255 /* Second run with minimal EFLags/MxCsr */
256 OriginalContext.EFlags = 0x200;
257 OriginalContext.MxCsr = 0x0000;
258 InOutContext = OriginalContext;
259 RtlFillMemory(&CapturedContext, sizeof(CapturedContext), 0xCC);
260 RtlCaptureContextWrapper(&InOutContext, &CapturedContext);
261
262 /* Captured Eflags has reserved flag set (which is always 1) */
263 ok_eq_hex64(CapturedContext.EFlags, OriginalContext.EFlags | 2);
264
265 /* Parity flag is flaky */
266 #ifndef KMT_KERNEL_MODE // User mode
267 ok_eq_hex64(InOutContext.EFlags & ~4, CapturedContext.EFlags);
268 #endif
269
270 /* MxCsr is captured/returned as passed in */
271 ok_eq_hex64(InOutContext.MxCsr, CapturedContext.MxCsr);
272 ok_eq_hex64(CapturedContext.MxCsr, OriginalContext.MxCsr);
273 }
274