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 _M_IX86
14 #define NTC_SEGMENT_BITS (0xFFFF)
15 #define NTC_EFLAGS_BITS  (0x3C0CD5)
16 #endif
17 
18 void continuePoint(void);
19 
20 static jmp_buf jmpbuf;
21 static CONTEXT continueContext;
22 static unsigned int nRandBytes;
23 
24 static int initrand(void)
25 {
26     unsigned int nRandMax;
27     unsigned int nRandMaxBits;
28     time_t tLoc;
29 
30     nRandMax = RAND_MAX;
31     for(nRandMaxBits = 0; nRandMax != 0; nRandMax >>= 1, ++ nRandMaxBits);
32     nRandBytes = nRandMaxBits / CHAR_BIT;
33     //assert(nRandBytes != 0);
34     srand((unsigned)(time(&tLoc) & UINT_MAX));
35     return 1;
36 }
37 
38 static void randbytes(void * p, size_t n)
39 {
40     unsigned char * b;
41     size_t i;
42     int r = rand();
43 
44     b = (unsigned char *)p;
45     for(i = 0; i < n; ++ i)
46     {
47         if(i % nRandBytes == 0)
48         r = rand();
49         b[i] = (unsigned char)(r & UCHAR_MAX);
50         r >>= CHAR_BIT;
51     }
52 }
53 
54 static ULONG randULONG(void)
55 {
56     ULONG n;
57     randbytes(&n, sizeof(n));
58     return n;
59 }
60 
61 #ifdef _M_AMD64
62 static ULONG64 randULONG64(void)
63 {
64     return (ULONG64)randULONG() << 32 | randULONG();
65 }
66 #endif
67 
68 void check(CONTEXT * pContext)
69 {
70 #ifdef _M_IX86
71     ok(pContext->ContextFlags == CONTEXT_FULL,
72        "ContextFlags=0x%lx\n", pContext->ContextFlags);
73 
74     /* Random data segments */
75     ok((pContext->SegGs & NTC_SEGMENT_BITS) ==
76        (continueContext.SegGs & NTC_SEGMENT_BITS),
77        "SegGs=0x%lx / 0x%lx\n", pContext->SegGs, continueContext.SegGs);
78 
79     ok((pContext->SegFs & NTC_SEGMENT_BITS) ==
80        (continueContext.SegFs & NTC_SEGMENT_BITS),
81        "SegFs=0x%lx / 0x%lx\n", pContext->SegFs, continueContext.SegFs);
82 
83     ok((pContext->SegEs & NTC_SEGMENT_BITS) ==
84        (continueContext.SegEs & NTC_SEGMENT_BITS),
85        "SegEs=0x%lx / 0x%lx\n", pContext->SegEs, continueContext.SegEs);
86 
87     ok((pContext->SegDs & NTC_SEGMENT_BITS) ==
88        (continueContext.SegDs & NTC_SEGMENT_BITS),
89        "SegDs=0x%lx / 0x%lx\n", pContext->SegDs, continueContext.SegDs);
90 
91     /* Integer registers */
92     ok(pContext->Edi == continueContext.Edi,
93        "Edi: 0x%lx != 0x%lx\n", pContext->Edi, continueContext.Edi);
94     ok(pContext->Esi == continueContext.Esi,
95        "Esi: 0x%lx != 0x%lx\n", pContext->Esi, continueContext.Esi);
96     ok(pContext->Ebx == continueContext.Ebx,
97        "Ebx: 0x%lx != 0x%lx\n", pContext->Ebx, continueContext.Ebx);
98     ok(pContext->Edx == continueContext.Edx,
99        "Edx: 0x%lx != 0x%lx\n", pContext->Edx, continueContext.Edx);
100     ok(pContext->Ecx == continueContext.Ecx,
101        "Ecx: 0x%lx != 0x%lx\n", pContext->Ecx, continueContext.Ecx);
102     ok(pContext->Eax == continueContext.Eax,
103        "Eax: 0x%lx != 0x%lx\n", pContext->Eax, continueContext.Eax);
104 
105     /* Control registers and segments */
106     ok(pContext->Ebp == continueContext.Ebp,
107        "Ebp: 0x%lx != 0x%lx\n", pContext->Ebp, continueContext.Ebp);
108     ok(pContext->Eip == continueContext.Eip,
109        "Eip: 0x%lx != 0x%lx\n", pContext->Eip, continueContext.Eip);
110     ok(pContext->Esp == continueContext.Esp,
111        "Esp: 0x%lx != 0x%lx\n", pContext->Esp, continueContext.Esp);
112 
113     ok((pContext->SegCs & NTC_SEGMENT_BITS) ==
114        (continueContext.SegCs & NTC_SEGMENT_BITS),
115        "SegCs: 0x%lx != 0x%lx\n", pContext->SegCs, continueContext.SegCs);
116 
117     ok((pContext->EFlags & NTC_EFLAGS_BITS) ==
118        (continueContext.EFlags & NTC_EFLAGS_BITS),
119        "EFlags: 0x%lx != 0x%lx\n", pContext->EFlags, continueContext.EFlags);
120 
121     ok((pContext->SegSs & NTC_SEGMENT_BITS) ==
122        (continueContext.SegSs & NTC_SEGMENT_BITS),
123        "SegSs: 0x%lx != 0x%lx\n", pContext->SegSs, continueContext.SegSs);
124 #endif
125 
126     /* Return where we came from */
127     longjmp(jmpbuf, 1);
128 }
129 
130 START_TEST(NtContinue)
131 {
132 #ifdef __RUNTIME_CHECKS__
133     skip("This test breaks MSVC runtime checks!\n");
134     return;
135 #endif /* __RUNTIME_CHECKS__ */
136     initrand();
137 
138     /* First time */
139     if(setjmp(jmpbuf) == 0)
140     {
141         CONTEXT bogus;
142 
143         continueContext.ContextFlags = CONTEXT_FULL;
144         GetThreadContext(GetCurrentThread(), &continueContext);
145 
146 #ifdef _M_IX86
147         continueContext.ContextFlags = CONTEXT_FULL;
148 
149         /* Fill the integer registers with random values */
150         continueContext.Edi = randULONG();
151         continueContext.Esi = randULONG();
152         continueContext.Ebx = randULONG();
153         continueContext.Edx = randULONG();
154         continueContext.Ecx = randULONG();
155         continueContext.Eax = randULONG();
156         continueContext.Ebp = randULONG();
157 
158         /* Randomize all the allowed flags (determined experimentally with WinDbg) */
159         continueContext.EFlags = randULONG() & 0x3C0CD5;
160 
161         /* Randomize the stack pointer as much as possible */
162         continueContext.Esp = (ULONG)(((ULONG_PTR)&bogus) & 0xFFFFFFFF) +
163                               sizeof(bogus) - (randULONG() & 0xF) * 4;
164 
165         /* continuePoint() is implemented in assembler */
166         continueContext.Eip = (ULONG)((ULONG_PTR)continuePoint & 0xFFFFFFF);
167 
168         /* Can't do a lot about segments */
169 #elif defined(_M_AMD64)
170         continueContext.ContextFlags = CONTEXT_FULL;
171 
172         /* Fill the integer registers with random values */
173         continueContext.Rdi = randULONG64();
174         continueContext.Rsi = randULONG64();
175         continueContext.Rbx = randULONG64();
176         continueContext.Rdx = randULONG64();
177         continueContext.Rcx = randULONG64();
178         continueContext.Rax = randULONG64();
179         continueContext.Rbp = randULONG64();
180 
181         /* Randomize all the allowed flags (determined experimentally with WinDbg) */
182         continueContext.EFlags = randULONG64() & 0x3C0CD5;
183 
184         /* Randomize the stack pointer as much as possible */
185         continueContext.Rsp = (((ULONG_PTR)&bogus)) +
186             sizeof(bogus) - (randULONG() & 0xF) * 4;
187 
188         /* continuePoint() is implemented in assembler */
189         //continueContext.Rip = ((ULONG_PTR)continuePoint);
190         skip("NtContinue test does not yet work on x64.");
191         return;
192 #endif
193 
194         NtContinue(&continueContext, FALSE);
195         ok(0, "should never get here\n");
196     }
197 
198     /* Second time */
199     return;
200 }
201