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 
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 #else
136     ok_eq_hex(CapturedContext.FltSave.ControlWord, 0xcccc);
137     ok_eq_hex(CapturedContext.FltSave.StatusWord, 0xcccc);
138     ok_eq_hex(CapturedContext.FltSave.TagWord, 0xcc);
139     ok_eq_hex(CapturedContext.FltSave.Reserved1, 0xcc);
140     ok_eq_hex(CapturedContext.FltSave.MxCsr_Mask, 0xcccccccc);
141     ok_eq_hex(CapturedContext.FltSave.ErrorOpcode, 0xcccc);
142     ok_eq_hex(CapturedContext.FltSave.ErrorOffset, 0xcccccccc);
143     ok_eq_hex(CapturedContext.FltSave.ErrorSelector, 0xcccc);
144     ok_eq_hex(CapturedContext.FltSave.Reserved2, 0xcccc);
145     ok_eq_hex(CapturedContext.FltSave.DataOffset, 0xcccccccc);
146     ok_eq_hex(CapturedContext.FltSave.DataSelector, 0xcccc);
147     ok_eq_hex(CapturedContext.FltSave.Reserved3, 0xcccc);
148 #endif
149 
150     /* We get the value from OriginalContext.MxCsr, since we set that later in the wrapper */
151     ok_eq_hex(CapturedContext.FltSave.MxCsr, OriginalContext.MxCsr);
152 
153     /* Legacy floating point registers are truncated to 10 bytes */
154     ok_eq_hex64(CapturedContext.Legacy[0].Low, OriginalContext.Legacy[0].Low);
155     ok_eq_hex64(CapturedContext.Legacy[0].High, OriginalContext.Legacy[0].High & 0xFF);
156     ok_eq_hex64(CapturedContext.Legacy[1].Low, OriginalContext.Legacy[1].Low);
157     ok_eq_hex64(CapturedContext.Legacy[1].High, OriginalContext.Legacy[1].High & 0xFF);
158     ok_eq_hex64(CapturedContext.Legacy[2].Low, OriginalContext.Legacy[2].Low);
159     ok_eq_hex64(CapturedContext.Legacy[2].High, OriginalContext.Legacy[2].High & 0xFF);
160     ok_eq_hex64(CapturedContext.Legacy[3].Low, OriginalContext.Legacy[3].Low);
161     ok_eq_hex64(CapturedContext.Legacy[3].High, OriginalContext.Legacy[3].High & 0xFF);
162     ok_eq_hex64(CapturedContext.Legacy[4].Low, OriginalContext.Legacy[4].Low);
163     ok_eq_hex64(CapturedContext.Legacy[4].High, OriginalContext.Legacy[4].High & 0xFF);
164     ok_eq_hex64(CapturedContext.Legacy[5].Low, OriginalContext.Legacy[5].Low);
165     ok_eq_hex64(CapturedContext.Legacy[5].High, OriginalContext.Legacy[5].High & 0xFF);
166     ok_eq_hex64(CapturedContext.Legacy[6].Low, OriginalContext.Legacy[6].Low);
167     ok_eq_hex64(CapturedContext.Legacy[6].High, OriginalContext.Legacy[6].High & 0xFF);
168     ok_eq_hex64(CapturedContext.Legacy[7].Low, OriginalContext.Legacy[7].Low);
169     ok_eq_hex64(CapturedContext.Legacy[7].High, OriginalContext.Legacy[7].High & 0xFF);
170 
171     /* We don't pass in segments, but expect the default values */
172     ok_eq_hex(CapturedContext.SegCs, 0x33);
173     ok_eq_hex(CapturedContext.SegDs, 0x2b);
174     ok_eq_hex(CapturedContext.SegEs, 0x2b);
175     ok_eq_hex(CapturedContext.SegFs, 0x53);
176     ok_eq_hex(CapturedContext.SegGs, 0x2b);
177     ok_eq_hex(CapturedContext.SegSs, 0x2b);
178 
179     /* For Rsp and Rip we get the expected value back from the asm wrapper */
180     ok_eq_hex64(CapturedContext.Rsp, InOutContext.Rsp);
181     ok_eq_hex64(CapturedContext.Rip, InOutContext.Rip);
182 
183     /* Check that these registers are not modified by RtlCaptureContext */
184     ok_eq_xmm(InOutContext.Xmm0, OriginalContext.Xmm0);
185     ok_eq_xmm(InOutContext.Xmm1, OriginalContext.Xmm1);
186     ok_eq_xmm(InOutContext.Xmm2, OriginalContext.Xmm2);
187     ok_eq_xmm(InOutContext.Xmm3, OriginalContext.Xmm3);
188     ok_eq_xmm(InOutContext.Xmm4, OriginalContext.Xmm4);
189     ok_eq_xmm(InOutContext.Xmm5, OriginalContext.Xmm5);
190     ok_eq_xmm(InOutContext.Xmm6, OriginalContext.Xmm6);
191     ok_eq_xmm(InOutContext.Xmm7, OriginalContext.Xmm7);
192     ok_eq_xmm(InOutContext.Xmm8, OriginalContext.Xmm8);
193     ok_eq_xmm(InOutContext.Xmm9, OriginalContext.Xmm9);
194     ok_eq_xmm(InOutContext.Xmm10, OriginalContext.Xmm10);
195     ok_eq_xmm(InOutContext.Xmm11, OriginalContext.Xmm11);
196     ok_eq_xmm(InOutContext.Xmm12, OriginalContext.Xmm12);
197     ok_eq_xmm(InOutContext.Xmm13, OriginalContext.Xmm13);
198     ok_eq_xmm(InOutContext.Xmm14, OriginalContext.Xmm14);
199     ok_eq_xmm(InOutContext.Xmm15, OriginalContext.Xmm15);
200     ok_eq_hex64(InOutContext.Rdx, OriginalContext.Rdx);
201     ok_eq_hex64(InOutContext.Rbx, OriginalContext.Rbx);
202     ok_eq_hex64(InOutContext.Rbp, OriginalContext.Rbp);
203     ok_eq_hex64(InOutContext.Rsi, OriginalContext.Rsi);
204     ok_eq_hex64(InOutContext.Rdi, OriginalContext.Rdi);
205     ok_eq_hex64(InOutContext.R8, OriginalContext.R8);
206     ok_eq_hex64(InOutContext.R9, OriginalContext.R9);
207     ok_eq_hex64(InOutContext.R10, OriginalContext.R10);
208     ok_eq_hex64(InOutContext.R11, OriginalContext.R11);
209     ok_eq_hex64(InOutContext.R12, OriginalContext.R12);
210     ok_eq_hex64(InOutContext.R13, OriginalContext.R13);
211     ok_eq_hex64(InOutContext.R14, OriginalContext.R14);
212     ok_eq_hex64(InOutContext.R15, OriginalContext.R15);
213 
214     /* Eflags is changed (parity is flaky) */
215     ok_eq_hex64(InOutContext.EFlags & ~0x04, OriginalContext.EFlags & 0x782);
216 
217     /* MxCsr is the one we passed in in OriginalContext.MxCsr */
218     ok_eq_hex(InOutContext.MxCsr, OriginalContext.MxCsr);
219     ok_eq_hex(InOutContext.FltSave.MxCsr, OriginalContext.MxCsr);
220 
221     /* Rcx still points to the captured context */
222     ok_eq_hex64(InOutContext.Rcx, (ULONG64)&CapturedContext);
223 
224     /* Rax contains eflags */
225     ok_eq_hex64(InOutContext.Rax, CapturedContext.EFlags);
226 
227     /* Second run with minimal EFLags/MxCsr */
228     OriginalContext.EFlags = 0x200;
229     OriginalContext.MxCsr = 0x0000;
230     InOutContext = OriginalContext;
231     RtlFillMemory(&CapturedContext, sizeof(CapturedContext), 0xCC);
232     RtlCaptureContextWrapper(&InOutContext, &CapturedContext);
233 
234     /* Captured Eflags has reserved flag set (which is always 1) */
235     ok_eq_hex64(CapturedContext.EFlags, OriginalContext.EFlags | 2);
236 
237     /* Parity flag is flaky */
238     ok_eq_hex64(InOutContext.EFlags & ~4, CapturedContext.EFlags);
239 
240     /* MxCsr is captured/returned as passed in */
241     ok_eq_hex64(InOutContext.MxCsr, CapturedContext.MxCsr);
242     ok_eq_hex64(CapturedContext.MxCsr, OriginalContext.MxCsr);
243 }
244