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