include: Fix off-by-one error in EmfPlusRecordType enumeration.
[wine/multimedia.git] / dlls / ntdll / signal_i386.c
blob63bf088df2d767f2bee2b6f06c724528f2b827ac
1 /*
2 * i386 signal handling routines
4 * Copyright 1999 Alexandre Julliard
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.
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.
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
21 #ifdef __i386__
23 #include "config.h"
24 #include "wine/port.h"
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYSCALL_H
40 # include <syscall.h>
41 #else
42 # ifdef HAVE_SYS_SYSCALL_H
43 # include <sys/syscall.h>
44 # endif
45 #endif
47 #ifdef HAVE_SYS_VM86_H
48 # include <sys/vm86.h>
49 #endif
51 #ifdef HAVE_SYS_SIGNAL_H
52 # include <sys/signal.h>
53 #endif
54 #ifdef HAVE_SYS_SYSCTL_H
55 # include <sys/sysctl.h>
56 #endif
58 #include "ntstatus.h"
59 #define WIN32_NO_STATUS
60 #include "windef.h"
61 #include "wine/library.h"
62 #include "ntdll_misc.h"
63 #include "wine/exception.h"
64 #include "wine/debug.h"
66 #ifdef HAVE_VALGRIND_MEMCHECK_H
67 #include <valgrind/memcheck.h>
68 #endif
70 #undef ERR /* Solaris needs to define this */
72 /* not defined for x86, so copy the x86_64 definition */
73 typedef struct DECLSPEC_ALIGN(16) _M128A
75 ULONGLONG Low;
76 LONGLONG High;
77 } M128A;
79 typedef struct
81 WORD ControlWord;
82 WORD StatusWord;
83 BYTE TagWord;
84 BYTE Reserved1;
85 WORD ErrorOpcode;
86 DWORD ErrorOffset;
87 WORD ErrorSelector;
88 WORD Reserved2;
89 DWORD DataOffset;
90 WORD DataSelector;
91 WORD Reserved3;
92 DWORD MxCsr;
93 DWORD MxCsr_Mask;
94 M128A FloatRegisters[8];
95 M128A XmmRegisters[16];
96 BYTE Reserved4[96];
97 } XMM_SAVE_AREA32;
99 /***********************************************************************
100 * signal context platform-specific definitions
103 #ifdef __ANDROID__
105 typedef struct ucontext
107 unsigned long uc_flags;
108 struct ucontext *uc_link;
109 stack_t uc_stack;
110 struct sigcontext uc_mcontext;
111 sigset_t uc_sigmask;
112 } SIGCONTEXT;
114 #define EAX_sig(context) ((context)->uc_mcontext.eax)
115 #define EBX_sig(context) ((context)->uc_mcontext.ebx)
116 #define ECX_sig(context) ((context)->uc_mcontext.ecx)
117 #define EDX_sig(context) ((context)->uc_mcontext.edx)
118 #define ESI_sig(context) ((context)->uc_mcontext.esi)
119 #define EDI_sig(context) ((context)->uc_mcontext.edi)
120 #define EBP_sig(context) ((context)->uc_mcontext.ebp)
121 #define ESP_sig(context) ((context)->uc_mcontext.esp)
123 #define CS_sig(context) ((context)->uc_mcontext.cs)
124 #define DS_sig(context) ((context)->uc_mcontext.ds)
125 #define ES_sig(context) ((context)->uc_mcontext.es)
126 #define SS_sig(context) ((context)->uc_mcontext.ss)
127 #define FS_sig(context) ((context)->uc_mcontext.fs)
128 #define GS_sig(context) ((context)->uc_mcontext.gs)
130 #define EFL_sig(context) ((context)->uc_mcontext.eflags)
131 #define EIP_sig(context) ((context)->uc_mcontext.eip)
132 #define TRAP_sig(context) ((context)->uc_mcontext.trapno)
133 #define ERROR_sig(context) ((context)->uc_mcontext.err)
135 #define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpstate))
136 #define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpstate->status >> 16) ? (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1) : NULL)
138 #elif defined (__linux__)
140 typedef ucontext_t SIGCONTEXT;
142 #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX])
143 #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX])
144 #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX])
145 #define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX])
146 #define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI])
147 #define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI])
148 #define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP])
149 #define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP])
151 #define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS])
152 #define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS])
153 #define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES])
154 #define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS])
155 #define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS])
156 #define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS])
158 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
159 #define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
160 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
161 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
163 #define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs))
164 #define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpregs->status >> 16) ? (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1) : NULL)
166 #define VM86_EAX 0 /* the %eax value while vm86_enter is executing */
167 #define VIF_FLAG 0x00080000
168 #define VIP_FLAG 0x00100000
170 int vm86_enter( void **vm86_ptr );
171 void vm86_return(void);
172 void vm86_return_end(void);
173 __ASM_GLOBAL_FUNC(vm86_enter,
174 "pushl %ebp\n\t"
175 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
176 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
177 "movl %esp,%ebp\n\t"
178 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
179 "pushl %ebx\n\t"
180 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
181 "movl $166,%eax\n\t" /*SYS_vm86*/
182 "movl 8(%ebp),%ecx\n\t" /* vm86_ptr */
183 "movl (%ecx),%ecx\n\t"
184 "movl $1,%ebx\n\t" /*VM86_ENTER*/
185 "pushl %ecx\n\t" /* put vm86plus_struct ptr somewhere we can find it */
186 "pushl %fs\n\t"
187 "pushl %gs\n\t"
188 "int $0x80\n"
189 ".globl " __ASM_NAME("vm86_return") "\n\t"
190 __ASM_FUNC("vm86_return") "\n"
191 __ASM_NAME("vm86_return") ":\n\t"
192 "popl %gs\n\t"
193 "popl %fs\n\t"
194 "popl %ecx\n\t"
195 "popl %ebx\n\t"
196 __ASM_CFI(".cfi_same_value %ebx\n\t")
197 "popl %ebp\n\t"
198 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
199 __ASM_CFI(".cfi_same_value %ebp\n\t")
200 "testl %eax,%eax\n\t"
201 "jl 0f\n\t"
202 "cmpb $0,%al\n\t" /* VM86_SIGNAL */
203 "je " __ASM_NAME("vm86_enter") "\n\t"
204 "0:\n\t"
205 "movl 4(%esp),%ecx\n\t" /* vm86_ptr */
206 "movl $0,(%ecx)\n\t"
207 ".globl " __ASM_NAME("vm86_return_end") "\n\t"
208 __ASM_FUNC("vm86_return_end") "\n"
209 __ASM_NAME("vm86_return_end") ":\n\t"
210 "ret" )
212 #ifdef HAVE_SYS_VM86_H
213 # define __HAVE_VM86
214 #endif
216 #elif defined (__BSDI__)
218 #include <machine/frame.h>
219 typedef struct trapframe SIGCONTEXT;
221 #define EAX_sig(context) ((context)->tf_eax)
222 #define EBX_sig(context) ((context)->tf_ebx)
223 #define ECX_sig(context) ((context)->tf_ecx)
224 #define EDX_sig(context) ((context)->tf_edx)
225 #define ESI_sig(context) ((context)->tf_esi)
226 #define EDI_sig(context) ((context)->tf_edi)
227 #define EBP_sig(context) ((context)->tf_ebp)
229 #define CS_sig(context) ((context)->tf_cs)
230 #define DS_sig(context) ((context)->tf_ds)
231 #define ES_sig(context) ((context)->tf_es)
232 #define SS_sig(context) ((context)->tf_ss)
234 #define EFL_sig(context) ((context)->tf_eflags)
236 #define EIP_sig(context) (*((unsigned long*)&(context)->tf_eip))
237 #define ESP_sig(context) (*((unsigned long*)&(context)->tf_esp))
239 #define FPU_sig(context) NULL /* FIXME */
240 #define FPUX_sig(context) NULL /* FIXME */
242 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
244 #include <machine/trap.h>
246 typedef struct sigcontext SIGCONTEXT;
248 #define EAX_sig(context) ((context)->sc_eax)
249 #define EBX_sig(context) ((context)->sc_ebx)
250 #define ECX_sig(context) ((context)->sc_ecx)
251 #define EDX_sig(context) ((context)->sc_edx)
252 #define ESI_sig(context) ((context)->sc_esi)
253 #define EDI_sig(context) ((context)->sc_edi)
254 #define EBP_sig(context) ((context)->sc_ebp)
256 #define CS_sig(context) ((context)->sc_cs)
257 #define DS_sig(context) ((context)->sc_ds)
258 #define ES_sig(context) ((context)->sc_es)
259 #define FS_sig(context) ((context)->sc_fs)
260 #define GS_sig(context) ((context)->sc_gs)
261 #define SS_sig(context) ((context)->sc_ss)
263 #define TRAP_sig(context) ((context)->sc_trapno)
264 #define ERROR_sig(context) ((context)->sc_err)
265 #define EFL_sig(context) ((context)->sc_eflags)
267 #define EIP_sig(context) ((context)->sc_eip)
268 #define ESP_sig(context) ((context)->sc_esp)
270 #define FPU_sig(context) NULL /* FIXME */
271 #define FPUX_sig(context) NULL /* FIXME */
273 #elif defined (__OpenBSD__)
275 typedef struct sigcontext SIGCONTEXT;
277 #define EAX_sig(context) ((context)->sc_eax)
278 #define EBX_sig(context) ((context)->sc_ebx)
279 #define ECX_sig(context) ((context)->sc_ecx)
280 #define EDX_sig(context) ((context)->sc_edx)
281 #define ESI_sig(context) ((context)->sc_esi)
282 #define EDI_sig(context) ((context)->sc_edi)
283 #define EBP_sig(context) ((context)->sc_ebp)
285 #define CS_sig(context) ((context)->sc_cs)
286 #define DS_sig(context) ((context)->sc_ds)
287 #define ES_sig(context) ((context)->sc_es)
288 #define FS_sig(context) ((context)->sc_fs)
289 #define GS_sig(context) ((context)->sc_gs)
290 #define SS_sig(context) ((context)->sc_ss)
292 #define TRAP_sig(context) ((context)->sc_trapno)
293 #define ERROR_sig(context) ((context)->sc_err)
294 #define EFL_sig(context) ((context)->sc_eflags)
296 #define EIP_sig(context) ((context)->sc_eip)
297 #define ESP_sig(context) ((context)->sc_esp)
299 #define FPU_sig(context) NULL /* FIXME */
300 #define FPUX_sig(context) NULL /* FIXME */
302 #define T_MCHK T_MACHK
303 #define T_XMMFLT T_XFTRAP
305 #elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
307 #ifdef _SCO_DS
308 #include <sys/regset.h>
309 #endif
310 #include <sys/ucontext.h>
311 typedef struct ucontext SIGCONTEXT;
313 #ifdef _SCO_DS
314 #define gregs regs
315 #endif
317 #define EAX_sig(context) ((context)->uc_mcontext.gregs[EAX])
318 #define EBX_sig(context) ((context)->uc_mcontext.gregs[EBX])
319 #define ECX_sig(context) ((context)->uc_mcontext.gregs[ECX])
320 #define EDX_sig(context) ((context)->uc_mcontext.gregs[EDX])
321 #define ESI_sig(context) ((context)->uc_mcontext.gregs[ESI])
322 #define EDI_sig(context) ((context)->uc_mcontext.gregs[EDI])
323 #define EBP_sig(context) ((context)->uc_mcontext.gregs[EBP])
325 #define CS_sig(context) ((context)->uc_mcontext.gregs[CS])
326 #define DS_sig(context) ((context)->uc_mcontext.gregs[DS])
327 #define ES_sig(context) ((context)->uc_mcontext.gregs[ES])
328 #define SS_sig(context) ((context)->uc_mcontext.gregs[SS])
330 #define FS_sig(context) ((context)->uc_mcontext.gregs[FS])
331 #define GS_sig(context) ((context)->uc_mcontext.gregs[GS])
333 #define EFL_sig(context) ((context)->uc_mcontext.gregs[EFL])
335 #define EIP_sig(context) ((context)->uc_mcontext.gregs[EIP])
336 #ifdef UESP
337 #define ESP_sig(context) ((context)->uc_mcontext.gregs[UESP])
338 #elif defined(R_ESP)
339 #define ESP_sig(context) ((context)->uc_mcontext.gregs[R_ESP])
340 #else
341 #define ESP_sig(context) ((context)->uc_mcontext.gregs[ESP])
342 #endif
343 #ifdef ERR
344 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[ERR])
345 #endif
346 #ifdef TRAPNO
347 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[TRAPNO])
348 #endif
350 #define FPU_sig(context) NULL /* FIXME */
351 #define FPUX_sig(context) NULL /* FIXME */
353 #elif defined (__APPLE__)
354 # include <sys/ucontext.h>
356 typedef ucontext_t SIGCONTEXT;
358 /* work around silly renaming of struct members in OS X 10.5 */
359 #if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32)
360 #define EAX_sig(context) ((context)->uc_mcontext->__ss.__eax)
361 #define EBX_sig(context) ((context)->uc_mcontext->__ss.__ebx)
362 #define ECX_sig(context) ((context)->uc_mcontext->__ss.__ecx)
363 #define EDX_sig(context) ((context)->uc_mcontext->__ss.__edx)
364 #define ESI_sig(context) ((context)->uc_mcontext->__ss.__esi)
365 #define EDI_sig(context) ((context)->uc_mcontext->__ss.__edi)
366 #define EBP_sig(context) ((context)->uc_mcontext->__ss.__ebp)
367 #define CS_sig(context) ((context)->uc_mcontext->__ss.__cs)
368 #define DS_sig(context) ((context)->uc_mcontext->__ss.__ds)
369 #define ES_sig(context) ((context)->uc_mcontext->__ss.__es)
370 #define FS_sig(context) ((context)->uc_mcontext->__ss.__fs)
371 #define GS_sig(context) ((context)->uc_mcontext->__ss.__gs)
372 #define SS_sig(context) ((context)->uc_mcontext->__ss.__ss)
373 #define EFL_sig(context) ((context)->uc_mcontext->__ss.__eflags)
374 #define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__eip))
375 #define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__esp))
376 #define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno)
377 #define ERROR_sig(context) ((context)->uc_mcontext->__es.__err)
378 #define FPU_sig(context) NULL
379 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw)
380 #else
381 #define EAX_sig(context) ((context)->uc_mcontext->ss.eax)
382 #define EBX_sig(context) ((context)->uc_mcontext->ss.ebx)
383 #define ECX_sig(context) ((context)->uc_mcontext->ss.ecx)
384 #define EDX_sig(context) ((context)->uc_mcontext->ss.edx)
385 #define ESI_sig(context) ((context)->uc_mcontext->ss.esi)
386 #define EDI_sig(context) ((context)->uc_mcontext->ss.edi)
387 #define EBP_sig(context) ((context)->uc_mcontext->ss.ebp)
388 #define CS_sig(context) ((context)->uc_mcontext->ss.cs)
389 #define DS_sig(context) ((context)->uc_mcontext->ss.ds)
390 #define ES_sig(context) ((context)->uc_mcontext->ss.es)
391 #define FS_sig(context) ((context)->uc_mcontext->ss.fs)
392 #define GS_sig(context) ((context)->uc_mcontext->ss.gs)
393 #define SS_sig(context) ((context)->uc_mcontext->ss.ss)
394 #define EFL_sig(context) ((context)->uc_mcontext->ss.eflags)
395 #define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
396 #define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.esp))
397 #define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
398 #define ERROR_sig(context) ((context)->uc_mcontext->es.err)
399 #define FPU_sig(context) NULL
400 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->fs.fpu_fcw)
401 #endif
403 #elif defined(__NetBSD__)
404 # include <sys/ucontext.h>
405 # include <sys/types.h>
406 # include <signal.h>
408 typedef ucontext_t SIGCONTEXT;
410 #define EAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EAX])
411 #define EBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBX])
412 #define ECX_sig(context) ((context)->uc_mcontext.__gregs[_REG_ECX])
413 #define EDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDX])
414 #define ESI_sig(context) ((context)->uc_mcontext.__gregs[_REG_ESI])
415 #define EDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDI])
416 #define EBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBP])
417 #define ESP_sig(context) _UC_MACHINE_SP(context)
419 #define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS])
420 #define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS])
421 #define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES])
422 #define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS])
423 #define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS])
424 #define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS])
426 #define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_EFL])
427 #define EIP_sig(context) _UC_MACHINE_PC(context)
428 #define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
429 #define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
431 #define FPU_sig(context) NULL
432 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&((context)->uc_mcontext.__fpregs))
434 #define T_MCHK T_MCA
435 #define T_XMMFLT T_XMM
437 #elif defined(__GNU__)
438 typedef ucontext_t SIGCONTEXT;
440 #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX])
441 #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX])
442 #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX])
443 #define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX])
444 #define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI])
445 #define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI])
446 #define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP])
447 #define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP])
449 #define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS])
450 #define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS])
451 #define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES])
452 #define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS])
453 #define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS])
454 #define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS])
456 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
457 #define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
458 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
459 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
461 #define FPU_sig(context) ((FLOATING_SAVE_AREA *)&(context)->uc_mcontext.fpregs.fp_reg_set.fpchip_state)
462 #define FPUX_sig(context) NULL
464 #else
465 #error You must define the signal context functions for your platform
466 #endif /* linux */
468 WINE_DEFAULT_DEBUG_CHANNEL(seh);
470 typedef int (*wine_signal_handler)(unsigned int sig);
472 static const size_t teb_size = 4096; /* we reserve one page for the TEB */
473 static size_t signal_stack_mask;
474 static size_t signal_stack_size;
476 static wine_signal_handler handlers[256];
478 static BOOL fpux_support; /* whether the CPU supports extended fpu context */
480 extern void DECLSPEC_NORETURN __wine_restore_regs( const CONTEXT *context );
482 enum i386_trap_code
484 TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
485 #if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
486 TRAP_x86_DIVIDE = T_DIVIDE, /* Division by zero exception */
487 TRAP_x86_TRCTRAP = T_TRCTRAP, /* Single-step exception */
488 TRAP_x86_NMI = T_NMI, /* NMI interrupt */
489 TRAP_x86_BPTFLT = T_BPTFLT, /* Breakpoint exception */
490 TRAP_x86_OFLOW = T_OFLOW, /* Overflow exception */
491 TRAP_x86_BOUND = T_BOUND, /* Bound range exception */
492 TRAP_x86_PRIVINFLT = T_PRIVINFLT, /* Invalid opcode exception */
493 TRAP_x86_DNA = T_DNA, /* Device not available exception */
494 TRAP_x86_DOUBLEFLT = T_DOUBLEFLT, /* Double fault exception */
495 TRAP_x86_FPOPFLT = T_FPOPFLT, /* Coprocessor segment overrun */
496 TRAP_x86_TSSFLT = T_TSSFLT, /* Invalid TSS exception */
497 TRAP_x86_SEGNPFLT = T_SEGNPFLT, /* Segment not present exception */
498 TRAP_x86_STKFLT = T_STKFLT, /* Stack fault */
499 TRAP_x86_PROTFLT = T_PROTFLT, /* General protection fault */
500 TRAP_x86_PAGEFLT = T_PAGEFLT, /* Page fault */
501 TRAP_x86_ARITHTRAP = T_ARITHTRAP, /* Floating point exception */
502 TRAP_x86_ALIGNFLT = T_ALIGNFLT, /* Alignment check exception */
503 TRAP_x86_MCHK = T_MCHK, /* Machine check exception */
504 TRAP_x86_CACHEFLT = T_XMMFLT /* Cache flush exception */
505 #else
506 TRAP_x86_DIVIDE = 0, /* Division by zero exception */
507 TRAP_x86_TRCTRAP = 1, /* Single-step exception */
508 TRAP_x86_NMI = 2, /* NMI interrupt */
509 TRAP_x86_BPTFLT = 3, /* Breakpoint exception */
510 TRAP_x86_OFLOW = 4, /* Overflow exception */
511 TRAP_x86_BOUND = 5, /* Bound range exception */
512 TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */
513 TRAP_x86_DNA = 7, /* Device not available exception */
514 TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */
515 TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */
516 TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */
517 TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */
518 TRAP_x86_STKFLT = 12, /* Stack fault */
519 TRAP_x86_PROTFLT = 13, /* General protection fault */
520 TRAP_x86_PAGEFLT = 14, /* Page fault */
521 TRAP_x86_ARITHTRAP = 16, /* Floating point exception */
522 TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */
523 TRAP_x86_MCHK = 18, /* Machine check exception */
524 TRAP_x86_CACHEFLT = 19 /* SIMD exception (via SIGFPE) if CPU is SSE capable
525 otherwise Cache flush exception (via SIGSEV) */
526 #endif
529 /* Exception record for handling exceptions happening inside exception handlers */
530 typedef struct
532 EXCEPTION_REGISTRATION_RECORD frame;
533 EXCEPTION_REGISTRATION_RECORD *prevFrame;
534 } EXC_NESTED_FRAME;
536 extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
537 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher,
538 PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler );
540 /***********************************************************************
541 * dispatch_signal
543 static inline int dispatch_signal(unsigned int sig)
545 if (handlers[sig] == NULL) return 0;
546 return handlers[sig](sig);
550 /***********************************************************************
551 * get_trap_code
553 * Get the trap code for a signal.
555 static inline enum i386_trap_code get_trap_code( const SIGCONTEXT *sigcontext )
557 #ifdef TRAP_sig
558 return TRAP_sig(sigcontext);
559 #else
560 return TRAP_x86_UNKNOWN; /* unknown trap code */
561 #endif
564 /***********************************************************************
565 * get_error_code
567 * Get the error code for a signal.
569 static inline WORD get_error_code( const SIGCONTEXT *sigcontext )
571 #ifdef ERROR_sig
572 return ERROR_sig(sigcontext);
573 #else
574 return 0;
575 #endif
578 /***********************************************************************
579 * get_signal_stack
581 * Get the base of the signal stack for the current thread.
583 static inline void *get_signal_stack(void)
585 return (char *)NtCurrentTeb() + 4096;
589 /***********************************************************************
590 * get_current_teb
592 * Get the current teb based on the stack pointer.
594 static inline TEB *get_current_teb(void)
596 unsigned long esp;
597 __asm__("movl %%esp,%0" : "=g" (esp) );
598 return (TEB *)(esp & ~signal_stack_mask);
602 /*******************************************************************
603 * is_valid_frame
605 static inline BOOL is_valid_frame( void *frame )
607 if ((ULONG_PTR)frame & 3) return FALSE;
608 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
609 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
612 /*******************************************************************
613 * raise_handler
615 * Handler for exceptions happening inside a handler.
617 static DWORD raise_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
618 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
620 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
621 return ExceptionContinueSearch;
622 /* We shouldn't get here so we store faulty frame in dispatcher */
623 *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
624 return ExceptionNestedException;
628 /*******************************************************************
629 * unwind_handler
631 * Handler for exceptions happening inside an unwind handler.
633 static DWORD unwind_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
634 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
636 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
637 return ExceptionContinueSearch;
638 /* We shouldn't get here so we store faulty frame in dispatcher */
639 *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
640 return ExceptionCollidedUnwind;
644 /**********************************************************************
645 * call_stack_handlers
647 * Call the stack handlers chain.
649 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
651 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
652 DWORD res;
654 frame = NtCurrentTeb()->Tib.ExceptionList;
655 nested_frame = NULL;
656 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
658 /* Check frame address */
659 if (!is_valid_frame( frame ))
661 rec->ExceptionFlags |= EH_STACK_INVALID;
662 break;
665 /* Call handler */
666 TRACE( "calling handler at %p code=%x flags=%x\n",
667 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
668 res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, raise_handler );
669 TRACE( "handler at %p returned %x\n", frame->Handler, res );
671 if (frame == nested_frame)
673 /* no longer nested */
674 nested_frame = NULL;
675 rec->ExceptionFlags &= ~EH_NESTED_CALL;
678 switch(res)
680 case ExceptionContinueExecution:
681 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
682 return STATUS_NONCONTINUABLE_EXCEPTION;
683 case ExceptionContinueSearch:
684 break;
685 case ExceptionNestedException:
686 if (nested_frame < dispatch) nested_frame = dispatch;
687 rec->ExceptionFlags |= EH_NESTED_CALL;
688 break;
689 default:
690 return STATUS_INVALID_DISPOSITION;
692 frame = frame->Prev;
694 return STATUS_UNHANDLED_EXCEPTION;
698 /*******************************************************************
699 * raise_exception
701 * Implementation of NtRaiseException.
703 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
705 NTSTATUS status;
707 if (first_chance)
709 DWORD c;
711 TRACE( "code=%x flags=%x addr=%p ip=%08x tid=%04x\n",
712 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
713 context->Eip, GetCurrentThreadId() );
714 for (c = 0; c < rec->NumberParameters; c++)
715 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
716 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
718 if (rec->ExceptionInformation[1] >> 16)
719 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
720 rec->ExceptionAddress,
721 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
722 else
723 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
724 rec->ExceptionAddress,
725 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
727 else
729 TRACE(" eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n",
730 context->Eax, context->Ebx, context->Ecx,
731 context->Edx, context->Esi, context->Edi );
732 TRACE(" ebp=%08x esp=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n",
733 context->Ebp, context->Esp, context->SegCs, context->SegDs,
734 context->SegEs, context->SegFs, context->SegGs, context->EFlags );
736 status = send_debug_event( rec, TRUE, context );
737 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
738 return STATUS_SUCCESS;
740 /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
741 if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
743 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
744 return STATUS_SUCCESS;
746 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
747 return status;
750 /* last chance exception */
752 status = send_debug_event( rec, FALSE, context );
753 if (status != DBG_CONTINUE)
755 if (rec->ExceptionFlags & EH_STACK_INVALID)
756 WINE_ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
757 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
758 WINE_ERR("Process attempted to continue execution after noncontinuable exception.\n");
759 else
760 WINE_ERR("Unhandled exception code %x flags %x addr %p\n",
761 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
762 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
764 return STATUS_SUCCESS;
768 #ifdef __HAVE_VM86
769 /***********************************************************************
770 * save_vm86_context
772 * Set the register values from a vm86 structure.
774 static void save_vm86_context( CONTEXT *context, const struct vm86plus_struct *vm86 )
776 context->ContextFlags = CONTEXT_FULL;
777 context->Eax = vm86->regs.eax;
778 context->Ebx = vm86->regs.ebx;
779 context->Ecx = vm86->regs.ecx;
780 context->Edx = vm86->regs.edx;
781 context->Esi = vm86->regs.esi;
782 context->Edi = vm86->regs.edi;
783 context->Esp = vm86->regs.esp;
784 context->Ebp = vm86->regs.ebp;
785 context->Eip = vm86->regs.eip;
786 context->SegCs = vm86->regs.cs;
787 context->SegDs = vm86->regs.ds;
788 context->SegEs = vm86->regs.es;
789 context->SegFs = vm86->regs.fs;
790 context->SegGs = vm86->regs.gs;
791 context->SegSs = vm86->regs.ss;
792 context->EFlags = vm86->regs.eflags;
796 /***********************************************************************
797 * restore_vm86_context
799 * Build a vm86 structure from the register values.
801 static void restore_vm86_context( const CONTEXT *context, struct vm86plus_struct *vm86 )
803 vm86->regs.eax = context->Eax;
804 vm86->regs.ebx = context->Ebx;
805 vm86->regs.ecx = context->Ecx;
806 vm86->regs.edx = context->Edx;
807 vm86->regs.esi = context->Esi;
808 vm86->regs.edi = context->Edi;
809 vm86->regs.esp = context->Esp;
810 vm86->regs.ebp = context->Ebp;
811 vm86->regs.eip = context->Eip;
812 vm86->regs.cs = context->SegCs;
813 vm86->regs.ds = context->SegDs;
814 vm86->regs.es = context->SegEs;
815 vm86->regs.fs = context->SegFs;
816 vm86->regs.gs = context->SegGs;
817 vm86->regs.ss = context->SegSs;
818 vm86->regs.eflags = context->EFlags;
822 /**********************************************************************
823 * merge_vm86_pending_flags
825 * Merges TEB.vm86_ptr and TEB.vm86_pending VIP flags and
826 * raises exception if there are pending events and VIF flag
827 * has been turned on.
829 * Called from __wine_enter_vm86 because vm86_enter
830 * doesn't check for pending events.
832 * Called from raise_vm86_sti_exception to check for
833 * pending events in a signal safe way.
835 static void merge_vm86_pending_flags( EXCEPTION_RECORD *rec )
837 BOOL check_pending = TRUE;
838 struct vm86plus_struct *vm86 =
839 (struct vm86plus_struct*)(ntdll_get_thread_data()->vm86_ptr);
842 * In order to prevent a race when SIGUSR2 occurs while
843 * we are returning from exception handler, pending events
844 * will be rechecked after each raised exception.
846 while (check_pending && get_vm86_teb_info()->vm86_pending)
848 check_pending = FALSE;
849 ntdll_get_thread_data()->vm86_ptr = NULL;
852 * If VIF is set, throw exception.
853 * Note that SIGUSR2 may turn VIF flag off so
854 * VIF check must occur only when TEB.vm86_ptr is NULL.
856 if (vm86->regs.eflags & VIF_FLAG)
858 CONTEXT vcontext;
859 save_vm86_context( &vcontext, vm86 );
861 rec->ExceptionCode = EXCEPTION_VM86_STI;
862 rec->ExceptionFlags = EXCEPTION_CONTINUABLE;
863 rec->ExceptionRecord = NULL;
864 rec->NumberParameters = 0;
865 rec->ExceptionAddress = (LPVOID)vcontext.Eip;
867 vcontext.EFlags &= ~VIP_FLAG;
868 get_vm86_teb_info()->vm86_pending = 0;
869 raise_exception( rec, &vcontext, TRUE );
871 restore_vm86_context( &vcontext, vm86 );
872 check_pending = TRUE;
875 ntdll_get_thread_data()->vm86_ptr = vm86;
879 * Merge VIP flags in a signal safe way. This requires
880 * that the following operation compiles into atomic
881 * instruction.
883 vm86->regs.eflags |= get_vm86_teb_info()->vm86_pending;
885 #endif /* __HAVE_VM86 */
888 #ifdef __sun
890 /* We have to workaround two Solaris breakages:
891 * - Solaris doesn't restore %ds and %es before calling the signal handler so exceptions in 16-bit
892 * code crash badly.
893 * - Solaris inserts a libc trampoline to call our handler, but the trampoline expects that registers
894 * are setup correctly. So we need to insert our own trampoline below the libc trampoline to set %gs.
897 extern int sigaction_syscall( int sig, const struct sigaction *new, struct sigaction *old );
898 __ASM_GLOBAL_FUNC( sigaction_syscall,
899 "movl $0x62,%eax\n\t"
900 "int $0x91\n\t"
901 "ret" )
903 /* assume the same libc handler is used for all signals */
904 static void (*libc_sigacthandler)( int signal, siginfo_t *siginfo, void *context );
906 static void wine_sigacthandler( int signal, siginfo_t *siginfo, void *sigcontext )
908 struct ntdll_thread_data *thread_data;
910 __asm__ __volatile__("mov %ss,%ax; mov %ax,%ds; mov %ax,%es");
912 thread_data = (struct ntdll_thread_data *)get_current_teb()->SpareBytes1;
913 wine_set_fs( thread_data->fs );
914 wine_set_gs( thread_data->gs );
916 libc_sigacthandler( signal, siginfo, sigcontext );
919 static int solaris_sigaction( int sig, const struct sigaction *new, struct sigaction *old )
921 struct sigaction real_act;
923 if (sigaction( sig, new, old ) == -1) return -1;
925 /* retrieve the real handler and flags with a direct syscall */
926 sigaction_syscall( sig, NULL, &real_act );
927 libc_sigacthandler = real_act.sa_sigaction;
928 real_act.sa_sigaction = wine_sigacthandler;
929 sigaction_syscall( sig, &real_act, NULL );
930 return 0;
932 #define sigaction(sig,new,old) solaris_sigaction(sig,new,old)
934 #endif
936 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
938 extern void clear_alignment_flag(void);
939 __ASM_GLOBAL_FUNC( clear_alignment_flag,
940 "pushfl\n\t"
941 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
942 "andl $~0x40000,(%esp)\n\t"
943 "popfl\n\t"
944 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
945 "ret" )
948 /***********************************************************************
949 * init_handler
951 * Handler initialization when the full context is not needed.
952 * Return the stack pointer to use for pushing the exception data.
954 static inline void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD *gs )
956 TEB *teb = get_current_teb();
958 clear_alignment_flag();
960 /* get %fs and %gs at time of the fault */
961 #ifdef FS_sig
962 *fs = LOWORD(FS_sig(sigcontext));
963 #else
964 *fs = wine_get_fs();
965 #endif
966 #ifdef GS_sig
967 *gs = LOWORD(GS_sig(sigcontext));
968 #else
969 *gs = wine_get_gs();
970 #endif
972 #ifndef __sun /* see above for Solaris handling */
974 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
975 wine_set_fs( thread_data->fs );
976 wine_set_gs( thread_data->gs );
978 #endif
980 if (!wine_ldt_is_system(CS_sig(sigcontext)) ||
981 !wine_ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */
984 * Win16 or DOS protected mode. Note that during switch
985 * from 16-bit mode to linear mode, CS may be set to system
986 * segment before FS is restored. Fortunately, in this case
987 * SS is still non-system segment. This is why both CS and SS
988 * are checked.
990 return teb->WOW32Reserved;
992 return (void *)(ESP_sig(sigcontext) & ~3);
996 /***********************************************************************
997 * save_fpu
999 * Save the thread FPU context.
1001 static inline void save_fpu( CONTEXT *context )
1003 #ifdef __GNUC__
1004 context->ContextFlags |= CONTEXT_FLOATING_POINT;
1005 __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
1006 #endif
1010 /***********************************************************************
1011 * save_fpux
1013 * Save the thread FPU extended context.
1015 static inline void save_fpux( CONTEXT *context )
1017 #ifdef __GNUC__
1018 /* we have to enforce alignment by hand */
1019 char buffer[sizeof(XMM_SAVE_AREA32) + 16];
1020 XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
1022 __asm__ __volatile__( "fxsave %0" : "=m" (*state) );
1023 context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1024 memcpy( context->ExtendedRegisters, state, sizeof(*state) );
1025 #endif
1029 /***********************************************************************
1030 * restore_fpu
1032 * Restore the FPU context to a sigcontext.
1034 static inline void restore_fpu( const CONTEXT *context )
1036 FLOATING_SAVE_AREA float_status = context->FloatSave;
1037 /* reset the current interrupt status */
1038 float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
1039 #ifdef __GNUC__
1040 __asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) );
1041 #endif /* __GNUC__ */
1045 /***********************************************************************
1046 * restore_fpux
1048 * Restore the FPU extended context to a sigcontext.
1050 static inline void restore_fpux( const CONTEXT *context )
1052 #ifdef __GNUC__
1053 /* we have to enforce alignment by hand */
1054 char buffer[sizeof(XMM_SAVE_AREA32) + 16];
1055 XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
1057 memcpy( state, context->ExtendedRegisters, sizeof(*state) );
1058 /* reset the current interrupt status */
1059 state->StatusWord &= state->ControlWord | 0xff80;
1060 __asm__ __volatile__( "fxrstor %0" : : "m" (*state) );
1061 #endif
1065 /***********************************************************************
1066 * fpux_to_fpu
1068 * Build a standard FPU context from an extended one.
1070 static void fpux_to_fpu( FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux )
1072 unsigned int i, tag, stack_top;
1074 fpu->ControlWord = fpux->ControlWord | 0xffff0000;
1075 fpu->StatusWord = fpux->StatusWord | 0xffff0000;
1076 fpu->ErrorOffset = fpux->ErrorOffset;
1077 fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16);
1078 fpu->DataOffset = fpux->DataOffset;
1079 fpu->DataSelector = fpux->DataSelector;
1080 fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000;
1082 stack_top = (fpux->StatusWord >> 11) & 7;
1083 fpu->TagWord = 0xffff0000;
1084 for (i = 0; i < 8; i++)
1086 memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 );
1087 if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */
1088 else
1090 const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7];
1091 if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */
1093 tag = 2; /* special */
1095 else if (!(reg->High & 0x7fff)) /* exponent all zeroes */
1097 if (reg->Low) tag = 2; /* special */
1098 else tag = 1; /* zero */
1100 else
1102 if (reg->Low >> 63) tag = 0; /* valid */
1103 else tag = 2; /* special */
1106 fpu->TagWord |= tag << (2 * i);
1111 /***********************************************************************
1112 * save_context
1114 * Build a context structure from the signal info.
1116 static inline void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
1118 struct ntdll_thread_data * const regs = ntdll_get_thread_data();
1119 FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext);
1120 XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext);
1122 memset(context, 0, sizeof(*context));
1123 context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
1124 context->Eax = EAX_sig(sigcontext);
1125 context->Ebx = EBX_sig(sigcontext);
1126 context->Ecx = ECX_sig(sigcontext);
1127 context->Edx = EDX_sig(sigcontext);
1128 context->Esi = ESI_sig(sigcontext);
1129 context->Edi = EDI_sig(sigcontext);
1130 context->Ebp = EBP_sig(sigcontext);
1131 context->EFlags = EFL_sig(sigcontext);
1132 context->Eip = EIP_sig(sigcontext);
1133 context->Esp = ESP_sig(sigcontext);
1134 context->SegCs = LOWORD(CS_sig(sigcontext));
1135 context->SegDs = LOWORD(DS_sig(sigcontext));
1136 context->SegEs = LOWORD(ES_sig(sigcontext));
1137 context->SegFs = fs;
1138 context->SegGs = gs;
1139 context->SegSs = LOWORD(SS_sig(sigcontext));
1140 context->Dr0 = regs->dr0;
1141 context->Dr1 = regs->dr1;
1142 context->Dr2 = regs->dr2;
1143 context->Dr3 = regs->dr3;
1144 context->Dr6 = regs->dr6;
1145 context->Dr7 = regs->dr7;
1147 if (fpu)
1149 context->ContextFlags |= CONTEXT_FLOATING_POINT;
1150 context->FloatSave = *fpu;
1152 if (fpux)
1154 context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
1155 memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) );
1156 fpux_support = TRUE;
1157 if (!fpu) fpux_to_fpu( &context->FloatSave, fpux );
1159 if (!fpu && !fpux) save_fpu( context );
1163 /***********************************************************************
1164 * restore_context
1166 * Restore the signal info from the context.
1168 static inline void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
1170 struct ntdll_thread_data * const regs = ntdll_get_thread_data();
1171 FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext);
1172 XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext);
1174 regs->dr0 = context->Dr0;
1175 regs->dr1 = context->Dr1;
1176 regs->dr2 = context->Dr2;
1177 regs->dr3 = context->Dr3;
1178 regs->dr6 = context->Dr6;
1179 regs->dr7 = context->Dr7;
1180 EAX_sig(sigcontext) = context->Eax;
1181 EBX_sig(sigcontext) = context->Ebx;
1182 ECX_sig(sigcontext) = context->Ecx;
1183 EDX_sig(sigcontext) = context->Edx;
1184 ESI_sig(sigcontext) = context->Esi;
1185 EDI_sig(sigcontext) = context->Edi;
1186 EBP_sig(sigcontext) = context->Ebp;
1187 EFL_sig(sigcontext) = context->EFlags;
1188 EIP_sig(sigcontext) = context->Eip;
1189 ESP_sig(sigcontext) = context->Esp;
1190 CS_sig(sigcontext) = context->SegCs;
1191 DS_sig(sigcontext) = context->SegDs;
1192 ES_sig(sigcontext) = context->SegEs;
1193 SS_sig(sigcontext) = context->SegSs;
1194 #ifdef GS_sig
1195 GS_sig(sigcontext) = context->SegGs;
1196 #else
1197 wine_set_gs( context->SegGs );
1198 #endif
1199 #ifdef FS_sig
1200 FS_sig(sigcontext) = context->SegFs;
1201 #else
1202 wine_set_fs( context->SegFs );
1203 #endif
1205 if (fpu) *fpu = context->FloatSave;
1206 if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) );
1207 if (!fpu && !fpux) restore_fpu( context );
1211 /***********************************************************************
1212 * RtlCaptureContext (NTDLL.@)
1214 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
1215 "pushl %eax\n\t"
1216 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1217 "movl 8(%esp),%eax\n\t" /* context */
1218 "movl $0x10007,(%eax)\n\t" /* context->ContextFlags */
1219 "movw %gs,0x8c(%eax)\n\t" /* context->SegGs */
1220 "movw %fs,0x90(%eax)\n\t" /* context->SegFs */
1221 "movw %es,0x94(%eax)\n\t" /* context->SegEs */
1222 "movw %ds,0x98(%eax)\n\t" /* context->SegDs */
1223 "movl %edi,0x9c(%eax)\n\t" /* context->Edi */
1224 "movl %esi,0xa0(%eax)\n\t" /* context->Esi */
1225 "movl %ebx,0xa4(%eax)\n\t" /* context->Ebx */
1226 "movl %edx,0xa8(%eax)\n\t" /* context->Edx */
1227 "movl %ecx,0xac(%eax)\n\t" /* context->Ecx */
1228 "movl %ebp,0xb4(%eax)\n\t" /* context->Ebp */
1229 "movl 4(%esp),%edx\n\t"
1230 "movl %edx,0xb8(%eax)\n\t" /* context->Eip */
1231 "movw %cs,0xbc(%eax)\n\t" /* context->SegCs */
1232 "pushfl\n\t"
1233 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1234 "popl 0xc0(%eax)\n\t" /* context->EFlags */
1235 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
1236 "leal 8(%esp),%edx\n\t"
1237 "movl %edx,0xc4(%eax)\n\t" /* context->Esp */
1238 "movw %ss,0xc8(%eax)\n\t" /* context->SegSs */
1239 "popl 0xb0(%eax)\n\t" /* context->Eax */
1240 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
1241 "ret $4" )
1244 /***********************************************************************
1245 * set_cpu_context
1247 * Set the new CPU context. Used by NtSetContextThread.
1249 void set_cpu_context( const CONTEXT *context )
1251 DWORD flags = context->ContextFlags & ~CONTEXT_i386;
1253 if ((flags & CONTEXT_EXTENDED_REGISTERS) && fpux_support) restore_fpux( context );
1254 else if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
1256 if (flags & CONTEXT_DEBUG_REGISTERS)
1258 ntdll_get_thread_data()->dr0 = context->Dr0;
1259 ntdll_get_thread_data()->dr1 = context->Dr1;
1260 ntdll_get_thread_data()->dr2 = context->Dr2;
1261 ntdll_get_thread_data()->dr3 = context->Dr3;
1262 ntdll_get_thread_data()->dr6 = context->Dr6;
1263 ntdll_get_thread_data()->dr7 = context->Dr7;
1265 if (flags & CONTEXT_FULL)
1267 if (!(flags & CONTEXT_CONTROL))
1268 FIXME( "setting partial context (%x) not supported\n", flags );
1269 else if (flags & CONTEXT_SEGMENTS)
1270 __wine_restore_regs( context );
1271 else
1273 CONTEXT newcontext = *context;
1274 newcontext.SegDs = wine_get_ds();
1275 newcontext.SegEs = wine_get_es();
1276 newcontext.SegFs = wine_get_fs();
1277 newcontext.SegGs = wine_get_gs();
1278 __wine_restore_regs( &newcontext );
1284 /***********************************************************************
1285 * set_debug_registers
1287 static void set_debug_registers( const CONTEXT *context )
1289 DWORD flags = context->ContextFlags & ~CONTEXT_i386;
1290 context_t server_context;
1292 if (!(flags & CONTEXT_DEBUG_REGISTERS)) return;
1293 if (ntdll_get_thread_data()->dr0 == context->Dr0 &&
1294 ntdll_get_thread_data()->dr1 == context->Dr1 &&
1295 ntdll_get_thread_data()->dr2 == context->Dr2 &&
1296 ntdll_get_thread_data()->dr3 == context->Dr3 &&
1297 ntdll_get_thread_data()->dr6 == context->Dr6 &&
1298 ntdll_get_thread_data()->dr7 == context->Dr7) return;
1300 context_to_server( &server_context, context );
1302 SERVER_START_REQ( set_thread_context )
1304 req->handle = wine_server_obj_handle( GetCurrentThread() );
1305 req->suspend = 0;
1306 wine_server_add_data( req, &server_context, sizeof(server_context) );
1307 wine_server_call( req );
1309 SERVER_END_REQ;
1313 /***********************************************************************
1314 * copy_context
1316 * Copy a register context according to the flags.
1318 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
1320 flags &= ~CONTEXT_i386; /* get rid of CPU id */
1321 if (flags & CONTEXT_INTEGER)
1323 to->Eax = from->Eax;
1324 to->Ebx = from->Ebx;
1325 to->Ecx = from->Ecx;
1326 to->Edx = from->Edx;
1327 to->Esi = from->Esi;
1328 to->Edi = from->Edi;
1330 if (flags & CONTEXT_CONTROL)
1332 to->Ebp = from->Ebp;
1333 to->Esp = from->Esp;
1334 to->Eip = from->Eip;
1335 to->SegCs = from->SegCs;
1336 to->SegSs = from->SegSs;
1337 to->EFlags = from->EFlags;
1339 if (flags & CONTEXT_SEGMENTS)
1341 to->SegDs = from->SegDs;
1342 to->SegEs = from->SegEs;
1343 to->SegFs = from->SegFs;
1344 to->SegGs = from->SegGs;
1346 if (flags & CONTEXT_DEBUG_REGISTERS)
1348 to->Dr0 = from->Dr0;
1349 to->Dr1 = from->Dr1;
1350 to->Dr2 = from->Dr2;
1351 to->Dr3 = from->Dr3;
1352 to->Dr6 = from->Dr6;
1353 to->Dr7 = from->Dr7;
1355 if (flags & CONTEXT_FLOATING_POINT)
1357 to->FloatSave = from->FloatSave;
1359 if (flags & CONTEXT_EXTENDED_REGISTERS)
1361 memcpy( to->ExtendedRegisters, from->ExtendedRegisters, sizeof(to->ExtendedRegisters) );
1366 /***********************************************************************
1367 * context_to_server
1369 * Convert a register context to the server format.
1371 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
1373 DWORD flags = from->ContextFlags & ~CONTEXT_i386; /* get rid of CPU id */
1375 memset( to, 0, sizeof(*to) );
1376 to->cpu = CPU_x86;
1378 if (flags & CONTEXT_CONTROL)
1380 to->flags |= SERVER_CTX_CONTROL;
1381 to->ctl.i386_regs.ebp = from->Ebp;
1382 to->ctl.i386_regs.esp = from->Esp;
1383 to->ctl.i386_regs.eip = from->Eip;
1384 to->ctl.i386_regs.cs = from->SegCs;
1385 to->ctl.i386_regs.ss = from->SegSs;
1386 to->ctl.i386_regs.eflags = from->EFlags;
1388 if (flags & CONTEXT_INTEGER)
1390 to->flags |= SERVER_CTX_INTEGER;
1391 to->integer.i386_regs.eax = from->Eax;
1392 to->integer.i386_regs.ebx = from->Ebx;
1393 to->integer.i386_regs.ecx = from->Ecx;
1394 to->integer.i386_regs.edx = from->Edx;
1395 to->integer.i386_regs.esi = from->Esi;
1396 to->integer.i386_regs.edi = from->Edi;
1398 if (flags & CONTEXT_SEGMENTS)
1400 to->flags |= SERVER_CTX_SEGMENTS;
1401 to->seg.i386_regs.ds = from->SegDs;
1402 to->seg.i386_regs.es = from->SegEs;
1403 to->seg.i386_regs.fs = from->SegFs;
1404 to->seg.i386_regs.gs = from->SegGs;
1406 if (flags & CONTEXT_FLOATING_POINT)
1408 to->flags |= SERVER_CTX_FLOATING_POINT;
1409 to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
1410 to->fp.i386_regs.status = from->FloatSave.StatusWord;
1411 to->fp.i386_regs.tag = from->FloatSave.TagWord;
1412 to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
1413 to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
1414 to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
1415 to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
1416 to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
1417 memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
1419 if (flags & CONTEXT_DEBUG_REGISTERS)
1421 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
1422 to->debug.i386_regs.dr0 = from->Dr0;
1423 to->debug.i386_regs.dr1 = from->Dr1;
1424 to->debug.i386_regs.dr2 = from->Dr2;
1425 to->debug.i386_regs.dr3 = from->Dr3;
1426 to->debug.i386_regs.dr6 = from->Dr6;
1427 to->debug.i386_regs.dr7 = from->Dr7;
1429 if (flags & CONTEXT_EXTENDED_REGISTERS)
1431 to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
1432 memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
1434 return STATUS_SUCCESS;
1438 /***********************************************************************
1439 * context_from_server
1441 * Convert a register context from the server format.
1443 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
1445 if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
1447 to->ContextFlags = CONTEXT_i386;
1448 if (from->flags & SERVER_CTX_CONTROL)
1450 to->ContextFlags |= CONTEXT_CONTROL;
1451 to->Ebp = from->ctl.i386_regs.ebp;
1452 to->Esp = from->ctl.i386_regs.esp;
1453 to->Eip = from->ctl.i386_regs.eip;
1454 to->SegCs = from->ctl.i386_regs.cs;
1455 to->SegSs = from->ctl.i386_regs.ss;
1456 to->EFlags = from->ctl.i386_regs.eflags;
1458 if (from->flags & SERVER_CTX_INTEGER)
1460 to->ContextFlags |= CONTEXT_INTEGER;
1461 to->Eax = from->integer.i386_regs.eax;
1462 to->Ebx = from->integer.i386_regs.ebx;
1463 to->Ecx = from->integer.i386_regs.ecx;
1464 to->Edx = from->integer.i386_regs.edx;
1465 to->Esi = from->integer.i386_regs.esi;
1466 to->Edi = from->integer.i386_regs.edi;
1468 if (from->flags & SERVER_CTX_SEGMENTS)
1470 to->ContextFlags |= CONTEXT_SEGMENTS;
1471 to->SegDs = from->seg.i386_regs.ds;
1472 to->SegEs = from->seg.i386_regs.es;
1473 to->SegFs = from->seg.i386_regs.fs;
1474 to->SegGs = from->seg.i386_regs.gs;
1476 if (from->flags & SERVER_CTX_FLOATING_POINT)
1478 to->ContextFlags |= CONTEXT_FLOATING_POINT;
1479 to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
1480 to->FloatSave.StatusWord = from->fp.i386_regs.status;
1481 to->FloatSave.TagWord = from->fp.i386_regs.tag;
1482 to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
1483 to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
1484 to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
1485 to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
1486 to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
1487 memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
1489 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
1491 to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
1492 to->Dr0 = from->debug.i386_regs.dr0;
1493 to->Dr1 = from->debug.i386_regs.dr1;
1494 to->Dr2 = from->debug.i386_regs.dr2;
1495 to->Dr3 = from->debug.i386_regs.dr3;
1496 to->Dr6 = from->debug.i386_regs.dr6;
1497 to->Dr7 = from->debug.i386_regs.dr7;
1499 if (from->flags & SERVER_CTX_EXTENDED_REGISTERS)
1501 to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1502 memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
1504 return STATUS_SUCCESS;
1508 /***********************************************************************
1509 * is_privileged_instr
1511 * Check if the fault location is a privileged instruction.
1512 * Based on the instruction emulation code in dlls/kernel/instr.c.
1514 static inline DWORD is_privileged_instr( CONTEXT *context )
1516 const BYTE *instr;
1517 unsigned int prefix_count = 0;
1519 if (!wine_ldt_is_system( context->SegCs )) return 0;
1520 instr = (BYTE *)context->Eip;
1522 for (;;) switch(*instr)
1524 /* instruction prefixes */
1525 case 0x2e: /* %cs: */
1526 case 0x36: /* %ss: */
1527 case 0x3e: /* %ds: */
1528 case 0x26: /* %es: */
1529 case 0x64: /* %fs: */
1530 case 0x65: /* %gs: */
1531 case 0x66: /* opcode size */
1532 case 0x67: /* addr size */
1533 case 0xf0: /* lock */
1534 case 0xf2: /* repne */
1535 case 0xf3: /* repe */
1536 if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION;
1537 instr++;
1538 continue;
1540 case 0x0f: /* extended instruction */
1541 switch(instr[1])
1543 case 0x20: /* mov crX, reg */
1544 case 0x21: /* mov drX, reg */
1545 case 0x22: /* mov reg, crX */
1546 case 0x23: /* mov reg drX */
1547 return EXCEPTION_PRIV_INSTRUCTION;
1549 return 0;
1550 case 0x6c: /* insb (%dx) */
1551 case 0x6d: /* insl (%dx) */
1552 case 0x6e: /* outsb (%dx) */
1553 case 0x6f: /* outsl (%dx) */
1554 case 0xcd: /* int $xx */
1555 case 0xe4: /* inb al,XX */
1556 case 0xe5: /* in (e)ax,XX */
1557 case 0xe6: /* outb XX,al */
1558 case 0xe7: /* out XX,(e)ax */
1559 case 0xec: /* inb (%dx),%al */
1560 case 0xed: /* inl (%dx),%eax */
1561 case 0xee: /* outb %al,(%dx) */
1562 case 0xef: /* outl %eax,(%dx) */
1563 case 0xf4: /* hlt */
1564 case 0xfa: /* cli */
1565 case 0xfb: /* sti */
1566 return EXCEPTION_PRIV_INSTRUCTION;
1567 default:
1568 return 0;
1572 /***********************************************************************
1573 * check_invalid_gs
1575 * Check for fault caused by invalid %gs value (some copy protection schemes mess with it).
1577 static inline BOOL check_invalid_gs( CONTEXT *context )
1579 unsigned int prefix_count = 0;
1580 const BYTE *instr = (BYTE *)context->Eip;
1581 WORD system_gs = ntdll_get_thread_data()->gs;
1583 if (context->SegGs == system_gs) return FALSE;
1584 if (!wine_ldt_is_system( context->SegCs )) return FALSE;
1585 /* only handle faults in system libraries */
1586 if (virtual_is_valid_code_address( instr, 1 )) return FALSE;
1588 for (;;) switch(*instr)
1590 /* instruction prefixes */
1591 case 0x2e: /* %cs: */
1592 case 0x36: /* %ss: */
1593 case 0x3e: /* %ds: */
1594 case 0x26: /* %es: */
1595 case 0x64: /* %fs: */
1596 case 0x66: /* opcode size */
1597 case 0x67: /* addr size */
1598 case 0xf0: /* lock */
1599 case 0xf2: /* repne */
1600 case 0xf3: /* repe */
1601 if (++prefix_count >= 15) return FALSE;
1602 instr++;
1603 continue;
1604 case 0x65: /* %gs: */
1605 TRACE( "%04x/%04x at %p, fixing up\n", context->SegGs, system_gs, instr );
1606 context->SegGs = system_gs;
1607 return TRUE;
1608 default:
1609 return FALSE;
1614 #include "pshpack1.h"
1615 struct atl_thunk
1617 DWORD movl; /* movl this,4(%esp) */
1618 DWORD this;
1619 BYTE jmp; /* jmp func */
1620 int func;
1622 #include "poppack.h"
1624 /**********************************************************************
1625 * check_atl_thunk
1627 * Check if code destination is an ATL thunk, and emulate it if so.
1629 static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
1631 const struct atl_thunk *thunk = (const struct atl_thunk *)rec->ExceptionInformation[1];
1632 BOOL ret = FALSE;
1634 if (!virtual_is_valid_code_address( thunk, sizeof(*thunk) )) return FALSE;
1636 __TRY
1638 if (thunk->movl == 0x042444c7 && thunk->jmp == 0xe9)
1640 *((DWORD *)context->Esp + 1) = thunk->this;
1641 context->Eip = (DWORD_PTR)(&thunk->func + 1) + thunk->func;
1642 TRACE( "emulating ATL thunk at %p, func=%08x arg=%08x\n",
1643 thunk, context->Eip, *((DWORD *)context->Esp + 1) );
1644 ret = TRUE;
1647 __EXCEPT_PAGE_FAULT
1649 return FALSE;
1651 __ENDTRY
1652 return ret;
1656 /***********************************************************************
1657 * setup_exception_record
1659 * Setup the exception record and context on the thread stack.
1661 static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *stack_ptr,
1662 WORD fs, WORD gs, raise_func func )
1664 struct stack_layout
1666 void *ret_addr; /* return address from raise_func */
1667 EXCEPTION_RECORD *rec_ptr; /* first arg for raise_func */
1668 CONTEXT *context_ptr; /* second arg for raise_func */
1669 CONTEXT context;
1670 EXCEPTION_RECORD rec;
1671 DWORD ebp;
1672 DWORD eip;
1673 } *stack = stack_ptr;
1674 DWORD exception_code = 0;
1676 /* stack sanity checks */
1678 if ((char *)stack >= (char *)get_signal_stack() &&
1679 (char *)stack < (char *)get_signal_stack() + signal_stack_size)
1681 WINE_ERR( "nested exception on signal stack in thread %04x eip %08x esp %08x stack %p-%p\n",
1682 GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
1683 (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
1684 NtCurrentTeb()->Tib.StackBase );
1685 abort_thread(1);
1688 if (stack - 1 > stack || /* check for overflow in subtraction */
1689 (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
1690 (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
1692 WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n",
1693 GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
1694 (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
1695 NtCurrentTeb()->Tib.StackBase );
1697 else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096)
1699 /* stack overflow on last page, unrecoverable */
1700 UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1);
1701 WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
1702 diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
1703 (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
1704 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
1705 abort_thread(1);
1707 else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
1709 /* stack access below stack limit, may be recoverable */
1710 if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
1711 else
1713 UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
1714 WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
1715 diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
1716 (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
1717 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
1718 abort_thread(1);
1722 stack--; /* push the stack_layout structure */
1723 #if defined(VALGRIND_MAKE_MEM_UNDEFINED)
1724 VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack));
1725 #elif defined(VALGRIND_MAKE_WRITABLE)
1726 VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
1727 #endif
1728 stack->ret_addr = (void *)0xdeadbabe; /* raise_func must not return */
1729 stack->rec_ptr = &stack->rec;
1730 stack->context_ptr = &stack->context;
1732 stack->rec.ExceptionRecord = NULL;
1733 stack->rec.ExceptionCode = exception_code;
1734 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
1735 stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
1736 stack->rec.NumberParameters = 0;
1738 save_context( &stack->context, sigcontext, fs, gs );
1740 /* now modify the sigcontext to return to the raise function */
1741 ESP_sig(sigcontext) = (DWORD)stack;
1742 EIP_sig(sigcontext) = (DWORD)func;
1743 /* clear single-step, direction, and align check flag */
1744 EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000);
1745 CS_sig(sigcontext) = wine_get_cs();
1746 DS_sig(sigcontext) = wine_get_ds();
1747 ES_sig(sigcontext) = wine_get_es();
1748 FS_sig(sigcontext) = wine_get_fs();
1749 GS_sig(sigcontext) = wine_get_gs();
1750 SS_sig(sigcontext) = wine_get_ss();
1752 return stack->rec_ptr;
1756 /***********************************************************************
1757 * setup_exception
1759 * Setup a proper stack frame for the raise function, and modify the
1760 * sigcontext so that the return from the signal handler will call
1761 * the raise function.
1763 static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
1765 WORD fs, gs;
1766 void *stack = init_handler( sigcontext, &fs, &gs );
1768 return setup_exception_record( sigcontext, stack, fs, gs, func );
1772 /***********************************************************************
1773 * get_exception_context
1775 * Get a pointer to the context built by setup_exception.
1777 static inline CONTEXT *get_exception_context( EXCEPTION_RECORD *rec )
1779 return (CONTEXT *)rec - 1; /* cf. stack_layout structure */
1783 /**********************************************************************
1784 * get_fpu_code
1786 * Get the FPU exception code from the FPU status.
1788 static inline DWORD get_fpu_code( const CONTEXT *context )
1790 DWORD status = context->FloatSave.StatusWord & ~(context->FloatSave.ControlWord & 0x3f);
1792 if (status & 0x01) /* IE */
1794 if (status & 0x40) /* SF */
1795 return EXCEPTION_FLT_STACK_CHECK;
1796 else
1797 return EXCEPTION_FLT_INVALID_OPERATION;
1799 if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND; /* DE flag */
1800 if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO; /* ZE flag */
1801 if (status & 0x08) return EXCEPTION_FLT_OVERFLOW; /* OE flag */
1802 if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW; /* UE flag */
1803 if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT; /* PE flag */
1804 return EXCEPTION_FLT_INVALID_OPERATION; /* generic error */
1808 /**********************************************************************
1809 * raise_segv_exception
1811 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1813 NTSTATUS status;
1815 switch(rec->ExceptionCode)
1817 case EXCEPTION_ACCESS_VIOLATION:
1818 if (rec->NumberParameters == 2)
1820 if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT && check_atl_thunk( rec, context ))
1821 goto done;
1822 if (rec->ExceptionInformation[1] == 0xffffffff && check_invalid_gs( context ))
1823 goto done;
1824 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
1825 rec->ExceptionInformation[0] )))
1826 goto done;
1827 /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
1828 if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
1830 ULONG flags;
1831 NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
1832 &flags, sizeof(flags), NULL );
1833 if (!(flags & MEM_EXECUTE_OPTION_DISABLE))
1834 rec->ExceptionInformation[0] = EXCEPTION_READ_FAULT;
1837 break;
1838 case EXCEPTION_DATATYPE_MISALIGNMENT:
1839 /* FIXME: pass through exception handler first? */
1840 if (context->EFlags & 0x00040000)
1842 /* Disable AC flag, return */
1843 context->EFlags &= ~0x00040000;
1844 goto done;
1846 break;
1848 status = NtRaiseException( rec, context, TRUE );
1849 raise_status( status, rec );
1850 done:
1851 set_cpu_context( context );
1855 /**********************************************************************
1856 * raise_trap_exception
1858 static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1860 NTSTATUS status;
1862 if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
1864 /* when single stepping can't tell whether this is a hw bp or a
1865 * single step interrupt. try to avoid as much overhead as possible
1866 * and only do a server call if there is any hw bp enabled. */
1868 if( !(context->EFlags & 0x100) || (ntdll_get_thread_data()->dr7 & 0xff) )
1870 /* (possible) hardware breakpoint, fetch the debug registers */
1871 context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
1872 NtGetContextThread(GetCurrentThread(), context);
1873 context->ContextFlags |= CONTEXT_FULL; /* restore flags */
1876 context->EFlags &= ~0x100; /* clear single-step flag */
1879 status = NtRaiseException( rec, context, TRUE );
1880 raise_status( status, rec );
1884 /**********************************************************************
1885 * raise_generic_exception
1887 * Generic raise function for exceptions that don't need special treatment.
1889 static void WINAPI raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1891 NTSTATUS status;
1893 status = NtRaiseException( rec, context, TRUE );
1894 raise_status( status, rec );
1898 #ifdef __HAVE_VM86
1899 /**********************************************************************
1900 * raise_vm86_sti_exception
1902 static void WINAPI raise_vm86_sti_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1904 /* merge_vm86_pending_flags merges the vm86_pending flag in safely */
1905 get_vm86_teb_info()->vm86_pending |= VIP_FLAG;
1907 if (ntdll_get_thread_data()->vm86_ptr)
1909 if (((char*)context->Eip >= (char*)vm86_return) &&
1910 ((char*)context->Eip <= (char*)vm86_return_end) &&
1911 (VM86_TYPE(context->Eax) != VM86_SIGNAL)) {
1912 /* exiting from VM86, can't throw */
1913 goto done;
1915 merge_vm86_pending_flags( rec );
1917 else if (get_vm86_teb_info()->dpmi_vif &&
1918 !wine_ldt_is_system(context->SegCs) &&
1919 !wine_ldt_is_system(context->SegSs))
1921 /* Executing DPMI code and virtual interrupts are enabled. */
1922 get_vm86_teb_info()->vm86_pending = 0;
1923 NtRaiseException( rec, context, TRUE );
1925 done:
1926 set_cpu_context( context );
1930 /**********************************************************************
1931 * usr2_handler
1933 * Handler for SIGUSR2.
1934 * We use it to signal that the running __wine_enter_vm86() should
1935 * immediately set VIP_FLAG, causing pending events to be handled
1936 * as early as possible.
1938 static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1940 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_vm86_sti_exception );
1941 rec->ExceptionCode = EXCEPTION_VM86_STI;
1943 #endif /* __HAVE_VM86 */
1946 /**********************************************************************
1947 * segv_handler
1949 * Handler for SIGSEGV and related errors.
1951 static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1953 WORD fs, gs;
1954 EXCEPTION_RECORD *rec;
1955 SIGCONTEXT *context = sigcontext;
1956 void *stack = init_handler( sigcontext, &fs, &gs );
1958 /* check for page fault inside the thread stack */
1959 if (get_trap_code(context) == TRAP_x86_PAGEFLT &&
1960 (char *)siginfo->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
1961 (char *)siginfo->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
1962 virtual_handle_stack_fault( siginfo->si_addr ))
1964 /* check if this was the last guard page */
1965 if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
1967 rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
1968 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1970 return;
1973 rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
1974 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
1976 switch(get_trap_code(context))
1978 case TRAP_x86_OFLOW: /* Overflow exception */
1979 rec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
1980 break;
1981 case TRAP_x86_BOUND: /* Bound range exception */
1982 rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1983 break;
1984 case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */
1985 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1986 break;
1987 case TRAP_x86_STKFLT: /* Stack fault */
1988 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1989 break;
1990 case TRAP_x86_SEGNPFLT: /* Segment not present exception */
1991 case TRAP_x86_PROTFLT: /* General protection fault */
1992 case TRAP_x86_UNKNOWN: /* Unknown fault code */
1994 WORD err = get_error_code(context);
1995 if (!err && (rec->ExceptionCode = is_privileged_instr( get_exception_context(rec) ))) break;
1996 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1997 rec->NumberParameters = 2;
1998 rec->ExceptionInformation[0] = 0;
1999 /* if error contains a LDT selector, use that as fault address */
2000 if ((err & 7) == 4 && !wine_ldt_is_system( err | 7 ))
2001 rec->ExceptionInformation[1] = err & ~7;
2002 else
2003 rec->ExceptionInformation[1] = 0xffffffff;
2005 break;
2006 case TRAP_x86_PAGEFLT: /* Page fault */
2007 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
2008 rec->NumberParameters = 2;
2009 rec->ExceptionInformation[0] = (get_error_code(context) >> 1) & 0x09;
2010 rec->ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
2011 break;
2012 case TRAP_x86_ALIGNFLT: /* Alignment check exception */
2013 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
2014 break;
2015 default:
2016 WINE_ERR( "Got unexpected trap %d\n", get_trap_code(context) );
2017 /* fall through */
2018 case TRAP_x86_NMI: /* NMI interrupt */
2019 case TRAP_x86_DNA: /* Device not available exception */
2020 case TRAP_x86_DOUBLEFLT: /* Double fault exception */
2021 case TRAP_x86_TSSFLT: /* Invalid TSS exception */
2022 case TRAP_x86_MCHK: /* Machine check exception */
2023 case TRAP_x86_CACHEFLT: /* Cache flush exception */
2024 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
2025 break;
2030 /**********************************************************************
2031 * trap_handler
2033 * Handler for SIGTRAP.
2035 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2037 SIGCONTEXT *context = sigcontext;
2038 EXCEPTION_RECORD *rec = setup_exception( context, raise_trap_exception );
2040 switch(get_trap_code(context))
2042 case TRAP_x86_TRCTRAP: /* Single-step exception */
2043 rec->ExceptionCode = EXCEPTION_SINGLE_STEP;
2044 break;
2045 case TRAP_x86_BPTFLT: /* Breakpoint exception */
2046 rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1; /* back up over the int3 instruction */
2047 /* fall through */
2048 default:
2049 rec->ExceptionCode = EXCEPTION_BREAKPOINT;
2050 break;
2055 /**********************************************************************
2056 * fpe_handler
2058 * Handler for SIGFPE.
2060 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2062 CONTEXT *win_context;
2063 SIGCONTEXT *context = sigcontext;
2064 EXCEPTION_RECORD *rec = setup_exception( context, raise_generic_exception );
2066 win_context = get_exception_context( rec );
2068 switch(get_trap_code(context))
2070 case TRAP_x86_DIVIDE: /* Division by zero exception */
2071 rec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
2072 break;
2073 case TRAP_x86_FPOPFLT: /* Coprocessor segment overrun */
2074 rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
2075 break;
2076 case TRAP_x86_ARITHTRAP: /* Floating point exception */
2077 case TRAP_x86_UNKNOWN: /* Unknown fault code */
2078 rec->ExceptionCode = get_fpu_code( win_context );
2079 rec->ExceptionAddress = (LPVOID)win_context->FloatSave.ErrorOffset;
2080 break;
2081 case TRAP_x86_CACHEFLT: /* SIMD exception */
2082 /* TODO:
2083 * Behaviour only tested for divide-by-zero exceptions
2084 * Check for other SIMD exceptions as well */
2085 if(siginfo->si_code != FPE_FLTDIV)
2086 FIXME("untested SIMD exception: %#x. Might not work correctly\n",
2087 siginfo->si_code);
2089 rec->ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
2090 rec->NumberParameters = 1;
2091 /* no idea what meaning is actually behind this but that's what native does */
2092 rec->ExceptionInformation[0] = 0;
2093 break;
2094 default:
2095 WINE_ERR( "Got unexpected trap %d\n", get_trap_code(context) );
2096 rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
2097 break;
2102 /**********************************************************************
2103 * int_handler
2105 * Handler for SIGINT.
2107 * FIXME: should not be calling external functions on the signal stack.
2109 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2111 WORD fs, gs;
2112 init_handler( sigcontext, &fs, &gs );
2113 if (!dispatch_signal(SIGINT))
2115 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
2116 rec->ExceptionCode = CONTROL_C_EXIT;
2120 /**********************************************************************
2121 * abrt_handler
2123 * Handler for SIGABRT.
2125 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2127 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
2128 rec->ExceptionCode = EXCEPTION_WINE_ASSERTION;
2129 rec->ExceptionFlags = EH_NONCONTINUABLE;
2133 /**********************************************************************
2134 * quit_handler
2136 * Handler for SIGQUIT.
2138 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2140 WORD fs, gs;
2141 init_handler( sigcontext, &fs, &gs );
2142 abort_thread(0);
2146 /**********************************************************************
2147 * usr1_handler
2149 * Handler for SIGUSR1, used to signal a thread that it got suspended.
2151 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
2153 CONTEXT context;
2154 WORD fs, gs;
2156 init_handler( sigcontext, &fs, &gs );
2157 save_context( &context, sigcontext, fs, gs );
2158 wait_suspend( &context );
2159 restore_context( &context, sigcontext );
2163 /***********************************************************************
2164 * __wine_set_signal_handler (NTDLL.@)
2166 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
2168 if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1;
2169 if (handlers[sig] != NULL) return -2;
2170 handlers[sig] = wsh;
2171 return 0;
2175 /***********************************************************************
2176 * locking for LDT routines
2178 static RTL_CRITICAL_SECTION ldt_section;
2179 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
2181 0, 0, &ldt_section,
2182 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
2183 0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") }
2185 static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 };
2186 static sigset_t ldt_sigset;
2188 static void ldt_lock(void)
2190 sigset_t sigset;
2192 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
2193 RtlEnterCriticalSection( &ldt_section );
2194 if (ldt_section.RecursionCount == 1) ldt_sigset = sigset;
2197 static void ldt_unlock(void)
2199 if (ldt_section.RecursionCount == 1)
2201 sigset_t sigset = ldt_sigset;
2202 RtlLeaveCriticalSection( &ldt_section );
2203 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
2205 else RtlLeaveCriticalSection( &ldt_section );
2209 /**********************************************************************
2210 * signal_alloc_thread
2212 NTSTATUS signal_alloc_thread( TEB **teb )
2214 static size_t sigstack_zero_bits;
2215 struct ntdll_thread_data *thread_data;
2216 struct ntdll_thread_data *parent_data = NULL;
2217 SIZE_T size;
2218 void *addr = NULL;
2219 NTSTATUS status;
2221 if (!sigstack_zero_bits)
2223 size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 );
2224 /* find the first power of two not smaller than min_size */
2225 sigstack_zero_bits = 12;
2226 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
2227 signal_stack_mask = (1 << sigstack_zero_bits) - 1;
2228 signal_stack_size = (1 << sigstack_zero_bits) - teb_size;
2230 else parent_data = ntdll_get_thread_data();
2232 size = signal_stack_mask + 1;
2233 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits,
2234 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
2236 *teb = addr;
2237 (*teb)->Tib.Self = &(*teb)->Tib;
2238 (*teb)->Tib.ExceptionList = (void *)~0UL;
2239 thread_data = (struct ntdll_thread_data *)(*teb)->SpareBytes1;
2240 if (!(thread_data->fs = wine_ldt_alloc_fs()))
2242 size = 0;
2243 NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE );
2244 status = STATUS_TOO_MANY_THREADS;
2246 if (parent_data)
2248 /* inherit debug registers from parent thread */
2249 thread_data->dr0 = parent_data->dr0;
2250 thread_data->dr1 = parent_data->dr1;
2251 thread_data->dr2 = parent_data->dr2;
2252 thread_data->dr3 = parent_data->dr3;
2253 thread_data->dr6 = parent_data->dr6;
2254 thread_data->dr7 = parent_data->dr7;
2258 return status;
2262 /**********************************************************************
2263 * signal_free_thread
2265 void signal_free_thread( TEB *teb )
2267 SIZE_T size;
2268 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
2270 if (thread_data) wine_ldt_free_fs( thread_data->fs );
2271 if (teb->DeallocationStack)
2273 size = 0;
2274 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
2276 size = 0;
2277 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
2281 /**********************************************************************
2282 * signal_init_thread
2284 void signal_init_thread( TEB *teb )
2286 const WORD fpu_cw = 0x27f;
2287 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
2288 LDT_ENTRY fs_entry;
2289 stack_t ss;
2291 #ifdef __APPLE__
2292 int mib[2], val = 1;
2294 mib[0] = CTL_KERN;
2295 mib[1] = KERN_THALTSTACK;
2296 sysctl( mib, 2, NULL, NULL, &val, sizeof(val) );
2297 #endif
2299 ss.ss_sp = (char *)teb + teb_size;
2300 ss.ss_size = signal_stack_size;
2301 ss.ss_flags = 0;
2302 if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
2304 wine_ldt_set_base( &fs_entry, teb );
2305 wine_ldt_set_limit( &fs_entry, teb_size - 1 );
2306 wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
2307 wine_ldt_init_fs( thread_data->fs, &fs_entry );
2308 thread_data->gs = wine_get_gs();
2310 #ifdef __GNUC__
2311 __asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
2312 #else
2313 FIXME("FPU setup not implemented for this platform.\n");
2314 #endif
2317 /**********************************************************************
2318 * signal_init_process
2320 void signal_init_process(void)
2322 struct sigaction sig_act;
2324 sig_act.sa_mask = server_block_set;
2325 sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
2326 #ifdef SA_ONSTACK
2327 sig_act.sa_flags |= SA_ONSTACK;
2328 #endif
2330 sig_act.sa_sigaction = int_handler;
2331 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
2332 sig_act.sa_sigaction = fpe_handler;
2333 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
2334 sig_act.sa_sigaction = abrt_handler;
2335 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
2336 sig_act.sa_sigaction = quit_handler;
2337 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
2338 sig_act.sa_sigaction = usr1_handler;
2339 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
2341 sig_act.sa_sigaction = segv_handler;
2342 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
2343 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
2344 #ifdef SIGBUS
2345 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
2346 #endif
2348 #ifdef SIGTRAP
2349 sig_act.sa_sigaction = trap_handler;
2350 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
2351 #endif
2353 #ifdef __HAVE_VM86
2354 sig_act.sa_sigaction = usr2_handler;
2355 if (sigaction( SIGUSR2, &sig_act, NULL ) == -1) goto error;
2356 #endif
2358 wine_ldt_init_locking( ldt_lock, ldt_unlock );
2359 return;
2361 error:
2362 perror("sigaction");
2363 exit(1);
2367 #ifdef __HAVE_VM86
2368 /**********************************************************************
2369 * __wine_enter_vm86 (NTDLL.@)
2371 * Enter vm86 mode with the specified register context.
2373 void __wine_enter_vm86( CONTEXT *context )
2375 EXCEPTION_RECORD rec;
2376 int res;
2377 struct vm86plus_struct vm86;
2379 memset( &vm86, 0, sizeof(vm86) );
2380 for (;;)
2382 restore_vm86_context( context, &vm86 );
2384 ntdll_get_thread_data()->vm86_ptr = &vm86;
2385 merge_vm86_pending_flags( &rec );
2387 res = vm86_enter( &ntdll_get_thread_data()->vm86_ptr ); /* uses and clears teb->vm86_ptr */
2388 if (res < 0)
2390 errno = -res;
2391 return;
2394 save_vm86_context( context, &vm86 );
2396 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
2397 rec.ExceptionRecord = NULL;
2398 rec.ExceptionAddress = (LPVOID)context->Eip;
2399 rec.NumberParameters = 0;
2401 switch(VM86_TYPE(res))
2403 case VM86_UNKNOWN: /* unhandled GP fault - IO-instruction or similar */
2404 rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
2405 break;
2406 case VM86_TRAP: /* return due to DOS-debugger request */
2407 switch(VM86_ARG(res))
2409 case TRAP_x86_TRCTRAP: /* Single-step exception */
2410 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
2411 break;
2412 case TRAP_x86_BPTFLT: /* Breakpoint exception */
2413 rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
2414 /* fall through */
2415 default:
2416 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
2417 break;
2419 break;
2420 case VM86_INTx: /* int3/int x instruction (ARG = x) */
2421 rec.ExceptionCode = EXCEPTION_VM86_INTx;
2422 rec.NumberParameters = 1;
2423 rec.ExceptionInformation[0] = VM86_ARG(res);
2424 break;
2425 case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */
2426 context->EFlags |= VIF_FLAG;
2427 context->EFlags &= ~VIP_FLAG;
2428 get_vm86_teb_info()->vm86_pending = 0;
2429 rec.ExceptionCode = EXCEPTION_VM86_STI;
2430 break;
2431 case VM86_PICRETURN: /* return due to pending PIC request */
2432 rec.ExceptionCode = EXCEPTION_VM86_PICRETURN;
2433 break;
2434 case VM86_SIGNAL: /* cannot happen because vm86_enter handles this case */
2435 default:
2436 WINE_ERR( "unhandled result from vm86 mode %x\n", res );
2437 continue;
2439 raise_exception( &rec, context, TRUE );
2443 #else /* __HAVE_VM86 */
2444 /**********************************************************************
2445 * __wine_enter_vm86 (NTDLL.@)
2447 void __wine_enter_vm86( CONTEXT *context )
2449 MESSAGE("vm86 mode not supported on this platform\n");
2451 #endif /* __HAVE_VM86 */
2454 /*******************************************************************
2455 * RtlUnwind (NTDLL.@)
2457 void WINAPI __regs_RtlUnwind( EXCEPTION_REGISTRATION_RECORD* pEndFrame, PVOID targetIp,
2458 PEXCEPTION_RECORD pRecord, PVOID retval, CONTEXT *context )
2460 EXCEPTION_RECORD record;
2461 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
2462 DWORD res;
2464 context->Eax = (DWORD)retval;
2466 /* build an exception record, if we do not have one */
2467 if (!pRecord)
2469 record.ExceptionCode = STATUS_UNWIND;
2470 record.ExceptionFlags = 0;
2471 record.ExceptionRecord = NULL;
2472 record.ExceptionAddress = (void *)context->Eip;
2473 record.NumberParameters = 0;
2474 pRecord = &record;
2477 pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
2479 TRACE( "code=%x flags=%x\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );
2481 /* get chain of exception frames */
2482 frame = NtCurrentTeb()->Tib.ExceptionList;
2483 while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != pEndFrame))
2485 /* Check frame address */
2486 if (pEndFrame && (frame > pEndFrame))
2487 raise_status( STATUS_INVALID_UNWIND_TARGET, pRecord );
2489 if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, pRecord );
2491 /* Call handler */
2492 TRACE( "calling handler at %p code=%x flags=%x\n",
2493 frame->Handler, pRecord->ExceptionCode, pRecord->ExceptionFlags );
2494 res = EXC_CallHandler( pRecord, frame, context, &dispatch, frame->Handler, unwind_handler );
2495 TRACE( "handler at %p returned %x\n", frame->Handler, res );
2497 switch(res)
2499 case ExceptionContinueSearch:
2500 break;
2501 case ExceptionCollidedUnwind:
2502 frame = dispatch;
2503 break;
2504 default:
2505 raise_status( STATUS_INVALID_DISPOSITION, pRecord );
2506 break;
2508 frame = __wine_pop_frame( frame );
2511 DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
2514 /*******************************************************************
2515 * NtRaiseException (NTDLL.@)
2517 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
2519 NTSTATUS status = raise_exception( rec, context, first_chance );
2520 if (status == STATUS_SUCCESS)
2522 set_debug_registers( context );
2523 set_cpu_context( context );
2525 return status;
2529 /***********************************************************************
2530 * RtlRaiseException (NTDLL.@)
2532 void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
2534 NTSTATUS status;
2536 rec->ExceptionAddress = (void *)context->Eip;
2537 status = raise_exception( rec, context, TRUE );
2538 if (status != STATUS_SUCCESS) raise_status( status, rec );
2540 DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
2543 /*************************************************************************
2544 * RtlCaptureStackBackTrace (NTDLL.@)
2546 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
2548 CONTEXT context;
2549 ULONG i;
2550 ULONG *frame;
2552 RtlCaptureContext( &context );
2553 if (hash) *hash = 0;
2554 frame = (ULONG *)context.Ebp;
2556 while (skip--)
2558 if (!is_valid_frame( frame )) return 0;
2559 frame = (ULONG *)*frame;
2562 for (i = 0; i < count; i++)
2564 if (!is_valid_frame( frame )) break;
2565 buffer[i] = (void *)frame[1];
2566 if (hash) *hash += frame[1];
2567 frame = (ULONG *)*frame;
2569 return i;
2573 extern void DECLSPEC_NORETURN call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg );
2574 __ASM_GLOBAL_FUNC( call_thread_entry_point,
2575 "pushl %ebp\n\t"
2576 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2577 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2578 "movl %esp,%ebp\n\t"
2579 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2580 "pushl %ebx\n\t"
2581 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
2582 "pushl %esi\n\t"
2583 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
2584 "pushl %edi\n\t"
2585 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
2586 "pushl %ebp\n\t"
2587 "pushl 12(%ebp)\n\t"
2588 "pushl 8(%ebp)\n\t"
2589 "call " __ASM_NAME("call_thread_func") );
2591 extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), void *frame );
2592 __ASM_GLOBAL_FUNC( call_thread_exit_func,
2593 "movl 4(%esp),%eax\n\t"
2594 "movl 8(%esp),%ecx\n\t"
2595 "movl 12(%esp),%ebp\n\t"
2596 __ASM_CFI(".cfi_def_cfa %ebp,4\n\t")
2597 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2598 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
2599 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
2600 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
2601 "leal -20(%ebp),%esp\n\t"
2602 "pushl %eax\n\t"
2603 "call *%ecx" );
2605 /* wrapper for apps that don't declare the thread function correctly */
2606 extern void DECLSPEC_NORETURN call_thread_func_wrapper( LPTHREAD_START_ROUTINE entry, void *arg );
2607 __ASM_GLOBAL_FUNC(call_thread_func_wrapper,
2608 "pushl %ebp\n\t"
2609 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2610 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2611 "movl %esp,%ebp\n\t"
2612 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2613 "subl $4,%esp\n\t"
2614 "pushl 12(%ebp)\n\t"
2615 "call *8(%ebp)\n\t"
2616 "leal -4(%ebp),%esp\n\t"
2617 "pushl %eax\n\t"
2618 "call " __ASM_NAME("exit_thread") "\n\t"
2619 "int $3" )
2621 /***********************************************************************
2622 * call_thread_func
2624 void call_thread_func( LPTHREAD_START_ROUTINE entry, void *arg, void *frame )
2626 ntdll_get_thread_data()->exit_frame = frame;
2627 __TRY
2629 call_thread_func_wrapper( entry, arg );
2631 __EXCEPT(unhandled_exception_filter)
2633 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
2635 __ENDTRY
2636 abort(); /* should not be reached */
2639 /***********************************************************************
2640 * RtlExitUserThread (NTDLL.@)
2642 void WINAPI RtlExitUserThread( ULONG status )
2644 if (!ntdll_get_thread_data()->exit_frame) exit_thread( status );
2645 call_thread_exit_func( status, exit_thread, ntdll_get_thread_data()->exit_frame );
2648 /***********************************************************************
2649 * abort_thread
2651 void abort_thread( int status )
2653 if (!ntdll_get_thread_data()->exit_frame) terminate_thread( status );
2654 call_thread_exit_func( status, terminate_thread, ntdll_get_thread_data()->exit_frame );
2657 /**********************************************************************
2658 * DbgBreakPoint (NTDLL.@)
2660 __ASM_STDCALL_FUNC( DbgBreakPoint, 0, "int $3; ret")
2662 /**********************************************************************
2663 * DbgUserBreakPoint (NTDLL.@)
2665 __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "int $3; ret")
2667 /**********************************************************************
2668 * NtCurrentTeb (NTDLL.@)
2670 __ASM_STDCALL_FUNC( NtCurrentTeb, 0, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" )
2673 /**************************************************************************
2674 * _chkstk (NTDLL.@)
2676 __ASM_STDCALL_FUNC( _chkstk, 0,
2677 "negl %eax\n\t"
2678 "addl %esp,%eax\n\t"
2679 "xchgl %esp,%eax\n\t"
2680 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
2681 "movl %eax,0(%esp)\n\t"
2682 "ret" )
2684 /**************************************************************************
2685 * _alloca_probe (NTDLL.@)
2687 __ASM_STDCALL_FUNC( _alloca_probe, 0,
2688 "negl %eax\n\t"
2689 "addl %esp,%eax\n\t"
2690 "xchgl %esp,%eax\n\t"
2691 "movl 0(%eax),%eax\n\t" /* copy return address from old location */
2692 "movl %eax,0(%esp)\n\t"
2693 "ret" )
2696 /**********************************************************************
2697 * EXC_CallHandler (internal)
2699 * Some exception handlers depend on EBP to have a fixed position relative to
2700 * the exception frame.
2701 * Shrinker depends on (*1) doing what it does,
2702 * (*2) being the exact instruction it is and (*3) beginning with 0x64
2703 * (i.e. the %fs prefix to the movl instruction). It also depends on the
2704 * function calling the handler having only 5 parameters (*4).
2706 __ASM_GLOBAL_FUNC( EXC_CallHandler,
2707 "pushl %ebp\n\t"
2708 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2709 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2710 "movl %esp,%ebp\n\t"
2711 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2712 "pushl %ebx\n\t"
2713 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
2714 "movl 28(%ebp), %edx\n\t" /* ugly hack to pass the 6th param needed because of Shrinker */
2715 "pushl 24(%ebp)\n\t"
2716 "pushl 20(%ebp)\n\t"
2717 "pushl 16(%ebp)\n\t"
2718 "pushl 12(%ebp)\n\t"
2719 "pushl 8(%ebp)\n\t"
2720 "call " __ASM_NAME("call_exception_handler") "\n\t"
2721 "popl %ebx\n\t"
2722 __ASM_CFI(".cfi_same_value %ebx\n\t")
2723 "leave\n"
2724 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
2725 __ASM_CFI(".cfi_same_value %ebp\n\t")
2726 "ret" )
2727 __ASM_GLOBAL_FUNC(call_exception_handler,
2728 "pushl %ebp\n\t"
2729 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2730 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2731 "movl %esp,%ebp\n\t"
2732 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2733 "subl $12,%esp\n\t"
2734 "pushl 12(%ebp)\n\t" /* make any exceptions in this... */
2735 "pushl %edx\n\t" /* handler be handled by... */
2736 ".byte 0x64\n\t"
2737 "pushl (0)\n\t" /* nested_handler (passed in edx). */
2738 ".byte 0x64\n\t"
2739 "movl %esp,(0)\n\t" /* push the new exception frame onto the exception stack. */
2740 "pushl 20(%ebp)\n\t"
2741 "pushl 16(%ebp)\n\t"
2742 "pushl 12(%ebp)\n\t"
2743 "pushl 8(%ebp)\n\t"
2744 "movl 24(%ebp), %ecx\n\t" /* (*1) */
2745 "call *%ecx\n\t" /* call handler. (*2) */
2746 ".byte 0x64\n\t"
2747 "movl (0), %esp\n\t" /* restore previous... (*3) */
2748 ".byte 0x64\n\t"
2749 "popl (0)\n\t" /* exception frame. */
2750 "movl %ebp, %esp\n\t" /* restore saved stack, in case it was corrupted */
2751 "popl %ebp\n\t"
2752 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
2753 __ASM_CFI(".cfi_same_value %ebp\n\t")
2754 "ret $20" ) /* (*4) */
2756 #endif /* __i386__ */