1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for NtContinue
5  * PROGRAMMER:
6  */
7 
8 #include "precomp.h"
9 
10 #include <setjmp.h>
11 #include <time.h>
12 
13 #ifdef _MSC_VER
14 #pragma runtime_checks("s", off)
15 #endif
16 
17 #define ok_eq_print(value, expected, spec)  ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
18 #define ok_eq_hex(value, expected)          ok_eq_print(value, expected, "%lx")
19 #define ok_eq_hex64(value, expected)        ok_eq_print(value, expected, "%I64x")
20 #define ok_eq_xmm(value, expected)          ok((value).Low == (expected).Low, #value " = %I64x'%08I64x, expected %I64x'%08I64x\n", (value).Low, (value).High, (expected).Low, (expected).High)
21 
22 #ifdef _M_IX86
23 #define NTC_SEGMENT_BITS (0xFFFF)
24 #define NTC_EFLAGS_BITS  (0x3C0CD5)
25 #endif
26 
27 void continuePoint(void);
28 
29 static jmp_buf jmpbuf;
30 static CONTEXT continueContext;
31 static unsigned int nRandBytes;
32 
33 static int initrand(void)
34 {
35     unsigned int nRandMax;
36     unsigned int nRandMaxBits;
37     time_t tLoc;
38 
39     nRandMax = RAND_MAX;
40     for(nRandMaxBits = 0; nRandMax != 0; nRandMax >>= 1, ++ nRandMaxBits);
41     nRandBytes = nRandMaxBits / CHAR_BIT;
42     //assert(nRandBytes != 0);
43     srand((unsigned)(time(&tLoc) & UINT_MAX));
44     return 1;
45 }
46 
47 static void randbytes(void * p, size_t n)
48 {
49     unsigned char * b;
50     size_t i;
51     int r = rand();
52 
53     b = (unsigned char *)p;
54     for(i = 0; i < n; ++ i)
55     {
56         if(i % nRandBytes == 0)
57         r = rand();
58         b[i] = (unsigned char)(r & UCHAR_MAX);
59         r >>= CHAR_BIT;
60     }
61 }
62 
63 static ULONG randULONG(void)
64 {
65     ULONG n;
66     randbytes(&n, sizeof(n));
67     return n;
68 }
69 
70 #ifdef _M_AMD64
71 static ULONG64 randULONG64(void)
72 {
73     return (ULONG64)randULONG() << 32 | randULONG();
74 }
75 #endif
76 
77 void check(CONTEXT * pContext)
78 {
79 #ifdef _M_IX86
80     ok(pContext->ContextFlags == CONTEXT_FULL,
81        "ContextFlags=0x%lx\n", pContext->ContextFlags);
82 
83     /* Random data segments */
84     ok((pContext->SegGs & NTC_SEGMENT_BITS) ==
85        (continueContext.SegGs & NTC_SEGMENT_BITS),
86        "SegGs=0x%lx / 0x%lx\n", pContext->SegGs, continueContext.SegGs);
87 
88     ok((pContext->SegFs & NTC_SEGMENT_BITS) ==
89        (continueContext.SegFs & NTC_SEGMENT_BITS),
90        "SegFs=0x%lx / 0x%lx\n", pContext->SegFs, continueContext.SegFs);
91 
92     ok((pContext->SegEs & NTC_SEGMENT_BITS) ==
93        (continueContext.SegEs & NTC_SEGMENT_BITS),
94        "SegEs=0x%lx / 0x%lx\n", pContext->SegEs, continueContext.SegEs);
95 
96     ok((pContext->SegDs & NTC_SEGMENT_BITS) ==
97        (continueContext.SegDs & NTC_SEGMENT_BITS),
98        "SegDs=0x%lx / 0x%lx\n", pContext->SegDs, continueContext.SegDs);
99 
100     /* Integer registers */
101     ok(pContext->Edi == continueContext.Edi,
102        "Edi: 0x%lx != 0x%lx\n", pContext->Edi, continueContext.Edi);
103     ok(pContext->Esi == continueContext.Esi,
104        "Esi: 0x%lx != 0x%lx\n", pContext->Esi, continueContext.Esi);
105     ok(pContext->Ebx == continueContext.Ebx,
106        "Ebx: 0x%lx != 0x%lx\n", pContext->Ebx, continueContext.Ebx);
107     ok(pContext->Edx == continueContext.Edx,
108        "Edx: 0x%lx != 0x%lx\n", pContext->Edx, continueContext.Edx);
109     ok(pContext->Ecx == continueContext.Ecx,
110        "Ecx: 0x%lx != 0x%lx\n", pContext->Ecx, continueContext.Ecx);
111     ok(pContext->Eax == continueContext.Eax,
112        "Eax: 0x%lx != 0x%lx\n", pContext->Eax, continueContext.Eax);
113 
114     /* Control registers and segments */
115     ok(pContext->Ebp == continueContext.Ebp,
116        "Ebp: 0x%lx != 0x%lx\n", pContext->Ebp, continueContext.Ebp);
117     ok(pContext->Eip == continueContext.Eip,
118        "Eip: 0x%lx != 0x%lx\n", pContext->Eip, continueContext.Eip);
119     ok(pContext->Esp == continueContext.Esp,
120        "Esp: 0x%lx != 0x%lx\n", pContext->Esp, continueContext.Esp);
121 
122     ok((pContext->SegCs & NTC_SEGMENT_BITS) ==
123        (continueContext.SegCs & NTC_SEGMENT_BITS),
124        "SegCs: 0x%lx != 0x%lx\n", pContext->SegCs, continueContext.SegCs);
125 
126     ok((pContext->EFlags & NTC_EFLAGS_BITS) ==
127        (continueContext.EFlags & NTC_EFLAGS_BITS),
128        "EFlags: 0x%lx != 0x%lx\n", pContext->EFlags, continueContext.EFlags);
129 
130     ok((pContext->SegSs & NTC_SEGMENT_BITS) ==
131        (continueContext.SegSs & NTC_SEGMENT_BITS),
132        "SegSs: 0x%lx != 0x%lx\n", pContext->SegSs, continueContext.SegSs);
133 #else
134     ok_eq_hex64(pContext->ContextFlags, CONTEXT_FULL | CONTEXT_SEGMENTS);
135     ok_eq_hex(pContext->MxCsr, continueContext.MxCsr);
136     ok_eq_hex(pContext->SegCs, continueContext.SegCs);
137     ok_eq_hex(pContext->SegDs, 0x2B);
138     ok_eq_hex(pContext->SegEs, 0x2B);
139     ok_eq_hex(pContext->SegFs, 0x53);
140     ok_eq_hex(pContext->SegGs, 0x2B);
141     ok_eq_hex(pContext->SegSs, continueContext.SegSs);
142     ok_eq_hex(pContext->EFlags, (continueContext.EFlags & ~0x1C0000) | 0x202);
143 
144     ok_eq_hex64(pContext->Rax, continueContext.Rax);
145     ok_eq_hex64(pContext->Rdx, continueContext.Rdx);
146     ok_eq_hex64(pContext->Rbx, continueContext.Rbx);
147     ok_eq_hex64(pContext->Rsp, continueContext.Rsp);
148     ok_eq_hex64(pContext->Rbp, continueContext.Rbp);
149     ok_eq_hex64(pContext->Rsi, continueContext.Rsi);
150     ok_eq_hex64(pContext->Rdi, continueContext.Rdi);
151     ok_eq_hex64(pContext->R8, continueContext.R8);
152     ok_eq_hex64(pContext->R9, continueContext.R9);
153     ok_eq_hex64(pContext->R10, continueContext.R10);
154     ok_eq_hex64(pContext->R11, continueContext.R11);
155     ok_eq_hex64(pContext->R12, continueContext.R12);
156     ok_eq_hex64(pContext->R13, continueContext.R13);
157     ok_eq_hex64(pContext->R14, continueContext.R14);
158     ok_eq_hex64(pContext->R15, continueContext.R15);
159     ok_eq_xmm(pContext->Xmm0, continueContext.Xmm0);
160     ok_eq_xmm(pContext->Xmm1, continueContext.Xmm1);
161     ok_eq_xmm(pContext->Xmm2, continueContext.Xmm2);
162     ok_eq_xmm(pContext->Xmm3, continueContext.Xmm3);
163     ok_eq_xmm(pContext->Xmm4, continueContext.Xmm4);
164     ok_eq_xmm(pContext->Xmm5, continueContext.Xmm5);
165     ok_eq_xmm(pContext->Xmm6, continueContext.Xmm6);
166     ok_eq_xmm(pContext->Xmm7, continueContext.Xmm7);
167     ok_eq_xmm(pContext->Xmm8, continueContext.Xmm8);
168     ok_eq_xmm(pContext->Xmm9, continueContext.Xmm9);
169     ok_eq_xmm(pContext->Xmm10, continueContext.Xmm10);
170     ok_eq_xmm(pContext->Xmm11, continueContext.Xmm11);
171     ok_eq_xmm(pContext->Xmm12, continueContext.Xmm12);
172     ok_eq_xmm(pContext->Xmm13, continueContext.Xmm13);
173     ok_eq_xmm(pContext->Xmm14, continueContext.Xmm14);
174     ok_eq_xmm(pContext->Xmm15, continueContext.Xmm15);
175 
176     // Clear the frame register to prevent unwinding, which is broken
177     ((_JUMP_BUFFER*)&jmpbuf)->Frame = 0;
178 #endif
179 
180     /* Return where we came from */
181     longjmp(jmpbuf, 1);
182 }
183 
184 START_TEST(NtContinue)
185 {
186     initrand();
187 
188     RtlFillMemory(&continueContext, sizeof(continueContext), 0xBBBBBBBB);
189 
190     /* First time */
191     if(setjmp(jmpbuf) == 0)
192     {
193         CONTEXT bogus[2];
194 
195         RtlFillMemory(&bogus, sizeof(bogus), 0xCCCCCCCC);
196 
197         continueContext.ContextFlags = CONTEXT_FULL;
198         GetThreadContext(GetCurrentThread(), &continueContext);
199 
200 #ifdef _M_IX86
201         continueContext.ContextFlags = CONTEXT_FULL;
202 
203         /* Fill the integer registers with random values */
204         continueContext.Edi = randULONG();
205         continueContext.Esi = randULONG();
206         continueContext.Ebx = randULONG();
207         continueContext.Edx = randULONG();
208         continueContext.Ecx = randULONG();
209         continueContext.Eax = randULONG();
210         continueContext.Ebp = randULONG();
211 
212         /* Randomize all the allowed flags (determined experimentally with WinDbg) */
213         continueContext.EFlags = randULONG() & 0x3C0CD5;
214 
215         /* Randomize the stack pointer as much as possible */
216         continueContext.Esp = (ULONG)(((ULONG_PTR)&bogus) & 0xFFFFFFFF) +
217                               sizeof(bogus) - (randULONG() & 0xF) * 4;
218 
219         /* continuePoint() is implemented in assembler */
220         continueContext.Eip = (ULONG)((ULONG_PTR)continuePoint & 0xFFFFFFF);
221 
222         /* Can't do a lot about segments */
223 #elif defined(_M_AMD64)
224         continueContext.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
225 
226         /* Fill the integer registers with random values */
227         PULONG64 Registers = &continueContext.Rax;
228         for (ULONG i = 0; i < 16; i++)
229         {
230             Registers[i] = randULONG64();
231         }
232 
233         /* Fill the XMM registers with random values */
234         Registers = (PULONG64)&continueContext.Xmm0;
235         for (ULONG i = 0; i < 32; i++)
236         {
237             Registers[i] = randULONG64();
238         }
239 
240         continueContext.Dr0 = randULONG64() & 0xFFFF;
241         continueContext.Dr1 = randULONG64() & 0xFFFF;
242         continueContext.Dr2 = randULONG64() & 0xFFFF;
243         continueContext.Dr3 = randULONG64() & 0xFFFF;
244         continueContext.Dr6 = randULONG64() & 0xFFFF;
245         continueContext.Dr7 = randULONG64() & 0xFFFF;
246 
247         /* Randomize all the allowed flags (determined experimentally with WinDbg) */
248         continueContext.EFlags = randULONG64() & 0x3C0CD5;
249 
250         /* Randomize the stack pointer as much as possible */
251         continueContext.Rsp = (((ULONG_PTR)&bogus)) + (randULONG() & 0xF) * 16;
252         continueContext.Rsp = ALIGN_DOWN_BY(continueContext.Rsp, 16);
253 
254         /* continuePoint() is implemented in assembler */
255         continueContext.Rip = ((ULONG_PTR)continuePoint);
256 #endif
257 
258         NtContinue(&continueContext, FALSE);
259         ok(0, "should never get here\n");
260     }
261 
262     /* Second time */
263     return;
264 }
265