ReactOS  0.4.14-dev-342-gdc047f9
exception.c
Go to the documentation of this file.
1 /*
2  * Unit test suite for ntdll exceptions
3  *
4  * Copyright 2005 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #ifndef _WIN32_WINNT
25 #define _WIN32_WINNT 0x500 /* For NTSTATUS */
26 #endif
27 
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #define NONAMELESSUNION
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnt.h"
34 #include "winreg.h"
35 #include "winternl.h"
36 #ifdef __REACTOS__
37 #include <wine/exception.h>
38 #else
39 #include "excpt.h"
40 #endif
41 #include "wine/test.h"
42 
43 static void *code_mem;
44 
45 static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
46 static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
47 static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
48 static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
49 static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
50 static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
51 static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler);
52 static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
53 static ULONG (WINAPI *pRtlRemoveVectoredContinueHandler)(PVOID handler);
54 static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
55 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
56 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
57 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
58 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
59 static NTSTATUS (WINAPI *pNtClose)(HANDLE);
60 
61 #if defined(__x86_64__)
62 #ifndef __REACTOS__
63 typedef struct
64 {
65  ULONG Count;
66  struct
67  {
68  ULONG BeginAddress;
69  ULONG EndAddress;
70  ULONG HandlerAddress;
71  ULONG JumpTarget;
72  } ScopeRecord[1];
73 } SCOPE_TABLE;
74 
75 typedef struct
76 {
77  ULONG64 ControlPc;
78  ULONG64 ImageBase;
79  PRUNTIME_FUNCTION FunctionEntry;
81  ULONG64 TargetIp;
83  void* /*PEXCEPTION_ROUTINE*/ LanguageHandler;
84  PVOID HandlerData;
85  PUNWIND_HISTORY_TABLE HistoryTable;
86  ULONG ScopeIndex;
88 
89 typedef struct _SETJMP_FLOAT128
90 {
91  unsigned __int64 DECLSPEC_ALIGN(16) Part[2];
92 } SETJMP_FLOAT128;
93 
94 typedef struct _JUMP_BUFFER
95 {
96  unsigned __int64 Frame;
97  unsigned __int64 Rbx;
98  unsigned __int64 Rsp;
99  unsigned __int64 Rbp;
100  unsigned __int64 Rsi;
101  unsigned __int64 Rdi;
102  unsigned __int64 R12;
103  unsigned __int64 R13;
104  unsigned __int64 R14;
105  unsigned __int64 R15;
106  unsigned __int64 Rip;
107  unsigned __int64 Spare;
108  SETJMP_FLOAT128 Xmm6;
109  SETJMP_FLOAT128 Xmm7;
110  SETJMP_FLOAT128 Xmm8;
111  SETJMP_FLOAT128 Xmm9;
112  SETJMP_FLOAT128 Xmm10;
113  SETJMP_FLOAT128 Xmm11;
114  SETJMP_FLOAT128 Xmm12;
115  SETJMP_FLOAT128 Xmm13;
116  SETJMP_FLOAT128 Xmm14;
117  SETJMP_FLOAT128 Xmm15;
118 } _JUMP_BUFFER;
119 #endif // __REACTOS__
120 
121 static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
122 static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
123 static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
124 static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
125 static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
126 static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
127 static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
128 static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*);
129 static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
130 #endif
131 
132 #ifdef __i386__
133 
134 #ifndef __WINE_WINTRNL_H
135 #define ProcessExecuteFlags 0x22
136 #define MEM_EXECUTE_OPTION_DISABLE 0x01
137 #define MEM_EXECUTE_OPTION_ENABLE 0x02
138 #define MEM_EXECUTE_OPTION_PERMANENT 0x08
139 #endif
140 
141 static int my_argc;
142 static char** my_argv;
143 static int test_stage;
144 
145 static BOOL is_wow64;
146 
147 /* Test various instruction combinations that cause a protection fault on the i386,
148  * and check what the resulting exception looks like.
149  */
150 
151 static const struct exception
152 {
153  BYTE code[18]; /* asm code */
154  BYTE offset; /* offset of faulting instruction */
155  BYTE length; /* length of faulting instruction */
156  BOOL wow64_broken; /* broken on Wow64, should be skipped */
157  NTSTATUS status; /* expected status code */
158  DWORD nb_params; /* expected number of parameters */
159  DWORD params[4]; /* expected parameters */
160  NTSTATUS alt_status; /* alternative status code */
161  DWORD alt_nb_params; /* alternative number of parameters */
162  DWORD alt_params[4]; /* alternative parameters */
163 } exceptions[] =
164 {
165 /* 0 */
166  /* test some privileged instructions */
167  { { 0xfb, 0xc3 }, /* 0: sti; ret */
169  { { 0x6c, 0xc3 }, /* 1: insb (%dx); ret */
171  { { 0x6d, 0xc3 }, /* 2: insl (%dx); ret */
173  { { 0x6e, 0xc3 }, /* 3: outsb (%dx); ret */
175  { { 0x6f, 0xc3 }, /* 4: outsl (%dx); ret */
177 /* 5 */
178  { { 0xe4, 0x11, 0xc3 }, /* 5: inb $0x11,%al; ret */
180  { { 0xe5, 0x11, 0xc3 }, /* 6: inl $0x11,%eax; ret */
182  { { 0xe6, 0x11, 0xc3 }, /* 7: outb %al,$0x11; ret */
184  { { 0xe7, 0x11, 0xc3 }, /* 8: outl %eax,$0x11; ret */
186  { { 0xed, 0xc3 }, /* 9: inl (%dx),%eax; ret */
188 /* 10 */
189  { { 0xee, 0xc3 }, /* 10: outb %al,(%dx); ret */
191  { { 0xef, 0xc3 }, /* 11: outl %eax,(%dx); ret */
193  { { 0xf4, 0xc3 }, /* 12: hlt; ret */
195  { { 0xfa, 0xc3 }, /* 13: cli; ret */
197 
198  /* test long jump to invalid selector */
199  { { 0xea, 0, 0, 0, 0, 0, 0, 0xc3 }, /* 14: ljmp $0,$0; ret */
200  0, 7, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
201 
202 /* 15 */
203  /* test iret to invalid selector */
204  { { 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0xcf, 0x83, 0xc4, 0x0c, 0xc3 },
205  /* 15: pushl $0; pushl $0; pushl $0; iret; addl $12,%esp; ret */
206  6, 1, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
207 
208  /* test loading an invalid selector */
209  { { 0xb8, 0xef, 0xbe, 0x00, 0x00, 0x8e, 0xe8, 0xc3 }, /* 16: mov $beef,%ax; mov %ax,%gs; ret */
210  5, 2, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xbee8 } }, /* 0xbee8 or 0xffffffff */
211 
212  /* test accessing a zero selector (%es broken on Wow64) */
213  { { 0x06, 0x31, 0xc0, 0x8e, 0xc0, 0x26, 0xa1, 0, 0, 0, 0, 0x07, 0xc3 },
214  /* push %es; xor %eax,%eax; mov %ax,%es; mov %es:(0),%ax; pop %es; ret */
215  5, 6, TRUE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
216  { { 0x0f, 0xa8, 0x31, 0xc0, 0x8e, 0xe8, 0x65, 0xa1, 0, 0, 0, 0, 0x0f, 0xa9, 0xc3 },
217  /* push %gs; xor %eax,%eax; mov %ax,%gs; mov %gs:(0),%ax; pop %gs; ret */
218  6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
219 
220  /* test moving %cs -> %ss */
221  { { 0x0e, 0x17, 0x58, 0xc3 }, /* pushl %cs; popl %ss; popl %eax; ret */
222  1, 1, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
223 
224 /* 20 */
225  /* test overlong instruction (limit is 15 bytes, 5 on Win7) */
226  { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 },
227  0, 16, TRUE, STATUS_ILLEGAL_INSTRUCTION, 0, { 0 },
228  STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
229  { { 0x64,0x64,0x64,0x64,0xfa,0xc3 },
231 
232  /* test invalid interrupt */
233  { { 0xcd, 0xff, 0xc3 }, /* int $0xff; ret */
234  0, 2, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
235 
236  /* test moves to/from Crx */
237  { { 0x0f, 0x20, 0xc0, 0xc3 }, /* movl %cr0,%eax; ret */
239  { { 0x0f, 0x20, 0xe0, 0xc3 }, /* movl %cr4,%eax; ret */
241 /* 25 */
242  { { 0x0f, 0x22, 0xc0, 0xc3 }, /* movl %eax,%cr0; ret */
244  { { 0x0f, 0x22, 0xe0, 0xc3 }, /* movl %eax,%cr4; ret */
246 
247  /* test moves to/from Drx */
248  { { 0x0f, 0x21, 0xc0, 0xc3 }, /* movl %dr0,%eax; ret */
250  { { 0x0f, 0x21, 0xc8, 0xc3 }, /* movl %dr1,%eax; ret */
252  { { 0x0f, 0x21, 0xf8, 0xc3 }, /* movl %dr7,%eax; ret */
254 /* 30 */
255  { { 0x0f, 0x23, 0xc0, 0xc3 }, /* movl %eax,%dr0; ret */
257  { { 0x0f, 0x23, 0xc8, 0xc3 }, /* movl %eax,%dr1; ret */
259  { { 0x0f, 0x23, 0xf8, 0xc3 }, /* movl %eax,%dr7; ret */
261 
262  /* test memory reads */
263  { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffc,%eax; ret */
264  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffc } },
265  { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffd,%eax; ret */
266  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffd } },
267 /* 35 */
268  { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffe,%eax; ret */
269  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffe } },
270  { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xffffffff,%eax; ret */
271  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
272 
273  /* test memory writes */
274  { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffc; ret */
275  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffc } },
276  { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffd; ret */
277  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffd } },
278  { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffe; ret */
279  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffe } },
280 /* 40 */
281  { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xffffffff; ret */
282  0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } },
283 
284  /* test exception with cleared %ds and %es (broken on Wow64) */
285  { { 0x1e, 0x06, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfa, 0x07, 0x1f, 0xc3 },
286  /* push %ds; push %es; xorl %eax,%eax; mov %ax,%ds; mov %ax,%es; cli; pop %es; pop %ds; ret */
288 
289  { { 0xf1, 0x90, 0xc3 }, /* icebp; nop; ret */
290  1, 1, FALSE, STATUS_SINGLE_STEP, 0 },
291  { { 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, /* mov $0xb8b8b8b8, %eax */
292  0xb9, 0xb9, 0xb9, 0xb9, 0xb9, /* mov $0xb9b9b9b9, %ecx */
293  0xba, 0xba, 0xba, 0xba, 0xba, /* mov $0xbabababa, %edx */
294  0xcd, 0x2d, 0xc3 }, /* int $0x2d; ret */
295  17, 0, FALSE, STATUS_BREAKPOINT, 3, { 0xb8b8b8b8, 0xb9b9b9b9, 0xbabababa } },
296 };
297 
298 static int got_exception;
299 static BOOL have_vectored_api;
300 
301 static void run_exception_test(void *handler, const void* context,
302  const void *code, unsigned int code_size,
303  DWORD access)
304 {
305  struct {
307  const void *context;
308  } exc_frame;
309  void (*func)(void) = code_mem;
310  DWORD oldaccess, oldaccess2;
311 
312  exc_frame.frame.Handler = handler;
313  exc_frame.frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
314  exc_frame.context = context;
315 
316  memcpy(code_mem, code, code_size);
317  if(access)
318  VirtualProtect(code_mem, code_size, access, &oldaccess);
319 
320  NtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame;
321  func();
322  NtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev;
323 
324  if(access)
325  VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2);
326 }
327 
328 static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
329 {
330  PCONTEXT context = ExceptionInfo->ContextRecord;
331  PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
332  trace("vect. handler %08x addr:%p context.Eip:%x\n", rec->ExceptionCode,
333  rec->ExceptionAddress, context->Eip);
334 
335  ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n",
336  rec->ExceptionAddress, (char *)code_mem + 0xb);
337 
339  ok((void *)context->Eax == pRtlRaiseException ||
340  broken( is_wow64 && context->Eax == 0xf00f00f1 ), /* broken on vista */
341  "debugger managed to modify Eax to %x should be %p\n",
342  context->Eax, pRtlRaiseException);
343 
344  /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT
345  * even if raised by RtlRaiseException
346  */
348  {
349  ok(context->Eip == (DWORD)code_mem + 0xa ||
350  broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */
351  "Eip at %x instead of %x or %x\n", context->Eip,
352  (DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb);
353  }
354  else
355  {
356  ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n",
357  context->Eip, (DWORD)code_mem + 0xb);
358  }
359 
360  /* test if context change is preserved from vectored handler to stack handlers */
361  context->Eax = 0xf00f00f0;
363 }
364 
365 static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
367 {
368  trace( "exception: %08x flags:%x addr:%p context: Eip:%x\n",
369  rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip );
370 
371  ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n",
372  rec->ExceptionAddress, (char *)code_mem + 0xb);
373 
374  /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT
375  * even if raised by RtlRaiseException
376  */
378  {
379  ok(context->Eip == (DWORD)code_mem + 0xa ||
380  broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */
381  "Eip at %x instead of %x or %x\n", context->Eip,
382  (DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb);
383  }
384  else
385  {
386  ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n",
387  context->Eip, (DWORD)code_mem + 0xb);
388  }
389 
390  if(have_vectored_api)
391  ok(context->Eax == 0xf00f00f0, "Eax is %x, should have been set to 0xf00f00f0 in vectored handler\n",
392  context->Eax);
393 
394  /* give the debugger a chance to examine the state a second time */
395  /* without the exception handler changing Eip */
396  if (test_stage == 2)
398 
399  /* Eip in context is decreased by 1
400  * Increase it again, else execution will continue in the middle of an instruction */
401  if(rec->ExceptionCode == EXCEPTION_BREAKPOINT && (context->Eip == (DWORD)code_mem + 0xa))
402  context->Eip += 1;
404 }
405 
406 
407 static const BYTE call_one_arg_code[] = {
408  0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */
409  0x50, /* push %eax */
410  0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */
411  0xff, 0xd0, /* call *%eax */
412  0x90, /* nop */
413  0x90, /* nop */
414  0x90, /* nop */
415  0x90, /* nop */
416  0xc3, /* ret */
417 };
418 
419 
420 static void run_rtlraiseexception_test(DWORD exceptioncode)
421 {
424  PVOID vectored_handler = NULL;
425 
426  void (*func)(void* function, EXCEPTION_RECORD* record) = code_mem;
427 
428  record.ExceptionCode = exceptioncode;
429  record.ExceptionFlags = 0;
430  record.ExceptionRecord = NULL;
431  record.ExceptionAddress = NULL; /* does not matter, copied return address */
432  record.NumberParameters = 0;
433 
434  frame.Handler = rtlraiseexception_handler;
435  frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
436 
437  memcpy(code_mem, call_one_arg_code, sizeof(call_one_arg_code));
438 
439  NtCurrentTeb()->Tib.ExceptionList = &frame;
440  if (have_vectored_api)
441  {
442  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &rtlraiseexception_vectored_handler);
443  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
444  }
445 
446  func(pRtlRaiseException, &record);
447  ok( record.ExceptionAddress == (char *)code_mem + 0x0b,
448  "address set to %p instead of %p\n", record.ExceptionAddress, (char *)code_mem + 0x0b );
449 
450  if (have_vectored_api)
451  pRtlRemoveVectoredExceptionHandler(vectored_handler);
452  NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
453 }
454 
455 static void test_rtlraiseexception(void)
456 {
457  if (!pRtlRaiseException)
458  {
459  skip("RtlRaiseException not found\n");
460  return;
461  }
462 
463  /* test without debugger */
464  run_rtlraiseexception_test(0x12345);
465  run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
466  run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
467 }
468 
469 static DWORD unwind_expected_eax;
470 
471 static DWORD unwind_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
473 {
474  trace("exception: %08x flags:%x addr:%p context: Eip:%x\n",
475  rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip);
476 
477  ok(rec->ExceptionCode == STATUS_UNWIND, "ExceptionCode is %08x instead of %08x\n",
479  ok(rec->ExceptionAddress == (char *)code_mem + 0x22, "ExceptionAddress at %p instead of %p\n",
480  rec->ExceptionAddress, (char *)code_mem + 0x22);
481  ok(context->Eax == unwind_expected_eax, "context->Eax is %08x instead of %08x\n",
482  context->Eax, unwind_expected_eax);
483 
484  context->Eax += 1;
486 }
487 
488 static const BYTE call_unwind_code[] = {
489  0x55, /* push %ebp */
490  0x53, /* push %ebx */
491  0x56, /* push %esi */
492  0x57, /* push %edi */
493  0xe8, 0x00, 0x00, 0x00, 0x00, /* call 0 */
494  0x58, /* 0: pop %eax */
495  0x05, 0x1e, 0x00, 0x00, 0x00, /* add $0x1e,%eax */
496  0xff, 0x74, 0x24, 0x20, /* push 0x20(%esp) */
497  0xff, 0x74, 0x24, 0x20, /* push 0x20(%esp) */
498  0x50, /* push %eax */
499  0xff, 0x74, 0x24, 0x24, /* push 0x24(%esp) */
500  0x8B, 0x44, 0x24, 0x24, /* mov 0x24(%esp),%eax */
501  0xff, 0xd0, /* call *%eax */
502  0x5f, /* pop %edi */
503  0x5e, /* pop %esi */
504  0x5b, /* pop %ebx */
505  0x5d, /* pop %ebp */
506  0xc3, /* ret */
507  0xcc, /* int $3 */
508 };
509 
510 static void test_unwind(void)
511 {
512  EXCEPTION_REGISTRATION_RECORD frames[2], *frame2 = &frames[0], *frame1 = &frames[1];
513  DWORD (*func)(void* function, EXCEPTION_REGISTRATION_RECORD *pEndFrame, EXCEPTION_RECORD* record, DWORD retval) = code_mem;
514  DWORD retval;
515 
516  memcpy(code_mem, call_unwind_code, sizeof(call_unwind_code));
517 
518  /* add first unwind handler */
519  frame1->Handler = unwind_handler;
520  frame1->Prev = NtCurrentTeb()->Tib.ExceptionList;
521  NtCurrentTeb()->Tib.ExceptionList = frame1;
522 
523  /* add second unwind handler */
524  frame2->Handler = unwind_handler;
525  frame2->Prev = NtCurrentTeb()->Tib.ExceptionList;
526  NtCurrentTeb()->Tib.ExceptionList = frame2;
527 
528  /* test unwind to current frame */
529  unwind_expected_eax = 0xDEAD0000;
530  retval = func(pRtlUnwind, frame2, NULL, 0xDEAD0000);
531  ok(retval == 0xDEAD0000, "RtlUnwind returned eax %08x instead of %08x\n", retval, 0xDEAD0000);
532  ok(NtCurrentTeb()->Tib.ExceptionList == frame2, "Exception record points to %p instead of %p\n",
533  NtCurrentTeb()->Tib.ExceptionList, frame2);
534 
535  /* unwind to frame1 */
536  unwind_expected_eax = 0xDEAD0000;
537  retval = func(pRtlUnwind, frame1, NULL, 0xDEAD0000);
538  ok(retval == 0xDEAD0001, "RtlUnwind returned eax %08x instead of %08x\n", retval, 0xDEAD0001);
539  ok(NtCurrentTeb()->Tib.ExceptionList == frame1, "Exception record points to %p instead of %p\n",
540  NtCurrentTeb()->Tib.ExceptionList, frame1);
541 
542  /* restore original handler */
543  NtCurrentTeb()->Tib.ExceptionList = frame1->Prev;
544 }
545 
548 {
549  const struct exception *except = *(const struct exception **)(frame + 1);
550  unsigned int i, parameter_count, entry = except - exceptions;
551 
552  got_exception++;
553  trace( "exception %u: %x flags:%x addr:%p\n",
555 
556  ok( rec->ExceptionCode == except->status ||
557  (except->alt_status != 0 && rec->ExceptionCode == except->alt_status),
558  "%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status );
559  ok( context->Eip == (DWORD_PTR)code_mem + except->offset,
560  "%u: Unexpected eip %#x/%#lx\n", entry,
561  context->Eip, (DWORD_PTR)code_mem + except->offset );
562  ok( rec->ExceptionAddress == (char*)context->Eip ||
563  (rec->ExceptionCode == STATUS_BREAKPOINT && rec->ExceptionAddress == (char*)context->Eip + 1),
564  "%u: Unexpected exception address %p/%p\n", entry,
565  rec->ExceptionAddress, (char*)context->Eip );
566 
567  if (except->status == STATUS_BREAKPOINT && is_wow64)
568  parameter_count = 1;
569  else if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status)
570  parameter_count = except->nb_params;
571  else
572  parameter_count = except->alt_nb_params;
573 
574  ok( rec->NumberParameters == parameter_count,
575  "%u: Unexpected parameter count %u/%u\n", entry, rec->NumberParameters, parameter_count );
576 
577  /* Most CPUs (except Intel Core apparently) report a segment limit violation */
578  /* instead of page faults for accesses beyond 0xffffffff */
579  if (except->nb_params == 2 && except->params[1] >= 0xfffffffd)
580  {
581  if (rec->ExceptionInformation[0] == 0 && rec->ExceptionInformation[1] == 0xffffffff)
582  goto skip_params;
583  }
584 
585  /* Seems that both 0xbee8 and 0xfffffffff can be returned in windows */
586  if (except->nb_params == 2 && rec->NumberParameters == 2
587  && except->params[1] == 0xbee8 && rec->ExceptionInformation[1] == 0xffffffff
588  && except->params[0] == rec->ExceptionInformation[0])
589  {
590  goto skip_params;
591  }
592 
593  if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status)
594  {
595  for (i = 0; i < rec->NumberParameters; i++)
596  ok( rec->ExceptionInformation[i] == except->params[i],
597  "%u: Wrong parameter %d: %lx/%x\n",
598  entry, i, rec->ExceptionInformation[i], except->params[i] );
599  }
600  else
601  {
602  for (i = 0; i < rec->NumberParameters; i++)
603  ok( rec->ExceptionInformation[i] == except->alt_params[i],
604  "%u: Wrong parameter %d: %lx/%x\n",
605  entry, i, rec->ExceptionInformation[i], except->alt_params[i] );
606  }
607 
608 skip_params:
609  /* don't handle exception if it's not the address we expected */
610  if (context->Eip != (DWORD_PTR)code_mem + except->offset) return ExceptionContinueSearch;
611 
612  context->Eip += except->length;
614 }
615 
616 static void test_prot_fault(void)
617 {
618  unsigned int i;
619 
620  for (i = 0; i < sizeof(exceptions)/sizeof(exceptions[0]); i++)
621  {
622  if (is_wow64 && exceptions[i].wow64_broken && !strcmp( winetest_platform, "windows" ))
623  {
624  skip( "Exception %u broken on Wow64\n", i );
625  continue;
626  }
627  got_exception = 0;
628  run_exception_test(handler, &exceptions[i], &exceptions[i].code,
629  sizeof(exceptions[i].code), 0);
630  if (!i && !got_exception)
631  {
632  trace( "No exception, assuming win9x, no point in testing further\n" );
633  break;
634  }
635  ok( got_exception == (exceptions[i].status != 0),
636  "%u: bad exception count %d\n", i, got_exception );
637  }
638 }
639 
640 struct dbgreg_test {
641  DWORD dr0, dr1, dr2, dr3, dr6, dr7;
642 };
643 
644 /* test handling of debug registers */
645 static DWORD dreg_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
647 {
648  const struct dbgreg_test *test = *(const struct dbgreg_test **)(frame + 1);
649 
650  context->Eip += 2; /* Skips the popl (%eax) */
651  context->Dr0 = test->dr0;
652  context->Dr1 = test->dr1;
653  context->Dr2 = test->dr2;
654  context->Dr3 = test->dr3;
655  context->Dr6 = test->dr6;
656  context->Dr7 = test->dr7;
658 }
659 
660 #define CHECK_DEBUG_REG(n, m) \
661  ok((ctx.Dr##n & m) == test->dr##n, "(%d) failed to set debug register " #n " to %x, got %x\n", \
662  test_num, test->dr##n, ctx.Dr##n)
663 
664 static void check_debug_registers(int test_num, const struct dbgreg_test *test)
665 {
666  CONTEXT ctx;
668 
670  status = pNtGetContextThread(GetCurrentThread(), &ctx);
671  ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status);
672 
673  CHECK_DEBUG_REG(0, ~0);
674  CHECK_DEBUG_REG(1, ~0);
675  CHECK_DEBUG_REG(2, ~0);
676  CHECK_DEBUG_REG(3, ~0);
677  CHECK_DEBUG_REG(6, 0x0f);
678  CHECK_DEBUG_REG(7, ~0xdc00);
679 }
680 
681 static const BYTE segfault_code[5] = {
682  0x31, 0xc0, /* xor %eax,%eax */
683  0x8f, 0x00, /* popl (%eax) - cause exception */
684  0xc3 /* ret */
685 };
686 
687 /* test the single step exception behaviour */
688 static DWORD single_step_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
690 {
691  got_exception++;
692  ok (!(context->EFlags & 0x100), "eflags has single stepping bit set\n");
693 
694  if( got_exception < 3)
695  context->EFlags |= 0x100; /* single step until popf instruction */
696  else {
697  /* show that the last single step exception on the popf instruction
698  * (which removed the TF bit), still is a EXCEPTION_SINGLE_STEP exception */
700  "exception is not EXCEPTION_SINGLE_STEP: %x\n", rec->ExceptionCode);
701  }
702 
704 }
705 
706 static const BYTE single_stepcode[] = {
707  0x9c, /* pushf */
708  0x58, /* pop %eax */
709  0x0d,0,1,0,0, /* or $0x100,%eax */
710  0x50, /* push %eax */
711  0x9d, /* popf */
712  0x35,0,1,0,0, /* xor $0x100,%eax */
713  0x50, /* push %eax */
714  0x9d, /* popf */
715  0xc3
716 };
717 
718 /* Test the alignment check (AC) flag handling. */
719 static const BYTE align_check_code[] = {
720  0x55, /* push %ebp */
721  0x89,0xe5, /* mov %esp,%ebp */
722  0x9c, /* pushf */
723  0x58, /* pop %eax */
724  0x0d,0,0,4,0, /* or $0x40000,%eax */
725  0x50, /* push %eax */
726  0x9d, /* popf */
727  0x89,0xe0, /* mov %esp, %eax */
728  0x8b,0x40,0x1, /* mov 0x1(%eax), %eax - cause exception */
729  0x9c, /* pushf */
730  0x58, /* pop %eax */
731  0x35,0,0,4,0, /* xor $0x40000,%eax */
732  0x50, /* push %eax */
733  0x9d, /* popf */
734  0x5d, /* pop %ebp */
735  0xc3, /* ret */
736 };
737 
738 static DWORD align_check_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
740 {
741  ok (!(context->EFlags & 0x40000), "eflags has AC bit set\n");
742  got_exception++;
744 }
745 
746 /* Test the direction flag handling. */
747 static const BYTE direction_flag_code[] = {
748  0x55, /* push %ebp */
749  0x89,0xe5, /* mov %esp,%ebp */
750  0xfd, /* std */
751  0xfa, /* cli - cause exception */
752  0x5d, /* pop %ebp */
753  0xc3, /* ret */
754 };
755 
756 static DWORD direction_flag_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
758 {
759 #ifdef __GNUC__
760  unsigned int flags;
761  __asm__("pushfl; popl %0; cld" : "=r" (flags) );
762  /* older windows versions don't clear DF properly so don't test */
763  if (flags & 0x400) trace( "eflags has DF bit set\n" );
764 #endif
765  ok( context->EFlags & 0x400, "context eflags has DF bit cleared\n" );
766  got_exception++;
767  context->Eip++; /* skip cli */
768  context->EFlags &= ~0x400; /* make sure it is cleared on return */
770 }
771 
772 /* test single stepping over hardware breakpoint */
773 static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
775 {
776  got_exception++;
778  "wrong exception code: %x\n", rec->ExceptionCode);
779 
780  if(got_exception == 1) {
781  /* hw bp exception on first nop */
782  ok( context->Eip == (DWORD)code_mem, "eip is wrong: %x instead of %x\n",
783  context->Eip, (DWORD)code_mem);
784  ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n");
785  ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n");
786  context->Dr0 = context->Dr0 + 1; /* set hw bp again on next instruction */
787  context->EFlags |= 0x100; /* enable single stepping */
788  } else if( got_exception == 2) {
789  /* single step exception on second nop */
790  ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
791  context->Eip, (DWORD)code_mem + 1);
792  ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
793  /* depending on the win version the B0 bit is already set here as well
794  ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n"); */
795  context->EFlags |= 0x100;
796  } else if( got_exception == 3) {
797  /* hw bp exception on second nop */
798  ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
799  context->Eip, (DWORD)code_mem + 1);
800  ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n");
801  ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n");
802  context->Dr0 = 0; /* clear breakpoint */
803  context->EFlags |= 0x100;
804  } else {
805  /* single step exception on ret */
806  ok( context->Eip == (DWORD)code_mem + 2, "eip is wrong: %x instead of %x\n",
807  context->Eip, (DWORD)code_mem + 2);
808  ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n");
809  ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
810  }
811 
812  context->Dr6 = 0; /* clear status register */
814 }
815 
816 static const BYTE dummy_code[] = { 0x90, 0x90, 0xc3 }; /* nop, nop, ret */
817 
818 /* test int3 handling */
819 static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
821 {
822  ok( rec->ExceptionAddress == code_mem, "exception address not at: %p, but at %p\n",
823  code_mem, rec->ExceptionAddress);
824  ok( context->Eip == (DWORD)code_mem, "eip not at: %p, but at %#x\n", code_mem, context->Eip);
825  if(context->Eip == (DWORD)code_mem) context->Eip++; /* skip breakpoint */
826 
828 }
829 
830 static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */
831 
832 static DWORD WINAPI hw_reg_exception_thread( void *arg )
833 {
834  int expect = (ULONG_PTR)arg;
835  got_exception = 0;
836  run_exception_test( bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0 );
837  ok( got_exception == expect, "expected %u exceptions, got %d\n", expect, got_exception );
838  return 0;
839 }
840 
841 static void test_exceptions(void)
842 {
843  CONTEXT ctx;
844  NTSTATUS res;
845  struct dbgreg_test dreg_test;
846  HANDLE h;
847 
848  if (!pNtGetContextThread || !pNtSetContextThread)
849  {
850  skip( "NtGetContextThread/NtSetContextThread not found\n" );
851  return;
852  }
853 
854  /* test handling of debug registers */
855  memset(&dreg_test, 0, sizeof(dreg_test));
856 
857  dreg_test.dr0 = 0x42424240;
858  dreg_test.dr2 = 0x126bb070;
859  dreg_test.dr3 = 0x0badbad0;
860  dreg_test.dr7 = 0xffff0115;
861  run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0);
862  check_debug_registers(1, &dreg_test);
863 
864  dreg_test.dr0 = 0x42424242;
865  dreg_test.dr2 = 0x100f0fe7;
866  dreg_test.dr3 = 0x0abebabe;
867  dreg_test.dr7 = 0x115;
868  run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0);
869  check_debug_registers(2, &dreg_test);
870 
871  /* test single stepping behavior */
872  got_exception = 0;
873  run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode), 0);
874  ok(got_exception == 3, "expected 3 single step exceptions, got %d\n", got_exception);
875 
876  /* test alignment exceptions */
877  got_exception = 0;
878  run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code), 0);
879  ok(got_exception == 0, "got %d alignment faults, expected 0\n", got_exception);
880 
881  /* test direction flag */
882  got_exception = 0;
883  run_exception_test(direction_flag_handler, NULL, direction_flag_code, sizeof(direction_flag_code), 0);
884  ok(got_exception == 1, "got %d exceptions, expected 1\n", got_exception);
885 
886  /* test single stepping over hardware breakpoint */
887  memset(&ctx, 0, sizeof(ctx));
888  ctx.Dr0 = (DWORD) code_mem; /* set hw bp on first nop */
889  ctx.Dr7 = 3;
891  res = pNtSetContextThread( GetCurrentThread(), &ctx);
892  ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res);
893 
894  got_exception = 0;
895  run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0);
896  ok( got_exception == 4,"expected 4 exceptions, got %d\n", got_exception);
897 
898  /* test int3 handling */
899  run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code), 0);
900 
901  /* test that hardware breakpoints are not inherited by created threads */
902  res = pNtSetContextThread( GetCurrentThread(), &ctx );
903  ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
904 
905  h = CreateThread( NULL, 0, hw_reg_exception_thread, 0, 0, NULL );
906  WaitForSingleObject( h, 10000 );
907  CloseHandle( h );
908 
909  h = CreateThread( NULL, 0, hw_reg_exception_thread, (void *)4, CREATE_SUSPENDED, NULL );
911  res = pNtGetContextThread( h, &ctx );
912  ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res );
913  ok( ctx.Dr0 == 0, "dr0 %x\n", ctx.Dr0 );
914  ok( ctx.Dr7 == 0, "dr7 %x\n", ctx.Dr7 );
915  ctx.Dr0 = (DWORD)code_mem;
916  ctx.Dr7 = 3;
917  res = pNtSetContextThread( h, &ctx );
918  ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
919  ResumeThread( h );
920  WaitForSingleObject( h, 10000 );
921  CloseHandle( h );
922 
923  ctx.Dr0 = 0;
924  ctx.Dr7 = 0;
925  res = pNtSetContextThread( GetCurrentThread(), &ctx );
926  ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
927 }
928 
929 static void test_debugger(void)
930 {
931  char cmdline[MAX_PATH];
933  STARTUPINFOA si = { 0 };
934  DEBUG_EVENT de;
935  DWORD continuestatus;
936  PVOID code_mem_address = NULL;
938  SIZE_T size_read;
939  BOOL ret;
940  int counter = 0;
941  si.cb = sizeof(si);
942 
943  if(!pNtGetContextThread || !pNtSetContextThread || !pNtReadVirtualMemory || !pNtTerminateProcess)
944  {
945  skip("NtGetContextThread, NtSetContextThread, NtReadVirtualMemory or NtTerminateProcess not found\n");
946  return;
947  }
948 
949  sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage);
951  ok(ret, "could not create child process error: %u\n", GetLastError());
952  if (!ret)
953  return;
954 
955  do
956  {
957  continuestatus = DBG_CONTINUE;
958  ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
959 
960  if (de.dwThreadId != pi.dwThreadId)
961  {
962  trace("event %d not coming from main thread, ignoring\n", de.dwDebugEventCode);
964  continue;
965  }
966 
968  {
970  {
971  skip("child process loaded at different address, terminating it\n");
972  pNtTerminateProcess(pi.hProcess, 0);
973  }
974  }
976  {
977  CONTEXT ctx;
978  int stage;
979 
980  counter++;
981  status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address,
982  sizeof(code_mem_address), &size_read);
983  ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
984  status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage,
985  sizeof(stage), &size_read);
986  ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
987 
989  status = pNtGetContextThread(pi.hThread, &ctx);
990  ok(!status, "NtGetContextThread failed with 0x%x\n", status);
991 
992  trace("exception 0x%x at %p firstchance=%d Eip=0x%x, Eax=0x%x\n",
995 
996  if (counter > 100)
997  {
998  ok(FALSE, "got way too many exceptions, probably caught in an infinite loop, terminating child\n");
999  pNtTerminateProcess(pi.hProcess, 1);
1000  }
1001  else if (counter >= 2) /* skip startup breakpoint */
1002  {
1003  if (stage == 1)
1004  {
1005  ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at %x instead of %p\n",
1006  ctx.Eip, (char *)code_mem_address + 0xb);
1007  /* setting the context from debugger does not affect the context, the exception handlers gets */
1008  /* uncomment once wine is fixed */
1009  /* ctx.Eip = 0x12345; */
1010  ctx.Eax = 0xf00f00f1;
1011 
1012  /* let the debuggee handle the exception */
1013  continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1014  }
1015  else if (stage == 2)
1016  {
1017  if (de.u.Exception.dwFirstChance)
1018  {
1019  /* debugger gets first chance exception with unmodified ctx.Eip */
1020  ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n",
1021  ctx.Eip, (char *)code_mem_address + 0xb);
1022 
1023  /* setting the context from debugger does not affect the context, the exception handlers gets */
1024  /* uncomment once wine is fixed */
1025  /* ctx.Eip = 0x12345; */
1026  ctx.Eax = 0xf00f00f1;
1027 
1028  /* pass exception to debuggee
1029  * exception will not be handled and
1030  * a second chance exception will be raised */
1031  continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1032  }
1033  else
1034  {
1035  /* debugger gets context after exception handler has played with it */
1036  /* ctx.Eip is the same value the exception handler got */
1038  {
1039  ok((char *)ctx.Eip == (char *)code_mem_address + 0xa ||
1040  broken(is_wow64 && (char *)ctx.Eip == (char *)code_mem_address + 0xb),
1041  "Eip at 0x%x instead of %p\n",
1042  ctx.Eip, (char *)code_mem_address + 0xa);
1043  /* need to fixup Eip for debuggee */
1044  if ((char *)ctx.Eip == (char *)code_mem_address + 0xa)
1045  ctx.Eip += 1;
1046  }
1047  else
1048  ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n",
1049  ctx.Eip, (char *)code_mem_address + 0xb);
1050  /* here we handle exception */
1051  }
1052  }
1053  else if (stage == 7 || stage == 8)
1054  {
1056  "expected EXCEPTION_BREAKPOINT, got %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode);
1057  ok((char *)ctx.Eip == (char *)code_mem_address + 0x1d,
1058  "expected Eip = %p, got 0x%x\n", (char *)code_mem_address + 0x1d, ctx.Eip);
1059 
1060  if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1061  }
1062  else if (stage == 9 || stage == 10)
1063  {
1065  "expected EXCEPTION_BREAKPOINT, got %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode);
1066  ok((char *)ctx.Eip == (char *)code_mem_address + 2,
1067  "expected Eip = %p, got 0x%x\n", (char *)code_mem_address + 2, ctx.Eip);
1068 
1069  if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1070  }
1071  else if (stage == 11 || stage == 12)
1072  {
1074  "unexpected exception code %08x, expected %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode,
1077  "unexpected number of parameters %d, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
1078 
1079  if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1080  }
1081  else
1082  ok(FALSE, "unexpected stage %x\n", stage);
1083 
1084  status = pNtSetContextThread(pi.hThread, &ctx);
1085  ok(!status, "NtSetContextThread failed with 0x%x\n", status);
1086  }
1087  }
1089  {
1090  int stage;
1091 #ifdef __REACTOS__
1092  /* This will catch our DPRINTs, such as
1093  * "WARNING: RtlpDphTargetDllsLogicInitialize at ..\..\lib\rtl\heappage.c:1283 is UNIMPLEMENTED!"
1094  * so we need a full-size buffer to avoid a stack overflow
1095  */
1096  char buffer[513];
1097 #else
1098  char buffer[64];
1099 #endif
1100 
1101  status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage,
1102  sizeof(stage), &size_read);
1103  ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
1104 
1105  ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n");
1106  ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n",
1108 
1109  memset(buffer, 0, sizeof(buffer));
1110  status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer,
1111  de.u.DebugString.nDebugStringLength, &size_read);
1112  ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
1113 
1114  if (stage == 3 || stage == 4)
1115  ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer);
1116  else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */
1117  ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer);
1118 
1119  if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1120  }
1121  else if (de.dwDebugEventCode == RIP_EVENT)
1122  {
1123  int stage;
1124 
1125  status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage,
1126  sizeof(stage), &size_read);
1127  ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
1128 
1129  if (stage == 5 || stage == 6)
1130  {
1131  ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08x, expected %08x\n",
1132  de.u.RipInfo.dwError, 0x11223344);
1133  ok(de.u.RipInfo.dwType == 0x55667788, "got unexpected rip type %08x, expected %08x\n",
1134  de.u.RipInfo.dwType, 0x55667788);
1135  }
1136  else
1137  ok(FALSE, "unexpected stage %x\n", stage);
1138 
1139  if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
1140  }
1141 
1142  ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus);
1143 
1145 
1146  winetest_wait_child_process( pi.hProcess );
1147  ret = CloseHandle(pi.hThread);
1148  ok(ret, "error %u\n", GetLastError());
1149  ret = CloseHandle(pi.hProcess);
1150  ok(ret, "error %u\n", GetLastError());
1151 
1152  return;
1153 }
1154 
1155 static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
1157 {
1158  int *stage = *(int **)(frame + 1);
1159 
1160  got_exception++;
1161 
1162  if( *stage == 1) {
1163  /* fault while executing sse instruction */
1164  context->Eip += 3; /* skip addps */
1166  }
1167  else if ( *stage == 2 || *stage == 3 ) {
1168  /* stage 2 - divide by zero fault */
1169  /* stage 3 - invalid operation fault */
1171  skip("system doesn't support SIMD exceptions\n");
1172  else {
1174  "exception code: %#x, should be %#x\n",
1176  ok( rec->NumberParameters == 1 || broken(is_wow64 && rec->NumberParameters == 2),
1177  "# of params: %i, should be 1\n",
1178  rec->NumberParameters);
1179  if( rec->NumberParameters == 1 )
1180  ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be 0\n", rec->ExceptionInformation[0]);
1181  }
1182  context->Eip += 3; /* skip divps */
1183  }
1184  else
1185  ok(FALSE, "unexpected stage %x\n", *stage);
1186 
1188 }
1189 
1190 static const BYTE simd_exception_test[] = {
1191  0x83, 0xec, 0x4, /* sub $0x4, %esp */
1192  0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */
1193  0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */
1194  0x66, 0x81, 0x24, 0x24, 0xff, 0xfd, /* andw $0xfdff,(%esp) * enable divide by */
1195  0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * zero exceptions */
1196  0x6a, 0x01, /* push $0x1 */
1197  0x6a, 0x01, /* push $0x1 */
1198  0x6a, 0x01, /* push $0x1 */
1199  0x6a, 0x01, /* push $0x1 */
1200  0x0f, 0x10, 0x0c, 0x24, /* movups (%esp),%xmm1 * fill dividend */
1201  0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */
1202  0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */
1203  0x83, 0xc4, 0x10, /* add $0x10,%esp */
1204  0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr */
1205  0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */
1206  0x83, 0xc4, 0x04, /* add $0x4,%esp */
1207  0xc3, /* ret */
1208 };
1209 
1210 static const BYTE simd_exception_test2[] = {
1211  0x83, 0xec, 0x4, /* sub $0x4, %esp */
1212  0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */
1213  0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */
1214  0x66, 0x81, 0x24, 0x24, 0x7f, 0xff, /* andw $0xff7f,(%esp) * enable invalid */
1215  0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * operation exceptions */
1216  0x0f, 0x57, 0xc9, /* xorps %xmm1,%xmm1 * clear dividend */
1217  0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */
1218  0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */
1219  0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr */
1220  0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */
1221  0x83, 0xc4, 0x04, /* add $0x4,%esp */
1222  0xc3, /* ret */
1223 };
1224 
1225 static const BYTE sse_check[] = {
1226  0x0f, 0x58, 0xc8, /* addps %xmm0,%xmm1 */
1227  0xc3, /* ret */
1228 };
1229 
1230 static void test_simd_exceptions(void)
1231 {
1232  int stage;
1233 
1234  /* test if CPU & OS can do sse */
1235  stage = 1;
1236  got_exception = 0;
1237  run_exception_test(simd_fault_handler, &stage, sse_check, sizeof(sse_check), 0);
1238  if(got_exception) {
1239  skip("system doesn't support SSE\n");
1240  return;
1241  }
1242 
1243  /* generate a SIMD exception */
1244  stage = 2;
1245  got_exception = 0;
1246  run_exception_test(simd_fault_handler, &stage, simd_exception_test,
1247  sizeof(simd_exception_test), 0);
1248  ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception);
1249 
1250  /* generate a SIMD exception, test FPE_FLTINV */
1251  stage = 3;
1252  got_exception = 0;
1253  run_exception_test(simd_fault_handler, &stage, simd_exception_test2,
1254  sizeof(simd_exception_test2), 0);
1255  ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception);
1256 }
1257 
1258 struct fpu_exception_info
1259 {
1260  DWORD exception_code;
1261  DWORD exception_offset;
1262  DWORD eip_offset;
1263 };
1264 
1265 static DWORD fpu_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
1267 {
1268  struct fpu_exception_info *info = *(struct fpu_exception_info **)(frame + 1);
1269 
1270  info->exception_code = rec->ExceptionCode;
1271  info->exception_offset = (BYTE *)rec->ExceptionAddress - (BYTE *)code_mem;
1272  info->eip_offset = context->Eip - (DWORD)code_mem;
1273 
1274  ++context->Eip;
1276 }
1277 
1278 static void test_fpu_exceptions(void)
1279 {
1280  static const BYTE fpu_exception_test_ie[] =
1281  {
1282  0x83, 0xec, 0x04, /* sub $0x4,%esp */
1283  0x66, 0xc7, 0x04, 0x24, 0xfe, 0x03, /* movw $0x3fe,(%esp) */
1284  0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */
1285  0xd9, 0x2c, 0x24, /* fldcw (%esp) */
1286  0xd9, 0xee, /* fldz */
1287  0xd9, 0xe8, /* fld1 */
1288  0xde, 0xf1, /* fdivp */
1289  0xdd, 0xd8, /* fstp %st(0) */
1290  0xdd, 0xd8, /* fstp %st(0) */
1291  0x9b, /* fwait */
1292  0xdb, 0xe2, /* fnclex */
1293  0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */
1294  0x83, 0xc4, 0x04, /* add $0x4,%esp */
1295  0xc3, /* ret */
1296  };
1297 
1298  static const BYTE fpu_exception_test_de[] =
1299  {
1300  0x83, 0xec, 0x04, /* sub $0x4,%esp */
1301  0x66, 0xc7, 0x04, 0x24, 0xfb, 0x03, /* movw $0x3fb,(%esp) */
1302  0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */
1303  0xd9, 0x2c, 0x24, /* fldcw (%esp) */
1304  0xdd, 0xd8, /* fstp %st(0) */
1305  0xd9, 0xee, /* fldz */
1306  0xd9, 0xe8, /* fld1 */
1307  0xde, 0xf1, /* fdivp */
1308  0x9b, /* fwait */
1309  0xdb, 0xe2, /* fnclex */
1310  0xdd, 0xd8, /* fstp %st(0) */
1311  0xdd, 0xd8, /* fstp %st(0) */
1312  0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */
1313  0x83, 0xc4, 0x04, /* add $0x4,%esp */
1314  0xc3, /* ret */
1315  };
1316 
1317  struct fpu_exception_info info;
1318 
1319  memset(&info, 0, sizeof(info));
1320  run_exception_test(fpu_exception_handler, &info, fpu_exception_test_ie, sizeof(fpu_exception_test_ie), 0);
1321  ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK,
1322  "Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n", info.exception_code);
1323  ok(info.exception_offset == 0x19 ||
1324  broken( info.exception_offset == info.eip_offset ),
1325  "Got exception offset %#x, expected 0x19\n", info.exception_offset);
1326  ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n", info.eip_offset);
1327 
1328  memset(&info, 0, sizeof(info));
1329  run_exception_test(fpu_exception_handler, &info, fpu_exception_test_de, sizeof(fpu_exception_test_de), 0);
1330  ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO,
1331  "Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n", info.exception_code);
1332  ok(info.exception_offset == 0x17 ||
1333  broken( info.exception_offset == info.eip_offset ),
1334  "Got exception offset %#x, expected 0x17\n", info.exception_offset);
1335  ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n", info.eip_offset);
1336 }
1337 
1338 struct dpe_exception_info {
1339  BOOL exception_caught;
1340  DWORD exception_info;
1341 };
1342 
1343 static DWORD dpe_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
1345 {
1346  DWORD old_prot;
1347  struct dpe_exception_info *info = *(struct dpe_exception_info **)(frame + 1);
1348 
1350  "Exception code %08x\n", rec->ExceptionCode);
1351  ok(rec->NumberParameters == 2,
1352  "Parameter count: %d\n", rec->NumberParameters);
1353  ok((LPVOID)rec->ExceptionInformation[1] == code_mem,
1354  "Exception address: %p, expected %p\n",
1356 
1357  info->exception_info = rec->ExceptionInformation[0];
1358  info->exception_caught = TRUE;
1359 
1362 }
1363 
1364 static void test_dpe_exceptions(void)
1365 {
1366  static const BYTE single_ret[] = {0xC3};
1367  struct dpe_exception_info info;
1368  NTSTATUS stat;
1369  BOOL has_hw_support;
1370  BOOL is_permanent = FALSE, can_test_without = TRUE, can_test_with = TRUE;
1371  DWORD val;
1372  ULONG len;
1373 
1374  /* Query DEP with len too small */
1375  stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val - 1, &len);
1377  {
1378  skip("This software platform does not support DEP\n");
1379  return;
1380  }
1381  ok(stat == STATUS_INFO_LENGTH_MISMATCH, "buffer too small: %08x\n", stat);
1382 
1383  /* Query DEP */
1384  stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val, &len);
1385  ok(stat == STATUS_SUCCESS, "querying DEP: status %08x\n", stat);
1386  if(stat == STATUS_SUCCESS)
1387  {
1388  ok(len == sizeof val, "returned length: %d\n", len);
1390  {
1391  skip("toggling DEP impossible - status locked\n");
1392  is_permanent = TRUE;
1394  can_test_without = FALSE;
1395  else
1396  can_test_with = FALSE;
1397  }
1398  }
1399 
1400  if(!is_permanent)
1401  {
1402  /* Enable DEP */
1404  stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
1405  ok(stat == STATUS_SUCCESS, "enabling DEP: status %08x\n", stat);
1406  }
1407 
1408  if(can_test_with)
1409  {
1410  /* Try access to locked page with DEP on*/
1411  info.exception_caught = FALSE;
1412  run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS);
1413  ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n");
1414  ok(info.exception_info == EXCEPTION_READ_FAULT ||
1415  info.exception_info == EXCEPTION_EXECUTE_FAULT,
1416  "Access violation type: %08x\n", (unsigned)info.exception_info);
1417  has_hw_support = info.exception_info == EXCEPTION_EXECUTE_FAULT;
1418  trace("DEP hardware support: %s\n", has_hw_support?"Yes":"No");
1419 
1420  /* Try execution of data with DEP on*/
1421  info.exception_caught = FALSE;
1422  run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE);
1423  if(has_hw_support)
1424  {
1425  ok(info.exception_caught == TRUE, "Execution of data memory succeeded\n");
1426  ok(info.exception_info == EXCEPTION_EXECUTE_FAULT,
1427  "Access violation type: %08x\n", (unsigned)info.exception_info);
1428  }
1429  else
1430  ok(info.exception_caught == FALSE, "Execution trapped without hardware support\n");
1431  }
1432  else
1433  skip("DEP is in AlwaysOff state\n");
1434 
1435  if(!is_permanent)
1436  {
1437  /* Disable DEP */
1439  stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
1440  ok(stat == STATUS_SUCCESS, "disabling DEP: status %08x\n", stat);
1441  }
1442 
1443  /* page is read without exec here */
1444  if(can_test_without)
1445  {
1446  /* Try execution of data with DEP off */
1447  info.exception_caught = FALSE;
1448  run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE);
1449  ok(info.exception_caught == FALSE, "Execution trapped with DEP turned off\n");
1450 
1451  /* Try access to locked page with DEP off - error code is different than
1452  with hardware DEP on */
1453  info.exception_caught = FALSE;
1454  run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS);
1455  ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n");
1456  ok(info.exception_info == EXCEPTION_READ_FAULT,
1457  "Access violation type: %08x\n", (unsigned)info.exception_info);
1458  }
1459  else
1460  skip("DEP is in AlwaysOn state\n");
1461 
1462  if(!is_permanent)
1463  {
1464  /* Turn off DEP permanently */
1466  stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
1467  ok(stat == STATUS_SUCCESS, "disabling DEP permanently: status %08x\n", stat);
1468  }
1469 
1470  /* Try to turn off DEP */
1472  stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
1473  ok(stat == STATUS_ACCESS_DENIED, "disabling DEP while permanent: status %08x\n", stat);
1474 
1475  /* Try to turn on DEP */
1477  stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
1478  ok(stat == STATUS_ACCESS_DENIED, "enabling DEP while permanent: status %08x\n", stat);
1479 }
1480 
1481 static void test_thread_context(void)
1482 {
1483  CONTEXT context;
1484  NTSTATUS status;
1485  struct expected
1486  {
1487  DWORD Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp, Esp, Eip,
1488  SegCs, SegDs, SegEs, SegFs, SegGs, SegSs, EFlags, prev_frame;
1489  } expect;
1490  NTSTATUS (*func_ptr)( struct expected *res, void *func, void *arg1, void *arg2 ) = (void *)code_mem;
1491 
1492  static const BYTE call_func[] =
1493  {
1494  0x55, /* pushl %ebp */
1495  0x89, 0xe5, /* mov %esp,%ebp */
1496  0x50, /* pushl %eax ; add a bit of offset to the stack */
1497  0x50, /* pushl %eax */
1498  0x50, /* pushl %eax */
1499  0x50, /* pushl %eax */
1500  0x8b, 0x45, 0x08, /* mov 0x8(%ebp),%eax */
1501  0x8f, 0x00, /* popl (%eax) */
1502  0x89, 0x58, 0x04, /* mov %ebx,0x4(%eax) */
1503  0x89, 0x48, 0x08, /* mov %ecx,0x8(%eax) */
1504  0x89, 0x50, 0x0c, /* mov %edx,0xc(%eax) */
1505  0x89, 0x70, 0x10, /* mov %esi,0x10(%eax) */
1506  0x89, 0x78, 0x14, /* mov %edi,0x14(%eax) */
1507  0x89, 0x68, 0x18, /* mov %ebp,0x18(%eax) */
1508  0x89, 0x60, 0x1c, /* mov %esp,0x1c(%eax) */
1509  0xff, 0x75, 0x04, /* pushl 0x4(%ebp) */
1510  0x8f, 0x40, 0x20, /* popl 0x20(%eax) */
1511  0x8c, 0x48, 0x24, /* mov %cs,0x24(%eax) */
1512  0x8c, 0x58, 0x28, /* mov %ds,0x28(%eax) */
1513  0x8c, 0x40, 0x2c, /* mov %es,0x2c(%eax) */
1514  0x8c, 0x60, 0x30, /* mov %fs,0x30(%eax) */
1515  0x8c, 0x68, 0x34, /* mov %gs,0x34(%eax) */
1516  0x8c, 0x50, 0x38, /* mov %ss,0x38(%eax) */
1517  0x9c, /* pushf */
1518  0x8f, 0x40, 0x3c, /* popl 0x3c(%eax) */
1519  0xff, 0x75, 0x00, /* pushl 0x0(%ebp) ; previous stack frame */
1520  0x8f, 0x40, 0x40, /* popl 0x40(%eax) */
1521  0x8b, 0x00, /* mov (%eax),%eax */
1522  0xff, 0x75, 0x14, /* pushl 0x14(%ebp) */
1523  0xff, 0x75, 0x10, /* pushl 0x10(%ebp) */
1524  0xff, 0x55, 0x0c, /* call *0xc(%ebp) */
1525  0xc9, /* leave */
1526  0xc3, /* ret */
1527  };
1528 
1529  memcpy( func_ptr, call_func, sizeof(call_func) );
1530 
1531 #define COMPARE(reg) \
1532  ok( context.reg == expect.reg, "wrong " #reg " %08x/%08x\n", context.reg, expect.reg )
1533 
1534  memset( &context, 0xcc, sizeof(context) );
1535  memset( &expect, 0xcc, sizeof(expect) );
1536  func_ptr( &expect, pRtlCaptureContext, &context, 0 );
1537  trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x "
1538  "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x prev=%08x\n",
1539  expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi,
1540  expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs,
1541  expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame );
1542  trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x "
1543  "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
1544  context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi,
1545  context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs, context.SegEs,
1546  context.SegFs, context.SegGs, context.SegSs, context.EFlags );
1547 
1548  ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) ||
1549  broken( context.ContextFlags == 0xcccccccc ), /* <= vista */
1550  "wrong flags %08x\n", context.ContextFlags );
1551  COMPARE( Eax );
1552  COMPARE( Ebx );
1553  COMPARE( Ecx );
1554  COMPARE( Edx );
1555  COMPARE( Esi );
1556  COMPARE( Edi );
1557  COMPARE( Eip );
1558  COMPARE( SegCs );
1559  COMPARE( SegDs );
1560  COMPARE( SegEs );
1561  COMPARE( SegFs );
1562  COMPARE( SegGs );
1563  COMPARE( SegSs );
1564  COMPARE( EFlags );
1565  /* Ebp is from the previous stackframe */
1566  ok( context.Ebp == expect.prev_frame, "wrong Ebp %08x/%08x\n", context.Ebp, expect.prev_frame );
1567  /* Esp is the value on entry to the previous stackframe */
1568  ok( context.Esp == expect.Ebp + 8, "wrong Esp %08x/%08x\n", context.Esp, expect.Ebp + 8 );
1569 
1570  memset( &context, 0xcc, sizeof(context) );
1571  memset( &expect, 0xcc, sizeof(expect) );
1573  status = func_ptr( &expect, pNtGetContextThread, (void *)GetCurrentThread(), &context );
1574  ok( status == STATUS_SUCCESS, "NtGetContextThread failed %08x\n", status );
1575  trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x "
1576  "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x prev=%08x\n",
1577  expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi,
1578  expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs,
1579  expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame );
1580  trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x "
1581  "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n",
1582  context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi,
1583  context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs, context.SegEs,
1584  context.SegFs, context.SegGs, context.SegSs, context.EFlags );
1585  /* Eax, Ecx, Edx, EFlags are not preserved */
1586  COMPARE( Ebx );
1587  COMPARE( Esi );
1588  COMPARE( Edi );
1589  COMPARE( Ebp );
1590  /* Esp is the stack upon entry to NtGetContextThread */
1591  ok( context.Esp == expect.Esp - 12 || context.Esp == expect.Esp - 16,
1592  "wrong Esp %08x/%08x\n", context.Esp, expect.Esp );
1593  /* Eip is somewhere close to the NtGetContextThread implementation */
1594  ok( (char *)context.Eip >= (char *)pNtGetContextThread - 0x10000 &&
1595  (char *)context.Eip <= (char *)pNtGetContextThread + 0x10000,
1596  "wrong Eip %08x/%08x\n", context.Eip, (DWORD)pNtGetContextThread );
1597  ok( *(WORD *)context.Eip == 0xc483 || *(WORD *)context.Eip == 0x08c2 || *(WORD *)context.Eip == 0x8dc3,
1598  "expected 0xc483 or 0x08c2 or 0x8dc3, got %04x\n", *(WORD *)context.Eip );
1599  /* segment registers clear the high word */
1600  ok( context.SegCs == LOWORD(expect.SegCs), "wrong SegCs %08x/%08x\n", context.SegCs, expect.SegCs );
1601  ok( context.SegDs == LOWORD(expect.SegDs), "wrong SegDs %08x/%08x\n", context.SegDs, expect.SegDs );
1602  ok( context.SegEs == LOWORD(expect.SegEs), "wrong SegEs %08x/%08x\n", context.SegEs, expect.SegEs );
1603  ok( context.SegFs == LOWORD(expect.SegFs), "wrong SegFs %08x/%08x\n", context.SegFs, expect.SegFs );
1604  ok( context.SegGs == LOWORD(expect.SegGs), "wrong SegGs %08x/%08x\n", context.SegGs, expect.SegGs );
1605  ok( context.SegSs == LOWORD(expect.SegSs), "wrong SegSs %08x/%08x\n", context.SegSs, expect.SegGs );
1606 #undef COMPARE
1607 }
1608 
1609 #elif defined(__x86_64__)
1610 
1611 #define is_wow64 0
1612 
1613 #ifndef __REACTOS__
1614 #define UNW_FLAG_NHANDLER 0
1615 #define UNW_FLAG_EHANDLER 1
1616 #define UNW_FLAG_UHANDLER 2
1617 #define UNW_FLAG_CHAININFO 4
1618 #endif // __REACTOS__
1619 
1620 #define UWOP_PUSH_NONVOL 0
1621 #define UWOP_ALLOC_LARGE 1
1622 #define UWOP_ALLOC_SMALL 2
1623 #define UWOP_SET_FPREG 3
1624 #define UWOP_SAVE_NONVOL 4
1625 #define UWOP_SAVE_NONVOL_FAR 5
1626 #define UWOP_SAVE_XMM128 8
1627 #define UWOP_SAVE_XMM128_FAR 9
1628 #define UWOP_PUSH_MACHFRAME 10
1629 
1630 struct results
1631 {
1632  int rip_offset; /* rip offset from code start */
1633  int rbp_offset; /* rbp offset from stack pointer */
1634  int handler; /* expect handler to be set? */
1635  int rip; /* expected final rip value */
1636  int frame; /* expected frame return value */
1637  int regs[8][2]; /* expected values for registers */
1638 };
1639 
1640 struct unwind_test
1641 {
1642  const BYTE *function;
1643  size_t function_size;
1644  const BYTE *unwind_info;
1645  const struct results *results;
1646  unsigned int nb_results;
1647 };
1648 
1649 enum regs
1650 {
1651  rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
1652  r8, r9, r10, r11, r12, r13, r14, r15
1653 };
1654 
1655 static const char * const reg_names[16] =
1656 {
1657  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1658  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1659 };
1660 
1661 #define UWOP(code,info) (UWOP_##code | ((info) << 4))
1662 
1663 static void call_virtual_unwind( int testnum, const struct unwind_test *test )
1664 {
1665  static const int code_offset = 1024;
1666  static const int unwind_offset = 2048;
1667  void *handler, *data;
1668  CONTEXT context;
1669  RUNTIME_FUNCTION runtime_func;
1670  KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
1671  UINT i, j, k;
1672  ULONG64 fake_stack[256];
1673  ULONG64 frame, orig_rip, orig_rbp, unset_reg;
1674  UINT unwind_size = 4 + 2 * test->unwind_info[2] + 8;
1675 
1676  memcpy( (char *)code_mem + code_offset, test->function, test->function_size );
1677  memcpy( (char *)code_mem + unwind_offset, test->unwind_info, unwind_size );
1678 
1679  runtime_func.BeginAddress = code_offset;
1680  runtime_func.EndAddress = code_offset + test->function_size;
1681  runtime_func.UnwindData = unwind_offset;
1682 
1683  trace( "code: %p stack: %p\n", code_mem, fake_stack );
1684 
1685  for (i = 0; i < test->nb_results; i++)
1686  {
1687  memset( &ctx_ptr, 0, sizeof(ctx_ptr) );
1688  memset( &context, 0x55, sizeof(context) );
1689  memset( &unset_reg, 0x55, sizeof(unset_reg) );
1690  for (j = 0; j < 256; j++) fake_stack[j] = j * 8;
1691 
1692  context.Rsp = (ULONG_PTR)fake_stack;
1693  context.Rbp = (ULONG_PTR)fake_stack + test->results[i].rbp_offset;
1694  orig_rbp = context.Rbp;
1695  orig_rip = (ULONG64)code_mem + code_offset + test->results[i].rip_offset;
1696 
1697  trace( "%u/%u: rip=%p (%02x) rbp=%p rsp=%p\n", testnum, i,
1698  (void *)orig_rip, *(BYTE *)orig_rip, (void *)orig_rbp, (void *)context.Rsp );
1699 
1700  data = (void *)0xdeadbeef;
1702  &runtime_func, &context, &data, &frame, &ctx_ptr );
1703  if (test->results[i].handler)
1704  {
1705  ok( (char *)handler == (char *)code_mem + 0x200,
1706  "%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 );
1707  if (handler) ok( *(DWORD *)data == 0x08070605,
1708  "%u/%u: wrong handler data %p\n", testnum, i, data );
1709  }
1710  else
1711  {
1712  ok( handler == NULL, "%u/%u: handler %p instead of NULL\n", testnum, i, handler );
1713  ok( data == (void *)0xdeadbeef, "%u/%u: handler data set to %p\n", testnum, i, data );
1714  }
1715 
1716  ok( context.Rip == test->results[i].rip, "%u/%u: wrong rip %p/%x\n",
1717  testnum, i, (void *)context.Rip, test->results[i].rip );
1718  ok( frame == (ULONG64)fake_stack + test->results[i].frame, "%u/%u: wrong frame %p/%p\n",
1719  testnum, i, (void *)frame, (char *)fake_stack + test->results[i].frame );
1720 
1721  for (j = 0; j < 16; j++)
1722  {
1723  static const UINT nb_regs = sizeof(test->results[i].regs) / sizeof(test->results[i].regs[0]);
1724 
1725  for (k = 0; k < nb_regs; k++)
1726  {
1727  if (test->results[i].regs[k][0] == -1)
1728  {
1729  k = nb_regs;
1730  break;
1731  }
1732  if (test->results[i].regs[k][0] == j) break;
1733  }
1734 
1735  if (j == rsp) /* rsp is special */
1736  {
1737 #ifndef __REACTOS__
1738  ok( !ctx_ptr.u2.IntegerContext[j],
1739  "%u/%u: rsp should not be set in ctx_ptr\n", testnum, i );
1740 #else
1741  ok(!ctx_ptr.IntegerContext[j],
1742  "%u/%u: rsp should not be set in ctx_ptr\n", testnum, i);
1743 #endif // __REACTOS__
1744 
1745  ok( context.Rsp == (ULONG64)fake_stack + test->results[i].regs[k][1],
1746  "%u/%u: register rsp wrong %p/%p\n",
1747  testnum, i, (void *)context.Rsp, (char *)fake_stack + test->results[i].regs[k][1] );
1748  continue;
1749  }
1750 
1751 #ifndef __REACTOS__
1752  if (ctx_ptr.u2.IntegerContext[j])
1753 #else
1754  if (ctx_ptr.IntegerContext[j])
1755 #endif // __REACTOS__
1756  {
1757  ok( k < nb_regs, "%u/%u: register %s should not be set to %lx\n",
1758  testnum, i, reg_names[j], *(&context.Rax + j) );
1759  if (k < nb_regs)
1760  ok( *(&context.Rax + j) == test->results[i].regs[k][1],
1761  "%u/%u: register %s wrong %p/%x\n",
1762  testnum, i, reg_names[j], (void *)*(&context.Rax + j), test->results[i].regs[k][1] );
1763  }
1764  else
1765  {
1766  ok( k == nb_regs, "%u/%u: register %s should be set\n", testnum, i, reg_names[j] );
1767  if (j == rbp)
1768  ok( context.Rbp == orig_rbp, "%u/%u: register rbp wrong %p/unset\n",
1769  testnum, i, (void *)context.Rbp );
1770  else
1771  ok( *(&context.Rax + j) == unset_reg,
1772  "%u/%u: register %s wrong %p/unset\n",
1773  testnum, i, reg_names[j], (void *)*(&context.Rax + j));
1774  }
1775  }
1776  }
1777 }
1778 
1779 static void test_virtual_unwind(void)
1780 {
1781  static const BYTE function_0[] =
1782  {
1783  0xff, 0xf5, /* 00: push %rbp */
1784  0x48, 0x81, 0xec, 0x10, 0x01, 0x00, 0x00, /* 02: sub $0x110,%rsp */
1785  0x48, 0x8d, 0x6c, 0x24, 0x30, /* 09: lea 0x30(%rsp),%rbp */
1786  0x48, 0x89, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 0e: mov %rbx,0xf0(%rbp) */
1787  0x48, 0x89, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 15: mov %rsi,0xf8(%rbp) */
1788  0x90, /* 1c: nop */
1789  0x48, 0x8b, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 1d: mov 0xf0(%rbp),%rbx */
1790  0x48, 0x8b, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 24: mov 0xf8(%rbp),%rsi */
1791  0x48, 0x8d, 0xa5, 0xe0, 0x00, 0x00, 0x00, /* 2b: lea 0xe0(%rbp),%rsp */
1792  0x5d, /* 32: pop %rbp */
1793  0xc3 /* 33: ret */
1794  };
1795 
1796  static const BYTE unwind_info_0[] =
1797  {
1798  1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
1799  0x1c, /* prolog size */
1800  8, /* opcode count */
1801  (0x03 << 4) | rbp, /* frame reg rbp offset 0x30 */
1802 
1803  0x1c, UWOP(SAVE_NONVOL, rsi), 0x25, 0, /* 1c: mov %rsi,0x128(%rsp) */
1804  0x15, UWOP(SAVE_NONVOL, rbx), 0x24, 0, /* 15: mov %rbx,0x120(%rsp) */
1805  0x0e, UWOP(SET_FPREG, rbp), /* 0e: lea 0x30(%rsp),rbp */
1806  0x09, UWOP(ALLOC_LARGE, 0), 0x22, 0, /* 09: sub $0x110,%rsp */
1807  0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
1808 
1809  0x00, 0x02, 0x00, 0x00, /* handler */
1810  0x05, 0x06, 0x07, 0x08, /* data */
1811  };
1812 
1813  static const struct results results_0[] =
1814  {
1815  /* offset rbp handler rip frame registers */
1816  { 0x00, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
1817  { 0x02, 0x40, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }},
1818  { 0x09, 0x40, FALSE, 0x118, 0x000, { {rsp,0x120}, {rbp,0x110}, {-1,-1} }},
1819  { 0x0e, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1} }},
1820  { 0x15, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {-1,-1} }},
1821  { 0x1c, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
1822  { 0x1d, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
1823  { 0x24, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
1824  { 0x2b, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1}}},
1825  { 0x32, 0x40, FALSE, 0x008, 0x010, { {rsp,0x010}, {rbp,0x000}, {-1,-1}}},
1826  { 0x33, 0x40, FALSE, 0x000, 0x010, { {rsp,0x008}, {-1,-1}}},
1827  };
1828 
1829 
1830  static const BYTE function_1[] =
1831  {
1832  0x53, /* 00: push %rbx */
1833  0x55, /* 01: push %rbp */
1834  0x56, /* 02: push %rsi */
1835  0x57, /* 03: push %rdi */
1836  0x41, 0x54, /* 04: push %r12 */
1837  0x48, 0x83, 0xec, 0x30, /* 06: sub $0x30,%rsp */
1838  0x90, 0x90, /* 0a: nop; nop */
1839  0x48, 0x83, 0xc4, 0x30, /* 0c: add $0x30,%rsp */
1840  0x41, 0x5c, /* 10: pop %r12 */
1841  0x5f, /* 12: pop %rdi */
1842  0x5e, /* 13: pop %rsi */
1843  0x5d, /* 14: pop %rbp */
1844  0x5b, /* 15: pop %rbx */
1845  0xc3 /* 16: ret */
1846  };
1847 
1848  static const BYTE unwind_info_1[] =
1849  {
1850  1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
1851  0x0a, /* prolog size */
1852  6, /* opcode count */
1853  0, /* frame reg */
1854 
1855  0x0a, UWOP(ALLOC_SMALL, 5), /* 0a: sub $0x30,%rsp */
1856  0x06, UWOP(PUSH_NONVOL, r12), /* 06: push %r12 */
1857  0x04, UWOP(PUSH_NONVOL, rdi), /* 04: push %rdi */
1858  0x03, UWOP(PUSH_NONVOL, rsi), /* 03: push %rsi */
1859  0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
1860  0x01, UWOP(PUSH_NONVOL, rbx), /* 01: push %rbx */
1861 
1862  0x00, 0x02, 0x00, 0x00, /* handler */
1863  0x05, 0x06, 0x07, 0x08, /* data */
1864  };
1865 
1866  static const struct results results_1[] =
1867  {
1868  /* offset rbp handler rip frame registers */
1869  { 0x00, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
1870  { 0x01, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
1871  { 0x02, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
1872  { 0x03, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
1873  { 0x04, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
1874  { 0x06, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
1875  { 0x0a, 0x50, TRUE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
1876  { 0x0c, 0x50, FALSE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
1877  { 0x10, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
1878  { 0x12, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
1879  { 0x13, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
1880  { 0x14, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
1881  { 0x15, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
1882  { 0x16, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
1883  };
1884 
1885  static const struct unwind_test tests[] =
1886  {
1887  { function_0, sizeof(function_0), unwind_info_0,
1888  results_0, sizeof(results_0)/sizeof(results_0[0]) },
1889  { function_1, sizeof(function_1), unwind_info_1,
1890  results_1, sizeof(results_1)/sizeof(results_1[0]) }
1891  };
1892  unsigned int i;
1893 
1894  for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
1895  call_virtual_unwind( i, &tests[i] );
1896 }
1897 
1898 static int consolidate_dummy_called;
1899 static PVOID CALLBACK test_consolidate_dummy(EXCEPTION_RECORD *rec)
1900 {
1901  CONTEXT *ctx = (CONTEXT *)rec->ExceptionInformation[1];
1902  consolidate_dummy_called = 1;
1903  ok(ctx->Rip == 0xdeadbeef, "test_consolidate_dummy failed for Rip, expected: 0xdeadbeef, got: %lx\n", ctx->Rip);
1904  return (PVOID)rec->ExceptionInformation[2];
1905 }
1906 
1907 static void test_restore_context(void)
1908 {
1909  SETJMP_FLOAT128 *fltsave;
1910  EXCEPTION_RECORD rec;
1911  _JUMP_BUFFER buf;
1912  CONTEXT ctx;
1913  int i, pass;
1914 
1915  if (!pRtlUnwindEx || !pRtlRestoreContext || !pRtlCaptureContext || !p_setjmp)
1916  {
1917  skip("RtlUnwindEx/RtlCaptureContext/RtlRestoreContext/_setjmp not found\n");
1918  return;
1919  }
1920 
1921  /* RtlRestoreContext(NULL, NULL); crashes on Windows */
1922 
1923  /* test simple case of capture and restore context */
1924  pass = 0;
1925  InterlockedIncrement(&pass); /* interlocked to prevent compiler from moving after capture */
1926  pRtlCaptureContext(&ctx);
1927  if (InterlockedIncrement(&pass) == 2) /* interlocked to prevent compiler from moving before capture */
1928  {
1929  pRtlRestoreContext(&ctx, NULL);
1930  ok(0, "shouldn't be reached\n");
1931  }
1932  else
1933  ok(pass < 4, "unexpected pass %d\n", pass);
1934 
1935  /* test with jmp using RltRestoreContext */
1936  pass = 0;
1938  RtlCaptureContext(&ctx);
1939  InterlockedIncrement(&pass); /* only called once */
1940  p_setjmp(&buf);
1942  if (pass == 3)
1943  {
1945  rec.NumberParameters = 1;
1946  rec.ExceptionInformation[0] = (DWORD64)&buf;
1947 
1948  /* uses buf.Rip instead of ctx.Rip */
1949  pRtlRestoreContext(&ctx, &rec);
1950  ok(0, "shouldn't be reached\n");
1951  }
1952  else if (pass == 4)
1953  {
1954  ok(buf.Rbx == ctx.Rbx, "longjmp failed for Rbx, expected: %lx, got: %lx\n", buf.Rbx, ctx.Rbx);
1955  ok(buf.Rsp == ctx.Rsp, "longjmp failed for Rsp, expected: %lx, got: %lx\n", buf.Rsp, ctx.Rsp);
1956  ok(buf.Rbp == ctx.Rbp, "longjmp failed for Rbp, expected: %lx, got: %lx\n", buf.Rbp, ctx.Rbp);
1957  ok(buf.Rsi == ctx.Rsi, "longjmp failed for Rsi, expected: %lx, got: %lx\n", buf.Rsi, ctx.Rsi);
1958  ok(buf.Rdi == ctx.Rdi, "longjmp failed for Rdi, expected: %lx, got: %lx\n", buf.Rdi, ctx.Rdi);
1959  ok(buf.R12 == ctx.R12, "longjmp failed for R12, expected: %lx, got: %lx\n", buf.R12, ctx.R12);
1960  ok(buf.R13 == ctx.R13, "longjmp failed for R13, expected: %lx, got: %lx\n", buf.R13, ctx.R13);
1961  ok(buf.R14 == ctx.R14, "longjmp failed for R14, expected: %lx, got: %lx\n", buf.R14, ctx.R14);
1962  ok(buf.R15 == ctx.R15, "longjmp failed for R15, expected: %lx, got: %lx\n", buf.R15, ctx.R15);
1963 
1964  fltsave = &buf.Xmm6;
1965  for (i = 0; i < 10; i++)
1966  {
1967 #ifndef __REACTOS__
1968  ok(fltsave[i].Part[0] == ctx.u.FltSave.XmmRegisters[i + 6].Low,
1969  "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
1970  fltsave[i].Part[0], ctx.u.FltSave.XmmRegisters[i + 6].Low);
1971 
1972  ok(fltsave[i].Part[1] == ctx.u.FltSave.XmmRegisters[i + 6].High,
1973  "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
1974  fltsave[i].Part[1], ctx.u.FltSave.XmmRegisters[i + 6].High);
1975 #else
1976  ok(fltsave[i].Part[0] == ctx.FltSave.XmmRegisters[i + 6].Low,
1977  "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
1978  fltsave[i].Part[0], ctx.FltSave.XmmRegisters[i + 6].Low);
1979 
1980  ok(fltsave[i].Part[1] == ctx.FltSave.XmmRegisters[i + 6].High,
1981  "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
1982  fltsave[i].Part[1], ctx.FltSave.XmmRegisters[i + 6].High);
1983 #endif
1984  }
1985  }
1986  else
1987  ok(0, "unexpected pass %d\n", pass);
1988 
1989  /* test with jmp through RtlUnwindEx */
1990  pass = 0;
1992  pRtlCaptureContext(&ctx);
1993  InterlockedIncrement(&pass); /* only called once */
1994  p_setjmp(&buf);
1996  if (pass == 3)
1997  {
1999  rec.NumberParameters = 1;
2000  rec.ExceptionInformation[0] = (DWORD64)&buf;
2001 
2002  /* uses buf.Rip instead of bogus 0xdeadbeef */
2003  pRtlUnwindEx((void*)buf.Rsp, (void*)0xdeadbeef, &rec, NULL, &ctx, NULL);
2004  ok(0, "shouldn't be reached\n");
2005  }
2006  else
2007  ok(pass == 4, "unexpected pass %d\n", pass);
2008 
2009 
2010  /* test with consolidate */
2011  pass = 0;
2013  RtlCaptureContext(&ctx);
2015  if (pass == 2)
2016  {
2018  rec.NumberParameters = 3;
2019  rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy;
2020  rec.ExceptionInformation[1] = (DWORD64)&ctx;
2021  rec.ExceptionInformation[2] = ctx.Rip;
2022  ctx.Rip = 0xdeadbeef;
2023 
2024  pRtlRestoreContext(&ctx, &rec);
2025  ok(0, "shouldn't be reached\n");
2026  }
2027  else if (pass == 3)
2028  ok(consolidate_dummy_called, "test_consolidate_dummy not called\n");
2029  else
2030  ok(0, "unexpected pass %d\n", pass);
2031 }
2032 
2033 static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID context )
2034 {
2035  static const int code_offset = 1024;
2036  static RUNTIME_FUNCTION runtime_func;
2037  (*(DWORD *)context)++;
2038 
2039  runtime_func.BeginAddress = code_offset + 16;
2040  runtime_func.EndAddress = code_offset + 32;
2041  runtime_func.UnwindData = 0;
2042  return &runtime_func;
2043 }
2044 
2045 static void test_dynamic_unwind(void)
2046 {
2047  static const int code_offset = 1024;
2048  char buf[sizeof(RUNTIME_FUNCTION) + 4];
2049  RUNTIME_FUNCTION *runtime_func, *func;
2050  ULONG_PTR table, base;
2051  DWORD count;
2052 
2053  /* Test RtlAddFunctionTable with aligned RUNTIME_FUNCTION pointer */
2054  runtime_func = (RUNTIME_FUNCTION *)buf;
2055  runtime_func->BeginAddress = code_offset;
2056  runtime_func->EndAddress = code_offset + 16;
2057  runtime_func->UnwindData = 0;
2058  ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
2059  "RtlAddFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
2060 
2061  /* Lookup function outside of any function table */
2062  base = 0xdeadbeef;
2063  func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
2064  ok( func == NULL,
2065  "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
2066  ok( !base || broken(base == 0xdeadbeef),
2067  "RtlLookupFunctionEntry modified base address, expected: 0, got: %lx\n", base );
2068 
2069  /* Test with pointer inside of our function */
2070  base = 0xdeadbeef;
2071  func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
2072  ok( func == runtime_func,
2073  "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
2074  ok( base == (ULONG_PTR)code_mem,
2075  "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
2076 
2077  /* Test RtlDeleteFunctionTable */
2078  ok( pRtlDeleteFunctionTable( runtime_func ),
2079  "RtlDeleteFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
2080  ok( !pRtlDeleteFunctionTable( runtime_func ),
2081  "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
2082 
2083  /* Unaligned RUNTIME_FUNCTION pointer */
2084  runtime_func = (RUNTIME_FUNCTION *)((ULONG_PTR)buf | 0x3);
2085  runtime_func->BeginAddress = code_offset;
2086  runtime_func->EndAddress = code_offset + 16;
2087  runtime_func->UnwindData = 0;
2088  ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
2089  "RtlAddFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
2090  ok( pRtlDeleteFunctionTable( runtime_func ),
2091  "RtlDeleteFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
2092 
2093  /* Attempt to insert the same entry twice */
2094  runtime_func = (RUNTIME_FUNCTION *)buf;
2095  runtime_func->BeginAddress = code_offset;
2096  runtime_func->EndAddress = code_offset + 16;
2097  runtime_func->UnwindData = 0;
2098  ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
2099  "RtlAddFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
2100  ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
2101  "RtlAddFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
2102  ok( pRtlDeleteFunctionTable( runtime_func ),
2103  "RtlDeleteFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
2104  ok( pRtlDeleteFunctionTable( runtime_func ),
2105  "RtlDeleteFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
2106  ok( !pRtlDeleteFunctionTable( runtime_func ),
2107  "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
2108 
2109  /* Test RtlInstallFunctionTableCallback with both low bits unset */
2111  ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
2112  "RtlInstallFunctionTableCallback returned success for table = %lx\n", table );
2113 
2114  /* Test RtlInstallFunctionTableCallback with both low bits set */
2115  table = (ULONG_PTR)code_mem | 0x3;
2116  ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
2117  "RtlInstallFunctionTableCallback failed for table = %lx\n", table );
2118 
2119  /* Lookup function outside of any function table */
2120  count = 0;
2121  base = 0xdeadbeef;
2122  func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &base, NULL );
2123  ok( func == NULL,
2124  "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
2125  ok( !base || broken(base == 0xdeadbeef),
2126  "RtlLookupFunctionEntry modified base address, expected: 0, got: %lx\n", base );
2127  ok( !count,
2128  "RtlLookupFunctionEntry issued %d unexpected calls to dynamic_unwind_callback\n", count );
2129 
2130  /* Test with pointer inside of our function */
2131  count = 0;
2132  base = 0xdeadbeef;
2133  func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 24, &base, NULL );
2134  ok( func != NULL && func->BeginAddress == code_offset + 16 && func->EndAddress == code_offset + 32,
2135  "RtlLookupFunctionEntry didn't return expected function, got: %p\n", func );
2136  ok( base == (ULONG_PTR)code_mem,
2137  "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
2138  ok( count == 1,
2139  "RtlLookupFunctionEntry issued %d calls to dynamic_unwind_callback, expected: 1\n", count );
2140 
2141  /* Clean up again */
2142  ok( pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
2143  "RtlDeleteFunctionTable failed for table = %p\n", (PVOID)table );
2144  ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
2145  "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table );
2146 
2147 }
2148 
2149 static int termination_handler_called;
2150 static void WINAPI termination_handler(ULONG flags, ULONG64 frame)
2151 {
2152  termination_handler_called++;
2153 
2154  ok(flags == 1 || broken(flags == 0x401), "flags = %x\n", flags);
2155  ok(frame == 0x1234, "frame = %p\n", (void*)frame);
2156 }
2157 
2158 static void test___C_specific_handler(void)
2159 {
2161  EXCEPTION_RECORD rec;
2162  CONTEXT context;
2163  ULONG64 frame;
2165  SCOPE_TABLE scope_table;
2166 
2167  if (!p__C_specific_handler)
2168  {
2169  win_skip("__C_specific_handler not available\n");
2170  return;
2171  }
2172 
2173  memset(&rec, 0, sizeof(rec));
2174  rec.ExceptionFlags = 2; /* EH_UNWINDING */
2175  frame = 0x1234;
2176  memset(&dispatch, 0, sizeof(dispatch));
2177 #ifndef __REACTOS__
2178  dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL);
2179  dispatch.ControlPc = dispatch.ImageBase + 0x200;
2180 #else
2181  dispatch.ImageBase = GetModuleHandleA(NULL);
2182  dispatch.ControlPc = (ULONG_PTR)dispatch.ImageBase + 0x200;
2183 #endif
2184  dispatch.HandlerData = &scope_table;
2185  dispatch.ContextRecord = &context;
2186  scope_table.Count = 1;
2187  scope_table.ScopeRecord[0].BeginAddress = 0x200;
2188  scope_table.ScopeRecord[0].EndAddress = 0x400;
2189 #ifndef __REACTOS__
2190  scope_table.ScopeRecord[0].HandlerAddress = (ULONG_PTR)termination_handler-dispatch.ImageBase;
2191 #else
2192  scope_table.ScopeRecord[0].HandlerAddress = ((ULONG_PTR)termination_handler - (ULONG_PTR)dispatch.ImageBase);
2193 #endif
2194  scope_table.ScopeRecord[0].JumpTarget = 0;
2195  memset(&context, 0, sizeof(context));
2196 
2197  termination_handler_called = 0;
2198  ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
2199  ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
2200  ok(termination_handler_called == 1, "termination_handler_called = %d\n",
2201  termination_handler_called);
2202  ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
2203 
2204  ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
2205  ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret);
2206  ok(termination_handler_called == 1, "termination_handler_called = %d\n",
2207  termination_handler_called);
2208  ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex);
2209 }
2210 
2211 #endif /* __x86_64__ */
2212 
2213 #if defined(__i386__) || defined(__x86_64__)
2214 
2215 static DWORD WINAPI register_check_thread(void *arg)
2216 {
2217  NTSTATUS status;
2218  CONTEXT ctx;
2219 
2220  memset(&ctx, 0, sizeof(ctx));
2222 
2223  status = pNtGetContextThread(GetCurrentThread(), &ctx);
2224  ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status);
2225  ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0);
2226  ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
2227  ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
2228  ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
2229  ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
2230  ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
2231 
2232  return 0;
2233 }
2234 
2235 static void test_debug_registers(void)
2236 {
2237  static const struct
2238  {
2239  ULONG_PTR dr0, dr1, dr2, dr3, dr6, dr7;
2240  }
2241  tests[] =
2242  {
2243  { 0x42424240, 0, 0x126bb070, 0x0badbad0, 0, 0xffff0115 },
2244  { 0x42424242, 0, 0x100f0fe7, 0x0abebabe, 0, 0x115 },
2245  };
2246  NTSTATUS status;
2247  CONTEXT ctx;
2248  HANDLE thread;
2249  int i;
2250 
2251  for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
2252  {
2253  memset(&ctx, 0, sizeof(ctx));
2255  ctx.Dr0 = tests[i].dr0;
2256  ctx.Dr1 = tests[i].dr1;
2257  ctx.Dr2 = tests[i].dr2;
2258  ctx.Dr3 = tests[i].dr3;
2259  ctx.Dr6 = tests[i].dr6;
2260  ctx.Dr7 = tests[i].dr7;
2261 
2262  status = pNtSetContextThread(GetCurrentThread(), &ctx);
2263  ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status);
2264 
2265  memset(&ctx, 0, sizeof(ctx));
2267 
2268  status = pNtGetContextThread(GetCurrentThread(), &ctx);
2269  ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status);
2270  ok(ctx.Dr0 == tests[i].dr0, "test %d: expected %lx, got %lx\n", i, tests[i].dr0, (DWORD_PTR)ctx.Dr0);
2271  ok(ctx.Dr1 == tests[i].dr1, "test %d: expected %lx, got %lx\n", i, tests[i].dr1, (DWORD_PTR)ctx.Dr1);
2272  ok(ctx.Dr2 == tests[i].dr2, "test %d: expected %lx, got %lx\n", i, tests[i].dr2, (DWORD_PTR)ctx.Dr2);
2273  ok(ctx.Dr3 == tests[i].dr3, "test %d: expected %lx, got %lx\n", i, tests[i].dr3, (DWORD_PTR)ctx.Dr3);
2274  ok((ctx.Dr6 & 0xf00f) == tests[i].dr6, "test %d: expected %lx, got %lx\n", i, tests[i].dr6, (DWORD_PTR)ctx.Dr6);
2275  ok((ctx.Dr7 & ~0xdc00) == tests[i].dr7, "test %d: expected %lx, got %lx\n", i, tests[i].dr7, (DWORD_PTR)ctx.Dr7);
2276  }
2277 
2278  memset(&ctx, 0, sizeof(ctx));
2280  ctx.Dr0 = 0xffffffff;
2281  ctx.Dr1 = 0xffffffff;
2282  ctx.Dr2 = 0xffffffff;
2283  ctx.Dr3 = 0xffffffff;
2284  ctx.Dr6 = 0xffffffff;
2285  ctx.Dr7 = 0x00000400;
2286  status = pNtSetContextThread(GetCurrentThread(), &ctx);
2287  ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", status);
2288 
2289  thread = CreateThread(NULL, 0, register_check_thread, NULL, CREATE_SUSPENDED, NULL);
2290  ok(thread != INVALID_HANDLE_VALUE, "CreateThread failed with %d\n", GetLastError());
2291 
2293  status = pNtGetContextThread(thread, &ctx);
2294  ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status);
2295  ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0);
2296  ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
2297  ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
2298  ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
2299  ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
2300  ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
2301 
2303  WaitForSingleObject(thread, 10000);
2305 }
2306 
2307 static DWORD outputdebugstring_exceptions;
2308 
2309 static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
2310 {
2311  PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
2312  trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
2313 
2314  ok(rec->ExceptionCode == DBG_PRINTEXCEPTION_C, "ExceptionCode is %08x instead of %08x\n",
2316  ok(rec->NumberParameters == 2, "ExceptionParameters is %d instead of 2\n", rec->NumberParameters);
2317  ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %d instead of 12\n", (DWORD)rec->ExceptionInformation[0]);
2318  ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"),
2319  "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]);
2320 
2321  outputdebugstring_exceptions++;
2323 }
2324 
2325 static void test_outputdebugstring(DWORD numexc)
2326 {
2327  PVOID vectored_handler;
2328 
2329  if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler)
2330  {
2331  skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n");
2332  return;
2333  }
2334 
2335  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &outputdebugstring_vectored_handler);
2336  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
2337 
2338  outputdebugstring_exceptions = 0;
2339  OutputDebugStringA("Hello World");
2340 
2341  ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
2342  outputdebugstring_exceptions, numexc);
2343 
2344  pRtlRemoveVectoredExceptionHandler(vectored_handler);
2345 }
2346 
2347 static DWORD ripevent_exceptions;
2348 
2349 static LONG CALLBACK ripevent_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
2350 {
2351  PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
2352  trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
2353 
2354  ok(rec->ExceptionCode == DBG_RIPEXCEPTION, "ExceptionCode is %08x instead of %08x\n",
2356  ok(rec->NumberParameters == 2, "ExceptionParameters is %d instead of 2\n", rec->NumberParameters);
2357  ok(rec->ExceptionInformation[0] == 0x11223344, "ExceptionInformation[0] = %08x instead of %08x\n",
2358  (NTSTATUS)rec->ExceptionInformation[0], 0x11223344);
2359  ok(rec->ExceptionInformation[1] == 0x55667788, "ExceptionInformation[1] = %08x instead of %08x\n",
2360  (NTSTATUS)rec->ExceptionInformation[1], 0x55667788);
2361 
2362  ripevent_exceptions++;
2364 }
2365 
2366 static void test_ripevent(DWORD numexc)
2367 {
2369  PVOID vectored_handler;
2370 
2371  if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler || !pRtlRaiseException)
2372  {
2373  skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler or RtlRaiseException not found\n");
2374  return;
2375  }
2376 
2377  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &ripevent_vectored_handler);
2378  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
2379 
2380  record.ExceptionCode = DBG_RIPEXCEPTION;
2381  record.ExceptionFlags = 0;
2382  record.ExceptionRecord = NULL;
2383  record.ExceptionAddress = NULL;
2384  record.NumberParameters = 2;
2385  record.ExceptionInformation[0] = 0x11223344;
2386  record.ExceptionInformation[1] = 0x55667788;
2387 
2388  ripevent_exceptions = 0;
2389  pRtlRaiseException(&record);
2390  ok(ripevent_exceptions == numexc, "RtlRaiseException generated %d exceptions, expected %d\n",
2391  ripevent_exceptions, numexc);
2392 
2393  pRtlRemoveVectoredExceptionHandler(vectored_handler);
2394 }
2395 
2396 static DWORD debug_service_exceptions;
2397 
2398 static LONG CALLBACK debug_service_handler(EXCEPTION_POINTERS *ExceptionInfo)
2399 {
2400  EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord;
2401  trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
2402 
2403  ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead of %08x\n",
2405 
2406 #ifdef __i386__
2407  ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 0x1c,
2408  "expected Eip = %x, got %x\n", (DWORD)code_mem + 0x1c, ExceptionInfo->ContextRecord->Eip);
2409  ok(rec->NumberParameters == (is_wow64 ? 1 : 3),
2410  "ExceptionParameters is %d instead of %d\n", rec->NumberParameters, is_wow64 ? 1 : 3);
2411  ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Eax,
2412  "expected ExceptionInformation[0] = %x, got %lx\n",
2413  ExceptionInfo->ContextRecord->Eax, rec->ExceptionInformation[0]);
2414  if (!is_wow64)
2415  {
2416  ok(rec->ExceptionInformation[1] == 0x11111111,
2417  "got ExceptionInformation[1] = %lx\n", rec->ExceptionInformation[1]);
2418  ok(rec->ExceptionInformation[2] == 0x22222222,
2419  "got ExceptionInformation[2] = %lx\n", rec->ExceptionInformation[2]);
2420  }
2421 #else
2422  ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 0x2f,
2423  "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 0x2f, ExceptionInfo->ContextRecord->Rip);
2424  ok(rec->NumberParameters == 1,
2425  "ExceptionParameters is %d instead of 1\n", rec->NumberParameters);
2426  ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Rax,
2427  "expected ExceptionInformation[0] = %lx, got %lx\n",
2428  ExceptionInfo->ContextRecord->Rax, rec->ExceptionInformation[0]);
2429 #endif
2430 
2431  debug_service_exceptions++;
2433 }
2434 
2435 #ifdef __i386__
2436 
2437 static const BYTE call_debug_service_code[] = {
2438  0x53, /* pushl %ebx */
2439  0x57, /* pushl %edi */
2440  0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */
2441  0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */
2442  0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */
2443  0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */
2444  0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */
2445  0xcd, 0x2d, /* int $0x2d */
2446  0xeb, /* jmp $+17 */
2447  0x0f, 0x1f, 0x00, /* nop */
2448  0x31, 0xc0, /* xorl %eax,%eax */
2449  0xeb, 0x0c, /* jmp $+14 */
2450  0x90, 0x90, 0x90, 0x90, /* nop */
2451  0x90, 0x90, 0x90, 0x90,
2452  0x90,
2453  0x31, 0xc0, /* xorl %eax,%eax */
2454  0x40, /* incl %eax */
2455  0x5f, /* popl %edi */
2456  0x5b, /* popl %ebx */
2457  0xc3, /* ret */
2458 };
2459 
2460 #else
2461 
2462 static const BYTE call_debug_service_code[] = {
2463  0x53, /* push %rbx */
2464  0x57, /* push %rdi */
2465  0x48, 0x89, 0xc8, /* movl %rcx,%rax */
2466  0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs $0x1111111111111111,%rcx */
2467  0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs $0x2222222222222222,%rdx */
2468  0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs $0x3333333333333333,%rbx */
2469  0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs $0x4444444444444444,%rdi */
2470  0xcd, 0x2d, /* int $0x2d */
2471  0xeb, /* jmp $+17 */
2472  0x0f, 0x1f, 0x00, /* nop */
2473  0x48, 0x31, 0xc0, /* xor %rax,%rax */
2474  0xeb, 0x0e, /* jmp $+16 */
2475  0x90, 0x90, 0x90, 0x90, /* nop */
2476  0x90, 0x90, 0x90, 0x90,
2477  0x48, 0x31, 0xc0, /* xor %rax,%rax */
2478  0x48, 0xff, 0xc0, /* inc %rax */
2479  0x5f, /* pop %rdi */
2480  0x5b, /* pop %rbx */
2481  0xc3, /* ret */
2482 };
2483 
2484 #endif
2485 
2486 static void test_debug_service(DWORD numexc)
2487 {
2489  DWORD expected_exc, expected_ret;
2490  void *vectored_handler;
2491  DWORD ret;
2492 
2493  /* code will return 0 if execution resumes immediately after "int $0x2d", otherwise 1 */
2494  memcpy(code_mem, call_debug_service_code, sizeof(call_debug_service_code));
2495 
2496  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &debug_service_handler);
2497  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
2498 
2499  expected_exc = numexc;
2500  expected_ret = (numexc != 0);
2501 
2502  /* BREAKPOINT_BREAK */
2503  debug_service_exceptions = 0;
2504  ret = func(0);
2505  ok(debug_service_exceptions == expected_exc,
2506  "BREAKPOINT_BREAK generated %u exceptions, expected %u\n",
2507  debug_service_exceptions, expected_exc);
2508  ok(ret == expected_ret,
2509  "BREAKPOINT_BREAK returned %u, expected %u\n", ret, expected_ret);
2510 
2511  /* BREAKPOINT_PROMPT */
2512  debug_service_exceptions = 0;
2513  ret = func(2);
2514  ok(debug_service_exceptions == expected_exc,
2515  "BREAKPOINT_PROMPT generated %u exceptions, expected %u\n",
2516  debug_service_exceptions, expected_exc);
2517  ok(ret == expected_ret,
2518  "BREAKPOINT_PROMPT returned %u, expected %u\n", ret, expected_ret);
2519 
2520  /* invalid debug service */
2521  debug_service_exceptions = 0;
2522  ret = func(6);
2523  ok(debug_service_exceptions == expected_exc,
2524  "invalid debug service generated %u exceptions, expected %u\n",
2525  debug_service_exceptions, expected_exc);
2526  ok(ret == expected_ret,
2527  "invalid debug service returned %u, expected %u\n", ret, expected_ret);
2528 
2529  expected_exc = (is_wow64 ? numexc : 0);
2530  expected_ret = (is_wow64 && numexc);
2531 
2532  /* BREAKPOINT_PRINT */
2533  debug_service_exceptions = 0;
2534  ret = func(1);
2535  ok(debug_service_exceptions == expected_exc,
2536  "BREAKPOINT_PRINT generated %u exceptions, expected %u\n",
2537  debug_service_exceptions, expected_exc);
2538  ok(ret == expected_ret,
2539  "BREAKPOINT_PRINT returned %u, expected %u\n", ret, expected_ret);
2540 
2541  /* BREAKPOINT_LOAD_SYMBOLS */
2542  debug_service_exceptions = 0;
2543  ret = func(3);
2544  ok(debug_service_exceptions == expected_exc,
2545  "BREAKPOINT_LOAD_SYMBOLS generated %u exceptions, expected %u\n",
2546  debug_service_exceptions, expected_exc);
2547  ok(ret == expected_ret,
2548  "BREAKPOINT_LOAD_SYMBOLS returned %u, expected %u\n", ret, expected_ret);
2549 
2550  /* BREAKPOINT_UNLOAD_SYMBOLS */
2551  debug_service_exceptions = 0;
2552  ret = func(4);
2553  ok(debug_service_exceptions == expected_exc,
2554  "BREAKPOINT_UNLOAD_SYMBOLS generated %u exceptions, expected %u\n",
2555  debug_service_exceptions, expected_exc);
2556  ok(ret == expected_ret,
2557  "BREAKPOINT_UNLOAD_SYMBOLS returned %u, expected %u\n", ret, expected_ret);
2558 
2559  /* BREAKPOINT_COMMAND_STRING */
2560  debug_service_exceptions = 0;
2561  ret = func(5);
2562  ok(debug_service_exceptions == expected_exc || broken(debug_service_exceptions == numexc),
2563  "BREAKPOINT_COMMAND_STRING generated %u exceptions, expected %u\n",
2564  debug_service_exceptions, expected_exc);
2565  ok(ret == expected_ret || broken(ret == (numexc != 0)),
2566  "BREAKPOINT_COMMAND_STRING returned %u, expected %u\n", ret, expected_ret);
2567 
2568  pRtlRemoveVectoredExceptionHandler(vectored_handler);
2569 }
2570 
2571 static DWORD breakpoint_exceptions;
2572 
2573 static LONG CALLBACK breakpoint_handler(EXCEPTION_POINTERS *ExceptionInfo)
2574 {
2575  EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord;
2576  trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
2577 
2578  ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead of %08x\n",
2580 
2581 #ifdef __i386__
2582  ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 1,
2583  "expected Eip = %x, got %x\n", (DWORD)code_mem + 1, ExceptionInfo->ContextRecord->Eip);
2584  ok(rec->NumberParameters == (is_wow64 ? 1 : 3),
2585  "ExceptionParameters is %d instead of %d\n", rec->NumberParameters, is_wow64 ? 1 : 3);
2586  ok(rec->ExceptionInformation[0] == 0,
2587  "got ExceptionInformation[0] = %lx\n", rec->ExceptionInformation[0]);
2588  ExceptionInfo->ContextRecord->Eip = (DWORD)code_mem + 2;
2589 #else
2590  ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 1,
2591  "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 1, ExceptionInfo->ContextRecord->Rip);
2592  ok(rec->NumberParameters == 1,
2593  "ExceptionParameters is %d instead of 1\n", rec->NumberParameters);
2594  ok(rec->ExceptionInformation[0] == 0,
2595  "got ExceptionInformation[0] = %lx\n", rec->ExceptionInformation[0]);
2596  ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)code_mem + 2;
2597 #endif
2598 
2599  breakpoint_exceptions++;
2601 }
2602 
2603 static const BYTE breakpoint_code[] = {
2604  0xcd, 0x03, /* int $0x3 */
2605  0xc3, /* ret */
2606 };
2607 
2608 static void test_breakpoint(DWORD numexc)
2609 {
2610  DWORD (CDECL *func)(void) = code_mem;
2611  void *vectored_handler;
2612 
2613  memcpy(code_mem, breakpoint_code, sizeof(breakpoint_code));
2614 
2615  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &breakpoint_handler);
2616  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
2617 
2618  breakpoint_exceptions = 0;
2619  func();
2620  ok(breakpoint_exceptions == numexc, "int $0x3 generated %u exceptions, expected %u\n",
2621  breakpoint_exceptions, numexc);
2622 
2623  pRtlRemoveVectoredExceptionHandler(vectored_handler);
2624 }
2625 
2626 static DWORD invalid_handle_exceptions;
2627 
2628 static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
2629 {
2630  PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
2631  trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
2632 
2633  ok(rec->ExceptionCode == EXCEPTION_INVALID_HANDLE, "ExceptionCode is %08x instead of %08x\n",
2635  ok(rec->NumberParameters == 0, "ExceptionParameters is %d instead of 0\n", rec->NumberParameters);
2636 
2637  invalid_handle_exceptions++;
2639 }
2640 
2641 static void test_closehandle(DWORD numexc)
2642 {
2643  PVOID vectored_handler;
2644  NTSTATUS status;
2645  DWORD res;
2646 
2647  if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler || !pRtlRaiseException)
2648  {
2649  skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler or RtlRaiseException not found\n");
2650  return;
2651  }
2652 
2653  vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &invalid_handle_vectored_handler);
2654  ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
2655 
2656  invalid_handle_exceptions = 0;
2657  res = CloseHandle((HANDLE)0xdeadbeef);
2658  ok(!res, "CloseHandle(0xdeadbeef) unexpectedly succeeded\n");
2659  ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d\n",
2661  ok(invalid_handle_exceptions == numexc, "CloseHandle generated %d exceptions, expected %d\n",
2662  invalid_handle_exceptions, numexc);
2663 
2664  invalid_handle_exceptions = 0;
2665  status = pNtClose((HANDLE)0xdeadbeef);
2666  ok(status == STATUS_INVALID_HANDLE, "NtClose(0xdeadbeef) returned status %08x\n", status);
2667  ok(invalid_handle_exceptions == numexc, "NtClose generated %d exceptions, expected %d\n",
2668  invalid_handle_exceptions, numexc);
2669 
2670  pRtlRemoveVectoredExceptionHandler(vectored_handler);
2671 }
2672 
2673 static void test_vectored_continue_handler(void)
2674 {
2675  PVOID handler1, handler2;
2676  ULONG ret;
2677 
2678  if (!pRtlAddVectoredContinueHandler || !pRtlRemoveVectoredContinueHandler)
2679  {
2680  skip("RtlAddVectoredContinueHandler or RtlRemoveVectoredContinueHandler not found\n");
2681  return;
2682  }
2683 
2684  handler1 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
2685  ok(handler1 != 0, "RtlAddVectoredContinueHandler failed\n");
2686 
2687  handler2 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
2688  ok(handler2 != 0, "RtlAddVectoredContinueHandler failed\n");
2689  ok(handler1 != handler2, "RtlAddVectoredContinueHandler returned same handler\n");
2690 
2691  if (pRtlRemoveVectoredExceptionHandler)
2692  {
2693  ret = pRtlRemoveVectoredExceptionHandler(handler1);
2694  ok(!ret, "RtlRemoveVectoredExceptionHandler succeeded\n");
2695  }
2696 
2697  ret = pRtlRemoveVectoredContinueHandler(handler1);
2698  ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
2699 
2700  ret = pRtlRemoveVectoredContinueHandler(handler2);
2701  ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
2702 
2703  ret = pRtlRemoveVectoredContinueHandler(handler1);
2704  ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
2705 
2706  ret = pRtlRemoveVectoredContinueHandler((void *)0x11223344);
2707  ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
2708 }
2709 #endif /* defined(__i386__) || defined(__x86_64__) */
2710 
2712 {
2713  HMODULE hntdll = GetModuleHandleA("ntdll.dll");
2714 #if defined(__x86_64__)
2715  HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll");
2716 #endif
2717 
2718 #ifdef __REACTOS__
2719  if (!winetest_interactive &&
2720  !strcmp(winetest_platform, "windows"))
2721  {
2722  skip("ROSTESTS-240: Skipping ntdll_winetest:exception because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
2723  return;
2724  }
2725 #endif
2727  if(!code_mem) {
2728  trace("VirtualAlloc failed\n");
2729  return;
2730  }
2731 
2732  pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" );
2733  pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" );
2734  pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" );
2735  pNtClose = (void *)GetProcAddress( hntdll, "NtClose" );
2736  pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" );
2737  pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" );
2738  pRtlCaptureContext = (void *)GetProcAddress( hntdll, "RtlCaptureContext" );
2739  pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" );
2740  pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
2741  "RtlAddVectoredExceptionHandler" );
2742  pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
2743  "RtlRemoveVectoredExceptionHandler" );
2744  pRtlAddVectoredContinueHandler = (void *)GetProcAddress( hntdll,
2745  "RtlAddVectoredContinueHandler" );
2746  pRtlRemoveVectoredContinueHandler = (void *)GetProcAddress( hntdll,
2747  "RtlRemoveVectoredContinueHandler" );
2748  pNtQueryInformationProcess = (void*)GetProcAddress( hntdll,
2749  "NtQueryInformationProcess" );
2750  pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
2751  "NtSetInformationProcess" );
2752  pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
2753 
2754 #ifdef __i386__
2755  if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2756 
2757  if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
2758  have_vectored_api = TRUE;
2759  else
2760  skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n");
2761 
2762  my_argc = winetest_get_mainargs( &my_argv );
2763  if (my_argc >= 4)
2764  {
2765  void *addr;
2766  sscanf( my_argv[3], "%p", &addr );
2767 
2768  if (addr != &test_stage)
2769  {
2770  skip( "child process not mapped at same address (%p/%p)\n", &test_stage, addr);
2771  return;
2772  }
2773 
2774  /* child must be run under a debugger */
2775  if (!NtCurrentTeb()->Peb->BeingDebugged)
2776  {
2777  ok(FALSE, "child process not being debugged?\n");
2778  return;
2779  }
2780 
2781  if (pRtlRaiseException)
2782  {
2783  test_stage = 1;
2784  run_rtlraiseexception_test(0x12345);
2785  run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
2786  run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
2787  test_stage = 2;
2788  run_rtlraiseexception_test(0x12345);
2789  run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
2790  run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
2791  test_stage = 3;
2792  test_outputdebugstring(0);
2793  test_stage = 4;
2794  test_outputdebugstring(2);
2795  test_stage = 5;
2796  test_ripevent(0);
2797  test_stage = 6;
2798  test_ripevent(1);
2799  test_stage = 7;
2800  test_debug_service(0);
2801  test_stage = 8;
2802  test_debug_service(1);
2803  test_stage = 9;
2804  test_breakpoint(0);
2805  test_stage = 10;
2806  test_breakpoint(1);
2807  test_stage = 11;
2808  test_closehandle(0);
2809  test_stage = 12;
2810  test_closehandle(1);
2811  }
2812  else
2813  skip( "RtlRaiseException not found\n" );
2814 
2815  /* rest of tests only run in parent */
2816  return;
2817  }
2818 
2819  test_unwind();
2820  test_exceptions();
2821  test_rtlraiseexception();
2822  test_debug_registers();
2823  test_outputdebugstring(1);
2824  test_ripevent(1);
2825  test_debug_service(1);
2826  test_breakpoint(1);
2827  test_closehandle(0);
2828  test_vectored_continue_handler();
2829  test_debugger();
2830  test_simd_exceptions();
2831  test_fpu_exceptions();
2832  test_dpe_exceptions();
2833  test_prot_fault();
2834  test_thread_context();
2835 
2836 #elif defined(__x86_64__)
2837  pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
2838  "RtlAddFunctionTable" );
2839  pRtlDeleteFunctionTable = (void *)GetProcAddress( hntdll,
2840  "RtlDeleteFunctionTable" );
2841  pRtlInstallFunctionTableCallback = (void *)GetProcAddress( hntdll,
2842  "RtlInstallFunctionTableCallback" );
2843  pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
2844  "RtlLookupFunctionEntry" );
2845  p__C_specific_handler = (void *)GetProcAddress( hntdll,
2846  "__C_specific_handler" );
2847  pRtlCaptureContext = (void *)GetProcAddress( hntdll,
2848  "RtlCaptureContext" );
2849  pRtlRestoreContext = (void *)GetProcAddress( hntdll,
2850  "RtlRestoreContext" );
2851  pRtlUnwindEx = (void *)GetProcAddress( hntdll,
2852  "RtlUnwindEx" );
2853  p_setjmp = (void *)GetProcAddress( hmsvcrt,
2854  "_setjmp" );
2855 
2856  test_debug_registers();
2857  test_outputdebugstring(1);
2858  test_ripevent(1);
2859  test_debug_service(1);
2860  test_breakpoint(1);
2861  test_closehandle(0);
2862  test_vectored_continue_handler();
2863  test_virtual_unwind();
2864  test___C_specific_handler();
2865  test_restore_context();
2866 
2867  if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
2868  test_dynamic_unwind();
2869  else
2870  skip( "Dynamic unwind functions not found\n" );
2871 
2872 #endif
2873 
2875 }
GLenum func
Definition: glext.h:6028
#define STATUS_UNWIND_CONSOLIDATE
Definition: ntstatus.h:208
RIP_INFO RipInfo
Definition: winbase.h:778
#define CONTEXT_CONTROL
Definition: nt_native.h:1369
const uint16_t * PCWSTR
Definition: typedefs.h:55
struct param_test tests[]
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
#define STATUS_ILLEGAL_INSTRUCTION
Definition: ntstatus.h:252
PPEB Peb
Definition: dllmain.c:27
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define DWORD_PTR
Definition: treelist.c:76
ULONG Eip
Definition: nt_native.h:1476
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:660
DWORD dwThreadId
Definition: winbase.h:768
Definition: http.c:6587
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
START_TEST(exception)
Definition: exception.c:2711
LONG(NTAPI * PVECTORED_EXCEPTION_HANDLER)(PEXCEPTION_POINTERS ExceptionPointers)
Definition: rtltypes.h:501
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
DWORD dwProcessId
Definition: winbase.h:767
DWORD dwError
Definition: winbase.h:761
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define EXCEPTION_ACCESS_VIOLATION
Definition: winbase.h:308
const GLint * first
Definition: glext.h:5794
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
LONG NTSTATUS
Definition: precomp.h:26
BOOL WINAPI ContinueDebugEvent(IN DWORD dwProcessId, IN DWORD dwThreadId, IN DWORD dwContinueStatus)
Definition: debugger.c:448
#define STATUS_SINGLE_STEP
Definition: ntstatus.h:173
static const void void SIZE_T
Definition: exception.c:54
GLintptr offset
Definition: glext.h:5920
#define CALLBACK
Definition: compat.h:27
#define EXCEPTION_INVALID_HANDLE
Definition: winbase.h:329
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:5644
GLuint buffer
Definition: glext.h:5915
BYTE BeingDebugged
Definition: btrfs_drv.h:1886
PEXCEPTION_ROUTINE NTAPI RtlVirtualUnwind(_In_ ULONG HandlerType, _In_ ULONG64 ImageBase, _In_ ULONG64 ControlPc, _In_ PRUNTIME_FUNCTION FunctionEntry, _Inout_ PCONTEXT Context, _Outptr_ PVOID *HandlerData, _Out_ PULONG64 EstablisherFrame, _Inout_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
Definition: unwind.c:349
#define EXCEPTION_SINGLE_STEP
Definition: winbase.h:311
#define test
Definition: rosglue.h:37
TCHAR * cmdline
Definition: stretchblt.cpp:32
int winetest_interactive
#define DECLSPEC_ALIGN(x)
Definition: ntbasedef.h:257
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
#define MEM_COMMIT
Definition: nt_native.h:1313
#define DWORD
Definition: nt_native.h:44
#define CONTEXT_SEGMENTS
Definition: nt_native.h:1371
ULONG Dr7
Definition: nt_native.h:1439
ULONG Dr3
Definition: nt_native.h:1437
#define DBG_CONTINUE
Definition: ntstatus.h:47
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
PEXCEPTION_ROUTINE Handler
Definition: compat.h:395
PVOID ExceptionAddress
Definition: compat.h:199
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
uint32_t ULONG_PTR
Definition: typedefs.h:63
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: glext.h:9514
PVOID ImageBaseAddress
Definition: ntddk_ex.h:245
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DWORD ExceptionCode
Definition: compat.h:196
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
pass
Definition: typegen.h:24
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static PVOID
Definition: exception.c:48
#define CREATE_SUSPENDED
Definition: winbase.h:178
LPVOID NTAPI VirtualAlloc(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flAllocationType, IN DWORD flProtect)
Definition: virtmem.c:74
GLenum const GLfloat * params
Definition: glext.h:5645
HANDLE WINAPI GetCurrentThread(VOID)
Definition: proc.c:1148
unsigned int BOOL
Definition: ntddk_ex.h:94
GLuint base
Definition: 3dtext.c:35
long LONG
Definition: pedump.c:60
__asm__("\t.globl GetPhys\n" "GetPhys:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t" "mtmsr 6\n\t" "isync\n\t" "sync\n\t" "lwz 3,0(3)\n\t" "mtmsr 5\n\t" "isync\n\t" "sync\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr")
struct @4038 regs[]
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:9513
OUTPUT_DEBUG_STRING_INFO DebugString
Definition: winbase.h:777
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
#define MEM_RESERVE
Definition: nt_native.h:1314
EXCEPTION_DEBUG_INFO Exception
Definition: winbase.h:770
ULONG Dr1
Definition: nt_native.h:1435
#define PAGE_NOACCESS
Definition: nt_native.h:1302
DWORD dwDebugEventCode
Definition: winbase.h:766
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:136
smooth NULL
Definition: ftsmooth.c:416
#define STATUS_BREAKPOINT
Definition: ntstatus.h:172
const char * winetest_platform
CREATE_PROCESS_DEBUG_INFO CreateProcessInfo
Definition: winbase.h:772
static PBOOL
Definition: exception.c:58
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
ULONG Dr2
Definition: nt_native.h:1436
#define STATUS_LONGJUMP
Definition: ntstatus.h:205
ULONG ContextFlags
Definition: nt_native.h:1426
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define EXCEPTION_EXECUTE_FAULT
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
static BOOL(WINAPI *pIsWow64Process)(HANDLE
PCONTEXT ContextRecord
Definition: rtltypes.h:197
static PROCESSINFOCLASS
Definition: exception.c:56
#define EXIT_PROCESS_DEBUG_EVENT
Definition: winbase.h:106
#define CONTEXT_FULL
Definition: nt_native.h:1375
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:201
DWORD cb
Definition: winbase.h:803
#define trace
Definition: atltest.h:70
static VOID(WINAPI *pRtlCaptureContext)(CONTEXT *)
#define EXCEPTION_FLT_DIVIDE_BY_ZERO
Definition: winbase.h:314
union _DEBUG_EVENT::@3163 u
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
HANDLE WINAPI GetCurrentProcess(VOID)
Definition: proc.c:1138
static BOOL is_wow64
Definition: loader.c:55
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4742
static const void void SIZE_T *static LONG exit_code
Definition: exception.c:55
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
#define EXCEPTION_READ_FAULT
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:71
#define EXCEPTION_BREAKPOINT
Definition: winbase.h:310
BOOL NTAPI VirtualProtect(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flNewProtect, OUT PDWORD lpflOldProtect)
Definition: virtmem.c:144
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define DEBUG_PROCESS
Definition: winbase.h:176
struct _RUNTIME_FUNCTION RUNTIME_FUNCTION
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
struct _test_info results[8]
Definition: SetCursorPos.c:29
int winetest_get_mainargs(char ***pargv)
GLbitfield flags
Definition: glext.h:7161
static DWORD pi
Definition: protocol.c:150
struct _RUNTIME_FUNCTION * PRUNTIME_FUNCTION
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:661
static HANDLE thread
Definition: service.c:33
BOOL WINAPI WaitForDebugEvent(IN LPDEBUG_EVENT lpDebugEvent, IN DWORD dwMilliseconds)
Definition: debugger.c:625
unsigned __int64 ULONG64
Definition: imports.h:198
#define DBG_EXCEPTION_NOT_HANDLED
Definition: ntstatus.h:57
int ret
GLenum const GLvoid * addr
Definition: glext.h:9621
#define STATUS_INVALID_INFO_CLASS
Definition: ntstatus.h:226
EXCEPTION_RECORD ExceptionRecord
Definition: winbase.h:729
#define CONTEXT_DEBUG_REGISTERS
Definition: nt_native.h:1373
Definition: stat.h:55
uint32_t entry
Definition: isohybrid.c:63
#define except(x)
Definition: btrfs_drv.h:135
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT
GLenum GLsizei len
Definition: glext.h:6722
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:821
unsigned char BYTE
Definition: mem.h:68
#define MEM_EXECUTE_OPTION_DISABLE
Definition: mmtypes.h:73
#define STATUS_PRIVILEGED_INSTRUCTION
Definition: ntstatus.h:372
#define DBG_PRINTEXCEPTION_C
Definition: ntstatus.h:53
#define STATUS_FLOAT_MULTIPLE_TRAPS
Definition: ntstatus.h:794
struct __unwind_info unwind_info
static ULONG
Definition: exception.c:56
ULONG Eax
Definition: nt_native.h:1468
uint32_t DWORD_PTR
Definition: typedefs.h:63
void dispatch(HANDLE hStopEvent)
Definition: dispatch.c:66
#define broken(x)
Definition: _sntprintf.h:21
static NTSTATUS(WINAPI *pNtGetContextThread)(HANDLE
void winetest_wait_child_process(HANDLE process)
ULONG_PTR SIZE_T
Definition: typedefs.h:78
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
#define InterlockedIncrement
Definition: armddk.h:53
uint64_t DWORD64
Definition: typedefs.h:65
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
#define CDECL
Definition: compat.h:21
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
#define ok(value,...)
Definition: atltest.h:57
#define EXCEPTION_DEBUG_EVENT
Definition: winbase.h:102
ULONG Dr6
Definition: nt_native.h:1438
#define EXCEPTION_FLT_STACK_CHECK
Definition: winbase.h:318
#define expect(expected, got)
Definition: combo.c:36
#define DBG_RIPEXCEPTION
Definition: ntstatus.h:54
#define STATUS_UNWIND
Definition: ntstatus.h:262
unsigned int UINT
Definition: ndis.h:50
ULONG R12
Definition: ke.h:267
static void * code_mem
Definition: exception.c:43
static HINSTANCE hntdll
Definition: process.c:66
#define MEM_EXECUTE_OPTION_PERMANENT
Definition: mmtypes.h:76
#define EXCEPTION_ILLEGAL_INSTRUCTION
Definition: winbase.h:324
static PULONG
Definition: exception.c:56
#define skip(...)
Definition: atltest.h:64
ULONG Dr0
Definition: nt_native.h:1434
#define MEM_RELEASE
Definition: nt_native.h:1316
#define BOOLEAN
Definition: pedump.c:73
GLuint res
Definition: glext.h:9613
DWORD WINAPI ResumeThread(IN HANDLE hThread)
Definition: thread.c:566
void(* func_ptr)(void)
Definition: gccmain.c:11
unsigned int ULONG
Definition: retypes.h:1
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define OUTPUT_DEBUG_STRING_EVENT
Definition: winbase.h:109
#define ULONG_PTR
Definition: config.h:101
DWORD ExceptionFlags
Definition: compat.h:197
#define CONTEXT_INTEGER
Definition: nt_native.h:1370
#define GetProcAddress(x, y)
Definition: compat.h:418
#define CREATE_PROCESS_DEBUG_EVENT
Definition: winbase.h:104
BOOL NTAPI VirtualFree(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD dwFreeType)
Definition: virtmem.c:128
PEXCEPTION_RECORD ExceptionRecord
Definition: rtltypes.h:196
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7786
DWORD NumberParameters
Definition: compat.h:200
#define INFINITE
Definition: serial.h:102
return STATUS_SUCCESS
Definition: btrfs.c:2938
#define memset(x, y, z)
Definition: compat.h:39
static SERVICE_STATUS status
Definition: service.c:31
#define win_skip
Definition: test.h:141
int k
Definition: mpi.c:3369
#define LOWORD(l)
Definition: pedump.c:82
void WINAPI SHIM_OBJ_NAME() OutputDebugStringA(LPCSTR lpOutputString)
Definition: ignoredbgout.c:18
#define RIP_EVENT
Definition: winbase.h:110
struct _EXCEPTION_REGISTRATION_RECORD * Prev
Definition: exception.h:42
static PEXCEPTION_RECORD
Definition: exception.c:48
DWORD dwType
Definition: winbase.h:762
INT testnum
Definition: capicon.c:26
BOOL expected
Definition: store.c:2063
#define __int64
Definition: basetyps.h:16
static PVECTORED_EXCEPTION_HANDLER func
Definition: exception.c:50
#define PAGE_READWRITE
Definition: nt_native.h:1304
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define EXCEPTION_CONTINUE_EXECUTION
Definition: excpt.h:87
Definition: ps.c:97