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