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 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