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
28 #include "wine/port.h"
35 #include <sys/types.h>
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>
45 # ifdef HAVE_SYS_SYSCALL_H
46 # include <sys/syscall.h>
49 #ifdef HAVE_SYS_SIGNAL_H
50 # include <sys/signal.h>
52 #ifdef HAVE_SYS_UCONTEXT_H
53 # include <sys/ucontext.h>
57 #define WIN32_NO_STATUS
60 #include "wine/exception.h"
61 #include "unix_private.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
66 #undef ERR /* Solaris needs to define this */
68 /* not defined for x86, so copy the x86_64 definition */
69 typedef struct DECLSPEC_ALIGN(16) _M128A
90 M128A FloatRegisters
[8];
91 M128A XmmRegisters
[16];
95 /***********************************************************************
96 * signal context platform-specific definitions
101 #ifndef HAVE_SYS_UCONTEXT_H
105 REG_GS
, REG_FS
, REG_ES
, REG_DS
, REG_EDI
, REG_ESI
, REG_EBP
, REG_ESP
,
106 REG_EBX
, REG_EDX
, REG_ECX
, REG_EAX
, REG_TRAPNO
, REG_ERR
, REG_EIP
,
107 REG_CS
, REG_EFL
, REG_UESP
, REG_SS
, NGREG
111 typedef greg_t gregset_t
[NGREG
];
115 unsigned short significand
[4];
116 unsigned short exponent
;
126 unsigned long dataoff
;
127 unsigned long datasel
;
128 struct _libc_fpreg _st
[8];
129 unsigned long status
;
132 typedef struct _libc_fpstate
* fpregset_t
;
138 unsigned long oldmask
;
142 typedef struct ucontext
144 unsigned long uc_flags
;
145 struct ucontext
*uc_link
;
147 mcontext_t uc_mcontext
;
150 #endif /* HAVE_SYS_UCONTEXT_H */
152 #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX])
153 #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX])
154 #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX])
155 #define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX])
156 #define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI])
157 #define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI])
158 #define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP])
159 #define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP])
161 #define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS])
162 #define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS])
163 #define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES])
164 #define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS])
165 #define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS])
166 #define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS])
168 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
169 #define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
170 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
171 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
173 #define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs))
174 #define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpregs->status >> 16) ? (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1) : NULL)
177 /* custom signal restorer since we may have unmapped the one in vdso, and bionic doesn't check for that */
178 void rt_sigreturn(void);
179 __ASM_GLOBAL_FUNC( rt_sigreturn
,
180 "movl $173,%eax\n\t" /* NR_rt_sigreturn */
186 unsigned int entry_number
;
189 unsigned int seg_32bit
: 1;
190 unsigned int contents
: 2;
191 unsigned int read_exec_only
: 1;
192 unsigned int limit_in_pages
: 1;
193 unsigned int seg_not_present
: 1;
194 unsigned int usable
: 1;
195 unsigned int garbage
: 25;
198 static inline int modify_ldt( int func
, struct modify_ldt_s
*ptr
, unsigned long count
)
200 return syscall( 123 /* SYS_modify_ldt */, func
, ptr
, count
);
203 static inline int set_thread_area( struct modify_ldt_s
*ptr
)
205 return syscall( 243 /* SYS_set_thread_area */, ptr
);
208 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
210 #include <machine/trap.h>
211 #include <machine/segments.h>
212 #include <machine/sysarch.h>
214 #define EAX_sig(context) ((context)->uc_mcontext.mc_eax)
215 #define EBX_sig(context) ((context)->uc_mcontext.mc_ebx)
216 #define ECX_sig(context) ((context)->uc_mcontext.mc_ecx)
217 #define EDX_sig(context) ((context)->uc_mcontext.mc_edx)
218 #define ESI_sig(context) ((context)->uc_mcontext.mc_esi)
219 #define EDI_sig(context) ((context)->uc_mcontext.mc_edi)
220 #define EBP_sig(context) ((context)->uc_mcontext.mc_ebp)
222 #define CS_sig(context) ((context)->uc_mcontext.mc_cs)
223 #define DS_sig(context) ((context)->uc_mcontext.mc_ds)
224 #define ES_sig(context) ((context)->uc_mcontext.mc_es)
225 #define FS_sig(context) ((context)->uc_mcontext.mc_fs)
226 #define GS_sig(context) ((context)->uc_mcontext.mc_gs)
227 #define SS_sig(context) ((context)->uc_mcontext.mc_ss)
229 #define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
230 #define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
231 #define EFL_sig(context) ((context)->uc_mcontext.mc_eflags)
233 #define EIP_sig(context) ((context)->uc_mcontext.mc_eip)
234 #define ESP_sig(context) ((context)->uc_mcontext.mc_esp)
236 #define FPU_sig(context) NULL /* FIXME */
237 #define FPUX_sig(context) NULL /* FIXME */
239 #elif defined (__OpenBSD__)
241 #include <machine/segments.h>
242 #include <machine/sysarch.h>
244 #define EAX_sig(context) ((context)->sc_eax)
245 #define EBX_sig(context) ((context)->sc_ebx)
246 #define ECX_sig(context) ((context)->sc_ecx)
247 #define EDX_sig(context) ((context)->sc_edx)
248 #define ESI_sig(context) ((context)->sc_esi)
249 #define EDI_sig(context) ((context)->sc_edi)
250 #define EBP_sig(context) ((context)->sc_ebp)
252 #define CS_sig(context) ((context)->sc_cs)
253 #define DS_sig(context) ((context)->sc_ds)
254 #define ES_sig(context) ((context)->sc_es)
255 #define FS_sig(context) ((context)->sc_fs)
256 #define GS_sig(context) ((context)->sc_gs)
257 #define SS_sig(context) ((context)->sc_ss)
259 #define TRAP_sig(context) ((context)->sc_trapno)
260 #define ERROR_sig(context) ((context)->sc_err)
261 #define EFL_sig(context) ((context)->sc_eflags)
263 #define EIP_sig(context) ((context)->sc_eip)
264 #define ESP_sig(context) ((context)->sc_esp)
266 #define FPU_sig(context) NULL /* FIXME */
267 #define FPUX_sig(context) NULL /* FIXME */
269 #define T_MCHK T_MACHK
270 #define T_XMMFLT T_XFTRAP
272 #elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
274 #if defined(_SCO_DS) || defined(__sun)
275 #include <sys/regset.h>
282 #define EAX_sig(context) ((context)->uc_mcontext.gregs[EAX])
283 #define EBX_sig(context) ((context)->uc_mcontext.gregs[EBX])
284 #define ECX_sig(context) ((context)->uc_mcontext.gregs[ECX])
285 #define EDX_sig(context) ((context)->uc_mcontext.gregs[EDX])
286 #define ESI_sig(context) ((context)->uc_mcontext.gregs[ESI])
287 #define EDI_sig(context) ((context)->uc_mcontext.gregs[EDI])
288 #define EBP_sig(context) ((context)->uc_mcontext.gregs[EBP])
290 #define CS_sig(context) ((context)->uc_mcontext.gregs[CS])
291 #define DS_sig(context) ((context)->uc_mcontext.gregs[DS])
292 #define ES_sig(context) ((context)->uc_mcontext.gregs[ES])
293 #define SS_sig(context) ((context)->uc_mcontext.gregs[SS])
295 #define FS_sig(context) ((context)->uc_mcontext.gregs[FS])
296 #define GS_sig(context) ((context)->uc_mcontext.gregs[GS])
298 #define EFL_sig(context) ((context)->uc_mcontext.gregs[EFL])
300 #define EIP_sig(context) ((context)->uc_mcontext.gregs[EIP])
302 #define ESP_sig(context) ((context)->uc_mcontext.gregs[UESP])
304 #define ESP_sig(context) ((context)->uc_mcontext.gregs[R_ESP])
306 #define ESP_sig(context) ((context)->uc_mcontext.gregs[ESP])
308 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[ERR])
309 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[TRAPNO])
311 #define FPU_sig(context) NULL /* FIXME */
312 #define FPUX_sig(context) NULL /* FIXME */
314 #elif defined (__APPLE__)
316 #include <i386/user_ldt.h>
318 /* work around silly renaming of struct members in OS X 10.5 */
319 #if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32)
320 #define EAX_sig(context) ((context)->uc_mcontext->__ss.__eax)
321 #define EBX_sig(context) ((context)->uc_mcontext->__ss.__ebx)
322 #define ECX_sig(context) ((context)->uc_mcontext->__ss.__ecx)
323 #define EDX_sig(context) ((context)->uc_mcontext->__ss.__edx)
324 #define ESI_sig(context) ((context)->uc_mcontext->__ss.__esi)
325 #define EDI_sig(context) ((context)->uc_mcontext->__ss.__edi)
326 #define EBP_sig(context) ((context)->uc_mcontext->__ss.__ebp)
327 #define CS_sig(context) ((context)->uc_mcontext->__ss.__cs)
328 #define DS_sig(context) ((context)->uc_mcontext->__ss.__ds)
329 #define ES_sig(context) ((context)->uc_mcontext->__ss.__es)
330 #define FS_sig(context) ((context)->uc_mcontext->__ss.__fs)
331 #define GS_sig(context) ((context)->uc_mcontext->__ss.__gs)
332 #define SS_sig(context) ((context)->uc_mcontext->__ss.__ss)
333 #define EFL_sig(context) ((context)->uc_mcontext->__ss.__eflags)
334 #define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__eip))
335 #define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__esp))
336 #define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno)
337 #define ERROR_sig(context) ((context)->uc_mcontext->__es.__err)
338 #define FPU_sig(context) NULL
339 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw)
341 #define EAX_sig(context) ((context)->uc_mcontext->ss.eax)
342 #define EBX_sig(context) ((context)->uc_mcontext->ss.ebx)
343 #define ECX_sig(context) ((context)->uc_mcontext->ss.ecx)
344 #define EDX_sig(context) ((context)->uc_mcontext->ss.edx)
345 #define ESI_sig(context) ((context)->uc_mcontext->ss.esi)
346 #define EDI_sig(context) ((context)->uc_mcontext->ss.edi)
347 #define EBP_sig(context) ((context)->uc_mcontext->ss.ebp)
348 #define CS_sig(context) ((context)->uc_mcontext->ss.cs)
349 #define DS_sig(context) ((context)->uc_mcontext->ss.ds)
350 #define ES_sig(context) ((context)->uc_mcontext->ss.es)
351 #define FS_sig(context) ((context)->uc_mcontext->ss.fs)
352 #define GS_sig(context) ((context)->uc_mcontext->ss.gs)
353 #define SS_sig(context) ((context)->uc_mcontext->ss.ss)
354 #define EFL_sig(context) ((context)->uc_mcontext->ss.eflags)
355 #define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
356 #define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.esp))
357 #define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
358 #define ERROR_sig(context) ((context)->uc_mcontext->es.err)
359 #define FPU_sig(context) NULL
360 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->fs.fpu_fcw)
363 #elif defined(__NetBSD__)
365 #include <machine/segments.h>
366 #include <machine/sysarch.h>
368 #define EAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EAX])
369 #define EBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBX])
370 #define ECX_sig(context) ((context)->uc_mcontext.__gregs[_REG_ECX])
371 #define EDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDX])
372 #define ESI_sig(context) ((context)->uc_mcontext.__gregs[_REG_ESI])
373 #define EDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDI])
374 #define EBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBP])
375 #define ESP_sig(context) _UC_MACHINE_SP(context)
377 #define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS])
378 #define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS])
379 #define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES])
380 #define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS])
381 #define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS])
382 #define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS])
384 #define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_EFL])
385 #define EIP_sig(context) _UC_MACHINE_PC(context)
386 #define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
387 #define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
389 #define FPU_sig(context) NULL
390 #define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&((context)->uc_mcontext.__fpregs))
393 #define T_XMMFLT T_XMM
395 #elif defined(__GNU__)
397 #include <mach/i386/mach_i386.h>
398 #include <mach/mach_traps.h>
400 #define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX])
401 #define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX])
402 #define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX])
403 #define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX])
404 #define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI])
405 #define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI])
406 #define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP])
407 #define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP])
409 #define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS])
410 #define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS])
411 #define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES])
412 #define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS])
413 #define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS])
414 #define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS])
416 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
417 #define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
418 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
419 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
421 #define FPU_sig(context) ((FLOATING_SAVE_AREA *)&(context)->uc_mcontext.fpregs.fp_reg_set.fpchip_state)
422 #define FPUX_sig(context) NULL
425 #error You must define the signal context functions for your platform
428 static ULONG first_ldt_entry
= 32;
432 #if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
433 TRAP_x86_DIVIDE
= T_DIVIDE
, /* Division by zero exception */
434 TRAP_x86_TRCTRAP
= T_TRCTRAP
, /* Single-step exception */
435 TRAP_x86_NMI
= T_NMI
, /* NMI interrupt */
436 TRAP_x86_BPTFLT
= T_BPTFLT
, /* Breakpoint exception */
437 TRAP_x86_OFLOW
= T_OFLOW
, /* Overflow exception */
438 TRAP_x86_BOUND
= T_BOUND
, /* Bound range exception */
439 TRAP_x86_PRIVINFLT
= T_PRIVINFLT
, /* Invalid opcode exception */
440 TRAP_x86_DNA
= T_DNA
, /* Device not available exception */
441 TRAP_x86_DOUBLEFLT
= T_DOUBLEFLT
, /* Double fault exception */
442 TRAP_x86_FPOPFLT
= T_FPOPFLT
, /* Coprocessor segment overrun */
443 TRAP_x86_TSSFLT
= T_TSSFLT
, /* Invalid TSS exception */
444 TRAP_x86_SEGNPFLT
= T_SEGNPFLT
, /* Segment not present exception */
445 TRAP_x86_STKFLT
= T_STKFLT
, /* Stack fault */
446 TRAP_x86_PROTFLT
= T_PROTFLT
, /* General protection fault */
447 TRAP_x86_PAGEFLT
= T_PAGEFLT
, /* Page fault */
448 TRAP_x86_ARITHTRAP
= T_ARITHTRAP
, /* Floating point exception */
449 TRAP_x86_ALIGNFLT
= T_ALIGNFLT
, /* Alignment check exception */
450 TRAP_x86_MCHK
= T_MCHK
, /* Machine check exception */
451 TRAP_x86_CACHEFLT
= T_XMMFLT
/* Cache flush exception */
453 TRAP_x86_DIVIDE
= 0, /* Division by zero exception */
454 TRAP_x86_TRCTRAP
= 1, /* Single-step exception */
455 TRAP_x86_NMI
= 2, /* NMI interrupt */
456 TRAP_x86_BPTFLT
= 3, /* Breakpoint exception */
457 TRAP_x86_OFLOW
= 4, /* Overflow exception */
458 TRAP_x86_BOUND
= 5, /* Bound range exception */
459 TRAP_x86_PRIVINFLT
= 6, /* Invalid opcode exception */
460 TRAP_x86_DNA
= 7, /* Device not available exception */
461 TRAP_x86_DOUBLEFLT
= 8, /* Double fault exception */
462 TRAP_x86_FPOPFLT
= 9, /* Coprocessor segment overrun */
463 TRAP_x86_TSSFLT
= 10, /* Invalid TSS exception */
464 TRAP_x86_SEGNPFLT
= 11, /* Segment not present exception */
465 TRAP_x86_STKFLT
= 12, /* Stack fault */
466 TRAP_x86_PROTFLT
= 13, /* General protection fault */
467 TRAP_x86_PAGEFLT
= 14, /* Page fault */
468 TRAP_x86_ARITHTRAP
= 16, /* Floating point exception */
469 TRAP_x86_ALIGNFLT
= 17, /* Alignment check exception */
470 TRAP_x86_MCHK
= 18, /* Machine check exception */
471 TRAP_x86_CACHEFLT
= 19 /* SIMD exception (via SIGFPE) if CPU is SSE capable
472 otherwise Cache flush exception (via SIGSEV) */
476 struct x86_thread_data
478 DWORD fs
; /* 1d4 TEB selector */
479 DWORD gs
; /* 1d8 libc selector; update winebuild if you move this! */
480 DWORD dr0
; /* 1dc debug registers */
486 void *exit_frame
; /* 1f4 exit frame pointer */
487 /* the ntdll_thread_data structure follows here */
490 C_ASSERT( offsetof( TEB
, SystemReserved2
) + offsetof( struct x86_thread_data
, gs
) == 0x1d8 );
491 C_ASSERT( offsetof( TEB
, SystemReserved2
) + offsetof( struct x86_thread_data
, exit_frame
) == 0x1f4 );
493 static inline struct x86_thread_data
*x86_thread_data(void)
495 return (struct x86_thread_data
*)NtCurrentTeb()->SystemReserved2
;
498 static inline WORD
get_cs(void) { WORD res
; __asm__( "movw %%cs,%0" : "=r" (res
) ); return res
; }
499 static inline WORD
get_ds(void) { WORD res
; __asm__( "movw %%ds,%0" : "=r" (res
) ); return res
; }
500 static inline WORD
get_fs(void) { WORD res
; __asm__( "movw %%fs,%0" : "=r" (res
) ); return res
; }
501 static inline WORD
get_gs(void) { WORD res
; __asm__( "movw %%gs,%0" : "=r" (res
) ); return res
; }
502 static inline void set_fs( WORD val
) { __asm__( "mov %0,%%fs" :: "r" (val
)); }
503 static inline void set_gs( WORD val
) { __asm__( "mov %0,%%gs" :: "r" (val
)); }
506 /***********************************************************************
509 NTSTATUS CDECL
unwind_builtin_dll( ULONG type
, struct _DISPATCHER_CONTEXT
*dispatch
, CONTEXT
*context
)
511 return STATUS_UNSUCCESSFUL
;
515 /***********************************************************************
518 static inline int is_gdt_sel( WORD sel
)
524 /***********************************************************************
527 static inline int ldt_is_system( WORD sel
)
529 return is_gdt_sel( sel
) || ((sel
>> 3) < first_ldt_entry
);
533 /***********************************************************************
536 * Get the current teb based on the stack pointer.
538 static inline TEB
*get_current_teb(void)
541 __asm__("movl %%esp,%0" : "=g" (esp
) );
542 return (TEB
*)(esp
& ~signal_stack_mask
);
548 /* We have to workaround two Solaris breakages:
549 * - Solaris doesn't restore %ds and %es before calling the signal handler so exceptions in 16-bit
551 * - Solaris inserts a libc trampoline to call our handler, but the trampoline expects that registers
552 * are setup correctly. So we need to insert our own trampoline below the libc trampoline to set %gs.
555 extern int sigaction_syscall( int sig
, const struct sigaction
*new, struct sigaction
*old
);
556 __ASM_GLOBAL_FUNC( sigaction_syscall
,
557 "movl $0x62,%eax\n\t"
561 /* assume the same libc handler is used for all signals */
562 static void (*libc_sigacthandler
)( int signal
, siginfo_t
*siginfo
, void *context
);
564 static void wine_sigacthandler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
566 struct x86_thread_data
*thread_data
;
568 __asm__
__volatile__("mov %ss,%ax; mov %ax,%ds; mov %ax,%es");
570 thread_data
= (struct x86_thread_data
*)get_current_teb()->SystemReserved2
;
571 set_fs( thread_data
->fs
);
572 set_gs( thread_data
->gs
);
574 libc_sigacthandler( signal
, siginfo
, sigcontext
);
577 static int solaris_sigaction( int sig
, const struct sigaction
*new, struct sigaction
*old
)
579 struct sigaction real_act
;
581 if (sigaction( sig
, new, old
) == -1) return -1;
583 /* retrieve the real handler and flags with a direct syscall */
584 sigaction_syscall( sig
, NULL
, &real_act
);
585 libc_sigacthandler
= real_act
.sa_sigaction
;
586 real_act
.sa_sigaction
= wine_sigacthandler
;
587 sigaction_syscall( sig
, &real_act
, NULL
);
590 #define sigaction(sig,new,old) solaris_sigaction(sig,new,old)
594 extern void clear_alignment_flag(void);
595 __ASM_GLOBAL_FUNC( clear_alignment_flag
,
597 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
598 "andl $~0x40000,(%esp)\n\t"
600 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
604 /***********************************************************************
607 * Handler initialization when the full context is not needed.
608 * Return the stack pointer to use for pushing the exception data.
610 static inline void *init_handler( const ucontext_t
*sigcontext
)
612 TEB
*teb
= get_current_teb();
614 clear_alignment_flag();
616 #ifndef __sun /* see above for Solaris handling */
618 struct x86_thread_data
*thread_data
= (struct x86_thread_data
*)teb
->SystemReserved2
;
619 set_fs( thread_data
->fs
);
620 set_gs( thread_data
->gs
);
624 if (!ldt_is_system(CS_sig(sigcontext
)) || !ldt_is_system(SS_sig(sigcontext
))) /* 16-bit mode */
627 * Win16 or DOS protected mode. Note that during switch
628 * from 16-bit mode to linear mode, CS may be set to system
629 * segment before FS is restored. Fortunately, in this case
630 * SS is still non-system segment. This is why both CS and SS
633 return teb
->WOW32Reserved
;
635 return (void *)(ESP_sig(sigcontext
) & ~3);
639 /***********************************************************************
642 * Save the thread FPU context.
644 static inline void save_fpu( CONTEXT
*context
)
658 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
659 __asm__
__volatile__( "fnsave %0; fwait" : "=m" (context
->FloatSave
) );
661 /* Reset unmasked exceptions status to avoid firing an exception. */
662 memcpy(&float_status
, &context
->FloatSave
, sizeof(float_status
));
663 float_status
.StatusWord
&= float_status
.ControlWord
| 0xffffff80;
665 __asm__
__volatile__( "fldenv %0" : : "m" (float_status
) );
669 /***********************************************************************
672 * Save the thread FPU extended context.
674 static inline void save_fpux( CONTEXT
*context
)
676 /* we have to enforce alignment by hand */
677 char buffer
[sizeof(XMM_SAVE_AREA32
) + 16];
678 XMM_SAVE_AREA32
*state
= (XMM_SAVE_AREA32
*)(((ULONG_PTR
)buffer
+ 15) & ~15);
680 context
->ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
681 __asm__
__volatile__( "fxsave %0" : "=m" (*state
) );
682 memcpy( context
->ExtendedRegisters
, state
, sizeof(*state
) );
686 /***********************************************************************
689 * Restore the FPU context to a sigcontext.
691 static inline void restore_fpu( const CONTEXT
*context
)
693 FLOATING_SAVE_AREA float_status
= context
->FloatSave
;
694 /* reset the current interrupt status */
695 float_status
.StatusWord
&= float_status
.ControlWord
| 0xffffff80;
696 __asm__
__volatile__( "frstor %0; fwait" : : "m" (float_status
) );
700 /***********************************************************************
703 * Restore the FPU extended context to a sigcontext.
705 static inline void restore_fpux( const CONTEXT
*context
)
707 /* we have to enforce alignment by hand */
708 char buffer
[sizeof(XMM_SAVE_AREA32
) + 16];
709 XMM_SAVE_AREA32
*state
= (XMM_SAVE_AREA32
*)(((ULONG_PTR
)buffer
+ 15) & ~15);
711 memcpy( state
, context
->ExtendedRegisters
, sizeof(*state
) );
712 /* reset the current interrupt status */
713 state
->StatusWord
&= state
->ControlWord
| 0xff80;
714 __asm__
__volatile__( "fxrstor %0" : : "m" (*state
) );
718 /***********************************************************************
721 * Build a standard FPU context from an extended one.
723 static void fpux_to_fpu( FLOATING_SAVE_AREA
*fpu
, const XMM_SAVE_AREA32
*fpux
)
725 unsigned int i
, tag
, stack_top
;
727 fpu
->ControlWord
= fpux
->ControlWord
| 0xffff0000;
728 fpu
->StatusWord
= fpux
->StatusWord
| 0xffff0000;
729 fpu
->ErrorOffset
= fpux
->ErrorOffset
;
730 fpu
->ErrorSelector
= fpux
->ErrorSelector
| (fpux
->ErrorOpcode
<< 16);
731 fpu
->DataOffset
= fpux
->DataOffset
;
732 fpu
->DataSelector
= fpux
->DataSelector
;
733 fpu
->Cr0NpxState
= fpux
->StatusWord
| 0xffff0000;
735 stack_top
= (fpux
->StatusWord
>> 11) & 7;
736 fpu
->TagWord
= 0xffff0000;
737 for (i
= 0; i
< 8; i
++)
739 memcpy( &fpu
->RegisterArea
[10 * i
], &fpux
->FloatRegisters
[i
], 10 );
740 if (!(fpux
->TagWord
& (1 << i
))) tag
= 3; /* empty */
743 const M128A
*reg
= &fpux
->FloatRegisters
[(i
- stack_top
) & 7];
744 if ((reg
->High
& 0x7fff) == 0x7fff) /* exponent all ones */
746 tag
= 2; /* special */
748 else if (!(reg
->High
& 0x7fff)) /* exponent all zeroes */
750 if (reg
->Low
) tag
= 2; /* special */
751 else tag
= 1; /* zero */
755 if (reg
->Low
>> 63) tag
= 0; /* valid */
756 else tag
= 2; /* special */
759 fpu
->TagWord
|= tag
<< (2 * i
);
764 /***********************************************************************
767 * Build a context structure from the signal info.
769 static inline void save_context( CONTEXT
*context
, const ucontext_t
*sigcontext
)
771 FLOATING_SAVE_AREA
*fpu
= FPU_sig(sigcontext
);
772 XMM_SAVE_AREA32
*fpux
= FPUX_sig(sigcontext
);
774 memset(context
, 0, sizeof(*context
));
775 context
->ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
776 context
->Eax
= EAX_sig(sigcontext
);
777 context
->Ebx
= EBX_sig(sigcontext
);
778 context
->Ecx
= ECX_sig(sigcontext
);
779 context
->Edx
= EDX_sig(sigcontext
);
780 context
->Esi
= ESI_sig(sigcontext
);
781 context
->Edi
= EDI_sig(sigcontext
);
782 context
->Ebp
= EBP_sig(sigcontext
);
783 context
->EFlags
= EFL_sig(sigcontext
);
784 context
->Eip
= EIP_sig(sigcontext
);
785 context
->Esp
= ESP_sig(sigcontext
);
786 context
->SegCs
= LOWORD(CS_sig(sigcontext
));
787 context
->SegDs
= LOWORD(DS_sig(sigcontext
));
788 context
->SegEs
= LOWORD(ES_sig(sigcontext
));
789 context
->SegFs
= LOWORD(FS_sig(sigcontext
));
790 context
->SegGs
= LOWORD(GS_sig(sigcontext
));
791 context
->SegSs
= LOWORD(SS_sig(sigcontext
));
792 context
->Dr0
= x86_thread_data()->dr0
;
793 context
->Dr1
= x86_thread_data()->dr1
;
794 context
->Dr2
= x86_thread_data()->dr2
;
795 context
->Dr3
= x86_thread_data()->dr3
;
796 context
->Dr6
= x86_thread_data()->dr6
;
797 context
->Dr7
= x86_thread_data()->dr7
;
801 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
802 context
->FloatSave
= *fpu
;
806 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
| CONTEXT_EXTENDED_REGISTERS
;
807 memcpy( context
->ExtendedRegisters
, fpux
, sizeof(*fpux
) );
808 if (!fpu
) fpux_to_fpu( &context
->FloatSave
, fpux
);
810 if (!fpu
&& !fpux
) save_fpu( context
);
814 /***********************************************************************
817 * Restore the signal info from the context.
819 static inline void restore_context( const CONTEXT
*context
, ucontext_t
*sigcontext
)
821 FLOATING_SAVE_AREA
*fpu
= FPU_sig(sigcontext
);
822 XMM_SAVE_AREA32
*fpux
= FPUX_sig(sigcontext
);
824 x86_thread_data()->dr0
= context
->Dr0
;
825 x86_thread_data()->dr1
= context
->Dr1
;
826 x86_thread_data()->dr2
= context
->Dr2
;
827 x86_thread_data()->dr3
= context
->Dr3
;
828 x86_thread_data()->dr6
= context
->Dr6
;
829 x86_thread_data()->dr7
= context
->Dr7
;
830 EAX_sig(sigcontext
) = context
->Eax
;
831 EBX_sig(sigcontext
) = context
->Ebx
;
832 ECX_sig(sigcontext
) = context
->Ecx
;
833 EDX_sig(sigcontext
) = context
->Edx
;
834 ESI_sig(sigcontext
) = context
->Esi
;
835 EDI_sig(sigcontext
) = context
->Edi
;
836 EBP_sig(sigcontext
) = context
->Ebp
;
837 EFL_sig(sigcontext
) = context
->EFlags
;
838 EIP_sig(sigcontext
) = context
->Eip
;
839 ESP_sig(sigcontext
) = context
->Esp
;
840 CS_sig(sigcontext
) = context
->SegCs
;
841 DS_sig(sigcontext
) = context
->SegDs
;
842 ES_sig(sigcontext
) = context
->SegEs
;
843 FS_sig(sigcontext
) = context
->SegFs
;
844 GS_sig(sigcontext
) = context
->SegGs
;
845 SS_sig(sigcontext
) = context
->SegSs
;
847 if (fpu
) *fpu
= context
->FloatSave
;
848 if (fpux
) memcpy( fpux
, context
->ExtendedRegisters
, sizeof(*fpux
) );
849 if (!fpu
&& !fpux
) restore_fpu( context
);
853 /***********************************************************************
854 * set_full_cpu_context
856 * Set the new CPU context.
858 extern void set_full_cpu_context( const CONTEXT
*context
);
859 __ASM_GLOBAL_FUNC( set_full_cpu_context
,
860 "movl 4(%esp),%ecx\n\t"
861 "movw 0x8c(%ecx),%gs\n\t" /* SegGs */
862 "movw 0x90(%ecx),%fs\n\t" /* SegFs */
863 "movw 0x94(%ecx),%es\n\t" /* SegEs */
864 "movl 0x9c(%ecx),%edi\n\t" /* Edi */
865 "movl 0xa0(%ecx),%esi\n\t" /* Esi */
866 "movl 0xa4(%ecx),%ebx\n\t" /* Ebx */
867 "movl 0xb4(%ecx),%ebp\n\t" /* Ebp */
869 "cmpw 0xc8(%ecx),%ax\n\t" /* SegSs */
871 /* As soon as we have switched stacks the context structure could
872 * be invalid (when signal handlers are executed for example). Copy
873 * values on the target stack before changing ESP. */
874 "movl 0xc4(%ecx),%eax\n\t" /* Esp */
875 "leal -4*4(%eax),%eax\n\t"
876 "movl 0xc0(%ecx),%edx\n\t" /* EFlags */
877 "movl %edx,3*4(%eax)\n\t"
878 "movl 0xbc(%ecx),%edx\n\t" /* SegCs */
879 "movl %edx,2*4(%eax)\n\t"
880 "movl 0xb8(%ecx),%edx\n\t" /* Eip */
881 "movl %edx,1*4(%eax)\n\t"
882 "movl 0xb0(%ecx),%edx\n\t" /* Eax */
883 "movl %edx,0*4(%eax)\n\t"
884 "pushl 0x98(%ecx)\n\t" /* SegDs */
885 "movl 0xa8(%ecx),%edx\n\t" /* Edx */
886 "movl 0xac(%ecx),%ecx\n\t" /* Ecx */
891 /* Restore the context when the stack segment changes. We can't use
892 * the same code as above because we do not know if the stack segment
893 * is 16 or 32 bit, and 'movl' will throw an exception when we try to
894 * access memory above the limit. */
896 "movl 0xa8(%ecx),%edx\n\t" /* Edx */
897 "movl 0xb0(%ecx),%eax\n\t" /* Eax */
898 "movw 0xc8(%ecx),%ss\n\t" /* SegSs */
899 "movl 0xc4(%ecx),%esp\n\t" /* Esp */
900 "pushl 0xc0(%ecx)\n\t" /* EFlags */
901 "pushl 0xbc(%ecx)\n\t" /* SegCs */
902 "pushl 0xb8(%ecx)\n\t" /* Eip */
903 "pushl 0x98(%ecx)\n\t" /* SegDs */
904 "movl 0xac(%ecx),%ecx\n\t" /* Ecx */
909 /***********************************************************************
910 * get_server_context_flags
912 * Convert CPU-specific flags to generic server flags
914 static unsigned int get_server_context_flags( DWORD flags
)
916 unsigned int ret
= 0;
918 flags
&= ~CONTEXT_i386
; /* get rid of CPU id */
919 if (flags
& CONTEXT_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
920 if (flags
& CONTEXT_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
921 if (flags
& CONTEXT_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
922 if (flags
& CONTEXT_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
923 if (flags
& CONTEXT_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
924 if (flags
& CONTEXT_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
;
929 /***********************************************************************
932 * Convert a register context to the server format.
934 NTSTATUS
context_to_server( context_t
*to
, const CONTEXT
*from
)
936 DWORD flags
= from
->ContextFlags
& ~CONTEXT_i386
; /* get rid of CPU id */
938 memset( to
, 0, sizeof(*to
) );
941 if (flags
& CONTEXT_CONTROL
)
943 to
->flags
|= SERVER_CTX_CONTROL
;
944 to
->ctl
.i386_regs
.ebp
= from
->Ebp
;
945 to
->ctl
.i386_regs
.esp
= from
->Esp
;
946 to
->ctl
.i386_regs
.eip
= from
->Eip
;
947 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
948 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
949 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
951 if (flags
& CONTEXT_INTEGER
)
953 to
->flags
|= SERVER_CTX_INTEGER
;
954 to
->integer
.i386_regs
.eax
= from
->Eax
;
955 to
->integer
.i386_regs
.ebx
= from
->Ebx
;
956 to
->integer
.i386_regs
.ecx
= from
->Ecx
;
957 to
->integer
.i386_regs
.edx
= from
->Edx
;
958 to
->integer
.i386_regs
.esi
= from
->Esi
;
959 to
->integer
.i386_regs
.edi
= from
->Edi
;
961 if (flags
& CONTEXT_SEGMENTS
)
963 to
->flags
|= SERVER_CTX_SEGMENTS
;
964 to
->seg
.i386_regs
.ds
= from
->SegDs
;
965 to
->seg
.i386_regs
.es
= from
->SegEs
;
966 to
->seg
.i386_regs
.fs
= from
->SegFs
;
967 to
->seg
.i386_regs
.gs
= from
->SegGs
;
969 if (flags
& CONTEXT_FLOATING_POINT
)
971 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
972 to
->fp
.i386_regs
.ctrl
= from
->FloatSave
.ControlWord
;
973 to
->fp
.i386_regs
.status
= from
->FloatSave
.StatusWord
;
974 to
->fp
.i386_regs
.tag
= from
->FloatSave
.TagWord
;
975 to
->fp
.i386_regs
.err_off
= from
->FloatSave
.ErrorOffset
;
976 to
->fp
.i386_regs
.err_sel
= from
->FloatSave
.ErrorSelector
;
977 to
->fp
.i386_regs
.data_off
= from
->FloatSave
.DataOffset
;
978 to
->fp
.i386_regs
.data_sel
= from
->FloatSave
.DataSelector
;
979 to
->fp
.i386_regs
.cr0npx
= from
->FloatSave
.Cr0NpxState
;
980 memcpy( to
->fp
.i386_regs
.regs
, from
->FloatSave
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
982 if (flags
& CONTEXT_DEBUG_REGISTERS
)
984 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
985 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
986 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
987 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
988 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
989 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
990 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
992 if (flags
& CONTEXT_EXTENDED_REGISTERS
)
994 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
;
995 memcpy( to
->ext
.i386_regs
, from
->ExtendedRegisters
, sizeof(to
->ext
.i386_regs
) );
997 return STATUS_SUCCESS
;
1001 /***********************************************************************
1002 * context_from_server
1004 * Convert a register context from the server format.
1006 NTSTATUS
context_from_server( CONTEXT
*to
, const context_t
*from
)
1008 if (from
->cpu
!= CPU_x86
) return STATUS_INVALID_PARAMETER
;
1010 to
->ContextFlags
= CONTEXT_i386
;
1011 if (from
->flags
& SERVER_CTX_CONTROL
)
1013 to
->ContextFlags
|= CONTEXT_CONTROL
;
1014 to
->Ebp
= from
->ctl
.i386_regs
.ebp
;
1015 to
->Esp
= from
->ctl
.i386_regs
.esp
;
1016 to
->Eip
= from
->ctl
.i386_regs
.eip
;
1017 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
1018 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
1019 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
1021 if (from
->flags
& SERVER_CTX_INTEGER
)
1023 to
->ContextFlags
|= CONTEXT_INTEGER
;
1024 to
->Eax
= from
->integer
.i386_regs
.eax
;
1025 to
->Ebx
= from
->integer
.i386_regs
.ebx
;
1026 to
->Ecx
= from
->integer
.i386_regs
.ecx
;
1027 to
->Edx
= from
->integer
.i386_regs
.edx
;
1028 to
->Esi
= from
->integer
.i386_regs
.esi
;
1029 to
->Edi
= from
->integer
.i386_regs
.edi
;
1031 if (from
->flags
& SERVER_CTX_SEGMENTS
)
1033 to
->ContextFlags
|= CONTEXT_SEGMENTS
;
1034 to
->SegDs
= from
->seg
.i386_regs
.ds
;
1035 to
->SegEs
= from
->seg
.i386_regs
.es
;
1036 to
->SegFs
= from
->seg
.i386_regs
.fs
;
1037 to
->SegGs
= from
->seg
.i386_regs
.gs
;
1039 if (from
->flags
& SERVER_CTX_FLOATING_POINT
)
1041 to
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
1042 to
->FloatSave
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
1043 to
->FloatSave
.StatusWord
= from
->fp
.i386_regs
.status
;
1044 to
->FloatSave
.TagWord
= from
->fp
.i386_regs
.tag
;
1045 to
->FloatSave
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
1046 to
->FloatSave
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
1047 to
->FloatSave
.DataOffset
= from
->fp
.i386_regs
.data_off
;
1048 to
->FloatSave
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
1049 to
->FloatSave
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
1050 memcpy( to
->FloatSave
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(to
->FloatSave
.RegisterArea
) );
1052 if (from
->flags
& SERVER_CTX_DEBUG_REGISTERS
)
1054 to
->ContextFlags
|= CONTEXT_DEBUG_REGISTERS
;
1055 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
1056 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
1057 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
1058 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
1059 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
1060 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
1062 if (from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
)
1064 to
->ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
1065 memcpy( to
->ExtendedRegisters
, from
->ext
.i386_regs
, sizeof(to
->ExtendedRegisters
) );
1067 return STATUS_SUCCESS
;
1071 /***********************************************************************
1072 * NtSetContextThread (NTDLL.@)
1073 * ZwSetContextThread (NTDLL.@)
1075 NTSTATUS WINAPI
NtSetContextThread( HANDLE handle
, const CONTEXT
*context
)
1077 NTSTATUS ret
= STATUS_SUCCESS
;
1078 DWORD flags
= context
->ContextFlags
& ~CONTEXT_i386
;
1079 BOOL self
= (handle
== GetCurrentThread());
1081 /* debug registers require a server call */
1082 if (self
&& (flags
& CONTEXT_DEBUG_REGISTERS
))
1083 self
= (x86_thread_data()->dr0
== context
->Dr0
&&
1084 x86_thread_data()->dr1
== context
->Dr1
&&
1085 x86_thread_data()->dr2
== context
->Dr2
&&
1086 x86_thread_data()->dr3
== context
->Dr3
&&
1087 x86_thread_data()->dr6
== context
->Dr6
&&
1088 x86_thread_data()->dr7
== context
->Dr7
);
1092 context_t server_context
;
1093 context_to_server( &server_context
, context
);
1094 ret
= set_thread_context( handle
, &server_context
, &self
);
1095 if (ret
|| !self
) return ret
;
1096 if (flags
& CONTEXT_DEBUG_REGISTERS
)
1098 x86_thread_data()->dr0
= context
->Dr0
;
1099 x86_thread_data()->dr1
= context
->Dr1
;
1100 x86_thread_data()->dr2
= context
->Dr2
;
1101 x86_thread_data()->dr3
= context
->Dr3
;
1102 x86_thread_data()->dr6
= context
->Dr6
;
1103 x86_thread_data()->dr7
= context
->Dr7
;
1107 if (flags
& CONTEXT_EXTENDED_REGISTERS
) restore_fpux( context
);
1108 else if (flags
& CONTEXT_FLOATING_POINT
) restore_fpu( context
);
1110 if (flags
& CONTEXT_FULL
)
1112 if (!(flags
& CONTEXT_CONTROL
))
1113 FIXME( "setting partial context (%x) not supported\n", flags
);
1114 else if (flags
& CONTEXT_SEGMENTS
)
1115 set_full_cpu_context( context
);
1118 CONTEXT newcontext
= *context
;
1119 newcontext
.SegDs
= get_ds();
1120 newcontext
.SegEs
= get_ds();
1121 newcontext
.SegFs
= get_fs();
1122 newcontext
.SegGs
= get_gs();
1123 set_full_cpu_context( &newcontext
);
1130 /***********************************************************************
1131 * NtGetContextThread (NTDLL.@)
1132 * ZwGetContextThread (NTDLL.@)
1134 * Note: we use a small assembly wrapper to save the necessary registers
1135 * in case we are fetching the context of the current thread.
1137 NTSTATUS WINAPI
NtGetContextThread( HANDLE handle
, CONTEXT
*context
)
1140 DWORD needed_flags
= context
->ContextFlags
& ~CONTEXT_i386
;
1141 BOOL self
= (handle
== GetCurrentThread());
1143 /* debug registers require a server call */
1144 if (needed_flags
& CONTEXT_DEBUG_REGISTERS
) self
= FALSE
;
1148 context_t server_context
;
1149 unsigned int server_flags
= get_server_context_flags( context
->ContextFlags
);
1151 if ((ret
= get_thread_context( handle
, &server_context
, server_flags
, &self
))) return ret
;
1152 if ((ret
= context_from_server( context
, &server_context
))) return ret
;
1153 needed_flags
&= ~context
->ContextFlags
;
1158 if (needed_flags
& CONTEXT_INTEGER
)
1163 /* other registers already set from asm wrapper */
1164 context
->ContextFlags
|= CONTEXT_INTEGER
;
1166 if (needed_flags
& CONTEXT_CONTROL
)
1168 context
->SegCs
= get_cs();
1169 context
->SegSs
= get_ds();
1170 /* other registers already set from asm wrapper */
1171 context
->ContextFlags
|= CONTEXT_CONTROL
;
1173 if (needed_flags
& CONTEXT_SEGMENTS
)
1175 context
->SegDs
= get_ds();
1176 context
->SegEs
= get_ds();
1177 context
->SegFs
= get_fs();
1178 context
->SegGs
= get_gs();
1179 context
->ContextFlags
|= CONTEXT_SEGMENTS
;
1181 if (needed_flags
& CONTEXT_FLOATING_POINT
) save_fpu( context
);
1182 if (needed_flags
& CONTEXT_EXTENDED_REGISTERS
) save_fpux( context
);
1184 /* update the cached version of the debug registers */
1185 if (context
->ContextFlags
& (CONTEXT_DEBUG_REGISTERS
& ~CONTEXT_i386
))
1187 x86_thread_data()->dr0
= context
->Dr0
;
1188 x86_thread_data()->dr1
= context
->Dr1
;
1189 x86_thread_data()->dr2
= context
->Dr2
;
1190 x86_thread_data()->dr3
= context
->Dr3
;
1191 x86_thread_data()->dr6
= context
->Dr6
;
1192 x86_thread_data()->dr7
= context
->Dr7
;
1196 if (context
->ContextFlags
& (CONTEXT_INTEGER
& ~CONTEXT_i386
))
1197 TRACE( "%p: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n", handle
,
1198 context
->Eax
, context
->Ebx
, context
->Ecx
, context
->Edx
, context
->Esi
, context
->Edi
);
1199 if (context
->ContextFlags
& (CONTEXT_CONTROL
& ~CONTEXT_i386
))
1200 TRACE( "%p: ebp=%08x esp=%08x eip=%08x cs=%04x ss=%04x flags=%08x\n", handle
,
1201 context
->Ebp
, context
->Esp
, context
->Eip
, context
->SegCs
, context
->SegSs
, context
->EFlags
);
1202 if (context
->ContextFlags
& (CONTEXT_SEGMENTS
& ~CONTEXT_i386
))
1203 TRACE( "%p: ds=%04x es=%04x fs=%04x gs=%04x\n", handle
,
1204 context
->SegDs
, context
->SegEs
, context
->SegFs
, context
->SegGs
);
1205 if (context
->ContextFlags
& (CONTEXT_DEBUG_REGISTERS
& ~CONTEXT_i386
))
1206 TRACE( "%p: dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n", handle
,
1207 context
->Dr0
, context
->Dr1
, context
->Dr2
, context
->Dr3
, context
->Dr6
, context
->Dr7
);
1209 return STATUS_SUCCESS
;
1213 /***********************************************************************
1214 * is_privileged_instr
1216 * Check if the fault location is a privileged instruction.
1217 * Based on the instruction emulation code in dlls/kernel/instr.c.
1219 static inline DWORD
is_privileged_instr( CONTEXT
*context
)
1222 unsigned int i
, len
, prefix_count
= 0;
1224 if (!ldt_is_system( context
->SegCs
)) return 0;
1225 len
= virtual_uninterrupted_read_memory( (BYTE
*)context
->Eip
, instr
, sizeof(instr
) );
1227 for (i
= 0; i
< len
; i
++) switch (instr
[i
])
1229 /* instruction prefixes */
1230 case 0x2e: /* %cs: */
1231 case 0x36: /* %ss: */
1232 case 0x3e: /* %ds: */
1233 case 0x26: /* %es: */
1234 case 0x64: /* %fs: */
1235 case 0x65: /* %gs: */
1236 case 0x66: /* opcode size */
1237 case 0x67: /* addr size */
1238 case 0xf0: /* lock */
1239 case 0xf2: /* repne */
1240 case 0xf3: /* repe */
1241 if (++prefix_count
>= 15) return EXCEPTION_ILLEGAL_INSTRUCTION
;
1244 case 0x0f: /* extended instruction */
1245 if (i
== len
- 1) return 0;
1246 switch(instr
[i
+ 1])
1248 case 0x20: /* mov crX, reg */
1249 case 0x21: /* mov drX, reg */
1250 case 0x22: /* mov reg, crX */
1251 case 0x23: /* mov reg drX */
1252 return EXCEPTION_PRIV_INSTRUCTION
;
1255 case 0x6c: /* insb (%dx) */
1256 case 0x6d: /* insl (%dx) */
1257 case 0x6e: /* outsb (%dx) */
1258 case 0x6f: /* outsl (%dx) */
1259 case 0xcd: /* int $xx */
1260 case 0xe4: /* inb al,XX */
1261 case 0xe5: /* in (e)ax,XX */
1262 case 0xe6: /* outb XX,al */
1263 case 0xe7: /* out XX,(e)ax */
1264 case 0xec: /* inb (%dx),%al */
1265 case 0xed: /* inl (%dx),%eax */
1266 case 0xee: /* outb %al,(%dx) */
1267 case 0xef: /* outl %eax,(%dx) */
1268 case 0xf4: /* hlt */
1269 case 0xfa: /* cli */
1270 case 0xfb: /* sti */
1271 return EXCEPTION_PRIV_INSTRUCTION
;
1279 /***********************************************************************
1282 * Check for fault caused by invalid %gs value (some copy protection schemes mess with it).
1284 static inline BOOL
check_invalid_gs( ucontext_t
*sigcontext
, CONTEXT
*context
)
1286 unsigned int prefix_count
= 0;
1287 const BYTE
*instr
= (BYTE
*)context
->Eip
;
1288 WORD system_gs
= x86_thread_data()->gs
;
1290 if (context
->SegGs
== system_gs
) return FALSE
;
1291 if (!ldt_is_system( context
->SegCs
)) return FALSE
;
1292 /* only handle faults in system libraries */
1293 if (virtual_is_valid_code_address( instr
, 1 )) return FALSE
;
1295 for (;;) switch(*instr
)
1297 /* instruction prefixes */
1298 case 0x2e: /* %cs: */
1299 case 0x36: /* %ss: */
1300 case 0x3e: /* %ds: */
1301 case 0x26: /* %es: */
1302 case 0x64: /* %fs: */
1303 case 0x66: /* opcode size */
1304 case 0x67: /* addr size */
1305 case 0xf0: /* lock */
1306 case 0xf2: /* repne */
1307 case 0xf3: /* repe */
1308 if (++prefix_count
>= 15) return FALSE
;
1311 case 0x65: /* %gs: */
1312 TRACE( "%04x/%04x at %p, fixing up\n", context
->SegGs
, system_gs
, instr
);
1313 GS_sig(sigcontext
) = system_gs
;
1321 #include "pshpack1.h"
1326 DWORD movl
; /* movl this,4(%esp) */
1328 BYTE jmp
; /* jmp func */
1333 BYTE movl
; /* movl this,ecx */
1335 BYTE jmp
; /* jmp func */
1340 BYTE movl1
; /* movl this,edx */
1342 BYTE movl2
; /* movl func,ecx */
1344 WORD jmp
; /* jmp ecx */
1348 BYTE movl1
; /* movl this,ecx */
1350 BYTE movl2
; /* movl func,eax */
1352 WORD jmp
; /* jmp eax */
1356 DWORD inst1
; /* pop ecx
1363 #include "poppack.h"
1365 /**********************************************************************
1368 * Check if code destination is an ATL thunk, and emulate it if so.
1370 static BOOL
check_atl_thunk( ucontext_t
*sigcontext
, EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1372 const union atl_thunk
*thunk
= (const union atl_thunk
*)rec
->ExceptionInformation
[1];
1373 union atl_thunk thunk_copy
;
1376 thunk_len
= virtual_uninterrupted_read_memory( thunk
, &thunk_copy
, sizeof(*thunk
) );
1377 if (!thunk_len
) return FALSE
;
1379 if (thunk_len
>= sizeof(thunk_copy
.t1
) && thunk_copy
.t1
.movl
== 0x042444c7 &&
1380 thunk_copy
.t1
.jmp
== 0xe9)
1382 if (!virtual_uninterrupted_write_memory( (DWORD
*)context
->Esp
+ 1,
1383 &thunk_copy
.t1
.this, sizeof(DWORD
) ))
1385 EIP_sig(sigcontext
) = (DWORD_PTR
)(&thunk
->t1
.func
+ 1) + thunk_copy
.t1
.func
;
1386 TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n",
1387 thunk
, EIP_sig(sigcontext
), thunk_copy
.t1
.this );
1391 else if (thunk_len
>= sizeof(thunk_copy
.t2
) && thunk_copy
.t2
.movl
== 0xb9 &&
1392 thunk_copy
.t2
.jmp
== 0xe9)
1394 ECX_sig(sigcontext
) = thunk_copy
.t2
.this;
1395 EIP_sig(sigcontext
) = (DWORD_PTR
)(&thunk
->t2
.func
+ 1) + thunk_copy
.t2
.func
;
1396 TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n",
1397 thunk
, EIP_sig(sigcontext
), ECX_sig(sigcontext
) );
1400 else if (thunk_len
>= sizeof(thunk_copy
.t3
) && thunk_copy
.t3
.movl1
== 0xba &&
1401 thunk_copy
.t3
.movl2
== 0xb9 &&
1402 thunk_copy
.t3
.jmp
== 0xe1ff)
1404 EDX_sig(sigcontext
) = thunk_copy
.t3
.this;
1405 ECX_sig(sigcontext
) = thunk_copy
.t3
.func
;
1406 EIP_sig(sigcontext
) = thunk_copy
.t3
.func
;
1407 TRACE( "emulating ATL thunk type 3 at %p, func=%08x ecx=%08x edx=%08x\n",
1408 thunk
, EIP_sig(sigcontext
), ECX_sig(sigcontext
), EDX_sig(sigcontext
) );
1411 else if (thunk_len
>= sizeof(thunk_copy
.t4
) && thunk_copy
.t4
.movl1
== 0xb9 &&
1412 thunk_copy
.t4
.movl2
== 0xb8 &&
1413 thunk_copy
.t4
.jmp
== 0xe0ff)
1415 ECX_sig(sigcontext
) = thunk_copy
.t4
.this;
1416 EAX_sig(sigcontext
) = thunk_copy
.t4
.func
;
1417 EIP_sig(sigcontext
) = thunk_copy
.t4
.func
;
1418 TRACE( "emulating ATL thunk type 4 at %p, func=%08x eax=%08x ecx=%08x\n",
1419 thunk
, EIP_sig(sigcontext
), EAX_sig(sigcontext
), ECX_sig(sigcontext
) );
1422 else if (thunk_len
>= sizeof(thunk_copy
.t5
) && thunk_copy
.t5
.inst1
== 0xff515859 &&
1423 thunk_copy
.t5
.inst2
== 0x0460)
1426 if (virtual_uninterrupted_read_memory( (DWORD
*)context
->Esp
, sp
, sizeof(sp
) ) == sizeof(sp
) &&
1427 virtual_uninterrupted_read_memory( (DWORD
*)sp
[1] + 1, &func
, sizeof(DWORD
) ) == sizeof(DWORD
) &&
1428 !virtual_uninterrupted_write_memory( (DWORD
*)context
->Esp
+ 1, &sp
[0], sizeof(sp
[0]) ))
1430 ECX_sig(sigcontext
) = sp
[0];
1431 EAX_sig(sigcontext
) = sp
[1];
1432 ESP_sig(sigcontext
) += sizeof(DWORD
);
1433 EIP_sig(sigcontext
) = func
;
1434 TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n",
1435 thunk
, EIP_sig(sigcontext
), EAX_sig(sigcontext
),
1436 ECX_sig(sigcontext
), ESP_sig(sigcontext
) );
1445 /***********************************************************************
1446 * setup_exception_record
1448 * Setup the exception record and context on the thread stack.
1450 static void *setup_exception_record( ucontext_t
*sigcontext
, EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1452 void *stack
= init_handler( sigcontext
);
1454 rec
->ExceptionAddress
= (void *)EIP_sig( sigcontext
);
1455 save_context( context
, sigcontext
);
1460 /***********************************************************************
1461 * setup_raise_exception
1463 * Change context to setup a call to a raise exception function.
1465 static void setup_raise_exception( ucontext_t
*sigcontext
, void *stack_ptr
,
1466 EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1470 EXCEPTION_RECORD
*rec_ptr
; /* first arg for KiUserExceptionDispatcher */
1471 CONTEXT
*context_ptr
; /* second arg for KiUserExceptionDispatcher */
1473 EXCEPTION_RECORD rec
;
1478 NTSTATUS status
= send_debug_event( rec
, context
, TRUE
);
1480 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
1482 restore_context( context
, sigcontext
);
1486 /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
1487 if (rec
->ExceptionCode
== EXCEPTION_BREAKPOINT
) context
->Eip
--;
1489 stack
= virtual_setup_exception( stack_ptr
, sizeof(*stack
), rec
);
1491 stack
->context
= *context
;
1492 stack
->rec_ptr
= &stack
->rec
;
1493 stack
->context_ptr
= &stack
->context
;
1494 ESP_sig(sigcontext
) = (DWORD
)stack
;
1495 EIP_sig(sigcontext
) = (DWORD
)pKiUserExceptionDispatcher
;
1496 /* clear single-step, direction, and align check flag */
1497 EFL_sig(sigcontext
) &= ~(0x100|0x400|0x40000);
1498 CS_sig(sigcontext
) = get_cs();
1499 DS_sig(sigcontext
) = get_ds();
1500 ES_sig(sigcontext
) = get_ds();
1501 FS_sig(sigcontext
) = get_fs();
1502 GS_sig(sigcontext
) = get_gs();
1503 SS_sig(sigcontext
) = get_ds();
1507 /***********************************************************************
1510 * Do the full setup to raise an exception from an exception record.
1512 static void setup_exception( ucontext_t
*sigcontext
, EXCEPTION_RECORD
*rec
)
1515 void *stack
= setup_exception_record( sigcontext
, rec
, &context
);
1516 setup_raise_exception( sigcontext
, stack
, rec
, &context
);
1519 __ASM_GLOBAL_FUNC( call_user_exception_dispatcher
,
1521 "movl (%esp),%eax\n\t" /* rec */
1522 "cmpl $0x80000003,(%eax)\n\t" /* ExceptionCode */
1524 "movl 4(%esp),%eax\n\t" /* context */
1525 "decl 0xb8(%eax)\n\t" /* Eip */
1528 /**********************************************************************
1531 * Get the FPU exception code from the FPU status.
1533 static inline DWORD
get_fpu_code( const CONTEXT
*context
)
1535 DWORD status
= context
->FloatSave
.StatusWord
& ~(context
->FloatSave
.ControlWord
& 0x3f);
1537 if (status
& 0x01) /* IE */
1539 if (status
& 0x40) /* SF */
1540 return EXCEPTION_FLT_STACK_CHECK
;
1542 return EXCEPTION_FLT_INVALID_OPERATION
;
1544 if (status
& 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND
; /* DE flag */
1545 if (status
& 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO
; /* ZE flag */
1546 if (status
& 0x08) return EXCEPTION_FLT_OVERFLOW
; /* OE flag */
1547 if (status
& 0x10) return EXCEPTION_FLT_UNDERFLOW
; /* UE flag */
1548 if (status
& 0x20) return EXCEPTION_FLT_INEXACT_RESULT
; /* PE flag */
1549 return EXCEPTION_FLT_INVALID_OPERATION
; /* generic error */
1553 /***********************************************************************
1556 * Handle an interrupt.
1558 static BOOL
handle_interrupt( unsigned int interrupt
, ucontext_t
*sigcontext
, void *stack
,
1559 EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1566 /* On Wow64, the upper DWORD of Rax contains garbage, and the debug
1567 * service is usually not recognized when called from usermode. */
1568 switch (context
->Eax
)
1570 case 1: /* BREAKPOINT_PRINT */
1571 case 3: /* BREAKPOINT_LOAD_SYMBOLS */
1572 case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */
1573 case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */
1574 EIP_sig(sigcontext
) += 3;
1579 rec
->ExceptionCode
= EXCEPTION_BREAKPOINT
;
1580 rec
->ExceptionAddress
= (void *)context
->Eip
;
1581 rec
->NumberParameters
= is_wow64
? 1 : 3;
1582 rec
->ExceptionInformation
[0] = context
->Eax
;
1583 rec
->ExceptionInformation
[1] = context
->Ecx
;
1584 rec
->ExceptionInformation
[2] = context
->Edx
;
1585 setup_raise_exception( sigcontext
, stack
, rec
, context
);
1593 /**********************************************************************
1596 * Handler for SIGSEGV and related errors.
1598 static void segv_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1600 EXCEPTION_RECORD rec
= { 0 };
1602 ucontext_t
*ucontext
= sigcontext
;
1603 void *stack
= setup_exception_record( sigcontext
, &rec
, &context
);
1605 switch (TRAP_sig(ucontext
))
1607 case TRAP_x86_OFLOW
: /* Overflow exception */
1608 rec
.ExceptionCode
= EXCEPTION_INT_OVERFLOW
;
1610 case TRAP_x86_BOUND
: /* Bound range exception */
1611 rec
.ExceptionCode
= EXCEPTION_ARRAY_BOUNDS_EXCEEDED
;
1613 case TRAP_x86_PRIVINFLT
: /* Invalid opcode exception */
1614 rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1616 case TRAP_x86_STKFLT
: /* Stack fault */
1617 rec
.ExceptionCode
= EXCEPTION_STACK_OVERFLOW
;
1619 case TRAP_x86_SEGNPFLT
: /* Segment not present exception */
1620 case TRAP_x86_PROTFLT
: /* General protection fault */
1622 WORD err
= ERROR_sig(ucontext
);
1623 if (!err
&& (rec
.ExceptionCode
= is_privileged_instr( &context
))) break;
1624 if ((err
& 7) == 2 && handle_interrupt( err
>> 3, ucontext
, stack
, &rec
, &context
)) return;
1625 rec
.ExceptionCode
= EXCEPTION_ACCESS_VIOLATION
;
1626 rec
.NumberParameters
= 2;
1627 rec
.ExceptionInformation
[0] = 0;
1628 /* if error contains a LDT selector, use that as fault address */
1629 if ((err
& 7) == 4 && !ldt_is_system( err
| 7 )) rec
.ExceptionInformation
[1] = err
& ~7;
1632 rec
.ExceptionInformation
[1] = 0xffffffff;
1633 if (check_invalid_gs( ucontext
, &context
)) return;
1637 case TRAP_x86_PAGEFLT
: /* Page fault */
1638 rec
.NumberParameters
= 2;
1639 rec
.ExceptionInformation
[0] = (ERROR_sig(ucontext
) >> 1) & 0x09;
1640 rec
.ExceptionInformation
[1] = (ULONG_PTR
)siginfo
->si_addr
;
1641 rec
.ExceptionCode
= virtual_handle_fault( siginfo
->si_addr
, rec
.ExceptionInformation
[0], stack
);
1642 if (!rec
.ExceptionCode
) return;
1643 if (rec
.ExceptionCode
== EXCEPTION_ACCESS_VIOLATION
&&
1644 rec
.ExceptionInformation
[0] == EXCEPTION_EXECUTE_FAULT
)
1647 NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags
,
1648 &flags
, sizeof(flags
), NULL
);
1649 if (!(flags
& MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
) &&
1650 check_atl_thunk( ucontext
, &rec
, &context
))
1653 /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */
1654 if (!(flags
& MEM_EXECUTE_OPTION_DISABLE
)) rec
.ExceptionInformation
[0] = EXCEPTION_READ_FAULT
;
1657 case TRAP_x86_ALIGNFLT
: /* Alignment check exception */
1658 /* FIXME: pass through exception handler first? */
1659 if (context
.EFlags
& 0x00040000)
1661 EFL_sig(ucontext
) &= ~0x00040000; /* disable AC flag */
1664 rec
.ExceptionCode
= EXCEPTION_DATATYPE_MISALIGNMENT
;
1667 WINE_ERR( "Got unexpected trap %d\n", TRAP_sig(ucontext
) );
1669 case TRAP_x86_NMI
: /* NMI interrupt */
1670 case TRAP_x86_DNA
: /* Device not available exception */
1671 case TRAP_x86_DOUBLEFLT
: /* Double fault exception */
1672 case TRAP_x86_TSSFLT
: /* Invalid TSS exception */
1673 case TRAP_x86_MCHK
: /* Machine check exception */
1674 case TRAP_x86_CACHEFLT
: /* Cache flush exception */
1675 rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1678 setup_raise_exception( ucontext
, stack
, &rec
, &context
);
1682 /**********************************************************************
1685 * Handler for SIGTRAP.
1687 static void trap_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1689 EXCEPTION_RECORD rec
= { 0 };
1691 ucontext_t
*ucontext
= sigcontext
;
1692 void *stack
= setup_exception_record( sigcontext
, &rec
, &context
);
1694 switch (TRAP_sig(ucontext
))
1696 case TRAP_x86_TRCTRAP
: /* Single-step exception */
1697 rec
.ExceptionCode
= EXCEPTION_SINGLE_STEP
;
1698 /* when single stepping can't tell whether this is a hw bp or a
1699 * single step interrupt. try to avoid as much overhead as possible
1700 * and only do a server call if there is any hw bp enabled. */
1701 if (!(context
.EFlags
& 0x100) || (context
.Dr7
& 0xff))
1703 /* (possible) hardware breakpoint, fetch the debug registers */
1704 DWORD saved_flags
= context
.ContextFlags
;
1705 context
.ContextFlags
= CONTEXT_DEBUG_REGISTERS
;
1706 NtGetContextThread( GetCurrentThread(), &context
);
1707 context
.ContextFlags
|= saved_flags
; /* restore flags */
1709 context
.EFlags
&= ~0x100; /* clear single-step flag */
1711 case TRAP_x86_BPTFLT
: /* Breakpoint exception */
1712 rec
.ExceptionAddress
= (char *)rec
.ExceptionAddress
- 1; /* back up over the int3 instruction */
1715 rec
.ExceptionCode
= EXCEPTION_BREAKPOINT
;
1716 rec
.NumberParameters
= is_wow64
? 1 : 3;
1717 rec
.ExceptionInformation
[0] = 0;
1718 rec
.ExceptionInformation
[1] = 0; /* FIXME */
1719 rec
.ExceptionInformation
[2] = 0; /* FIXME */
1722 setup_raise_exception( sigcontext
, stack
, &rec
, &context
);
1726 /**********************************************************************
1729 * Handler for SIGFPE.
1731 static void fpe_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1733 EXCEPTION_RECORD rec
= { 0 };
1735 ucontext_t
*ucontext
= sigcontext
;
1736 void *stack
= setup_exception_record( sigcontext
, &rec
, &context
);
1738 switch (TRAP_sig(ucontext
))
1740 case TRAP_x86_DIVIDE
: /* Division by zero exception */
1741 rec
.ExceptionCode
= EXCEPTION_INT_DIVIDE_BY_ZERO
;
1743 case TRAP_x86_FPOPFLT
: /* Coprocessor segment overrun */
1744 rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
1746 case TRAP_x86_ARITHTRAP
: /* Floating point exception */
1747 rec
.ExceptionCode
= get_fpu_code( &context
);
1748 rec
.ExceptionAddress
= (void *)context
.FloatSave
.ErrorOffset
;
1750 case TRAP_x86_CACHEFLT
: /* SIMD exception */
1752 * Behaviour only tested for divide-by-zero exceptions
1753 * Check for other SIMD exceptions as well */
1754 if(siginfo
->si_code
!= FPE_FLTDIV
&& siginfo
->si_code
!= FPE_FLTINV
)
1755 FIXME("untested SIMD exception: %#x. Might not work correctly\n",
1758 rec
.ExceptionCode
= STATUS_FLOAT_MULTIPLE_TRAPS
;
1759 rec
.NumberParameters
= 1;
1760 /* no idea what meaning is actually behind this but that's what native does */
1761 rec
.ExceptionInformation
[0] = 0;
1764 WINE_ERR( "Got unexpected trap %d\n", TRAP_sig(ucontext
) );
1765 rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
1768 setup_raise_exception( sigcontext
, stack
, &rec
, &context
);
1772 /**********************************************************************
1775 * Handler for SIGINT.
1777 static void int_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1779 EXCEPTION_RECORD rec
= { CONTROL_C_EXIT
};
1781 setup_exception( sigcontext
, &rec
);
1784 /**********************************************************************
1787 * Handler for SIGABRT.
1789 static void abrt_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1791 EXCEPTION_RECORD rec
= { EXCEPTION_WINE_ASSERTION
, EH_NONCONTINUABLE
};
1793 setup_exception( sigcontext
, &rec
);
1797 /**********************************************************************
1800 * Handler for SIGQUIT.
1802 static void quit_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1804 init_handler( sigcontext
);
1809 /**********************************************************************
1812 * Handler for SIGUSR1, used to signal a thread that it got suspended.
1814 static void usr1_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1818 init_handler( sigcontext
);
1819 save_context( &context
, sigcontext
);
1820 wait_suspend( &context
);
1821 restore_context( &context
, sigcontext
);
1825 /***********************************************************************
1829 #define LDT_SIZE 8192
1831 #define LDT_FLAGS_DATA 0x13 /* Data segment */
1832 #define LDT_FLAGS_CODE 0x1b /* Code segment */
1833 #define LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */
1834 #define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated */
1838 void *base
[LDT_SIZE
];
1839 unsigned int limit
[LDT_SIZE
];
1840 unsigned char flags
[LDT_SIZE
];
1843 static WORD gdt_fs_sel
;
1844 static pthread_mutex_t ldt_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1845 static const LDT_ENTRY null_entry
;
1847 static inline void *ldt_get_base( LDT_ENTRY ent
)
1849 return (void *)(ent
.BaseLow
|
1850 (ULONG_PTR
)ent
.HighWord
.Bits
.BaseMid
<< 16 |
1851 (ULONG_PTR
)ent
.HighWord
.Bits
.BaseHi
<< 24);
1854 static inline unsigned int ldt_get_limit( LDT_ENTRY ent
)
1856 unsigned int limit
= ent
.LimitLow
| (ent
.HighWord
.Bits
.LimitHi
<< 16);
1857 if (ent
.HighWord
.Bits
.Granularity
) limit
= (limit
<< 12) | 0xfff;
1861 static LDT_ENTRY
ldt_make_entry( void *base
, unsigned int limit
, unsigned char flags
)
1865 entry
.BaseLow
= (WORD
)(ULONG_PTR
)base
;
1866 entry
.HighWord
.Bits
.BaseMid
= (BYTE
)((ULONG_PTR
)base
>> 16);
1867 entry
.HighWord
.Bits
.BaseHi
= (BYTE
)((ULONG_PTR
)base
>> 24);
1868 if ((entry
.HighWord
.Bits
.Granularity
= (limit
>= 0x100000))) limit
>>= 12;
1869 entry
.LimitLow
= (WORD
)limit
;
1870 entry
.HighWord
.Bits
.LimitHi
= limit
>> 16;
1871 entry
.HighWord
.Bits
.Dpl
= 3;
1872 entry
.HighWord
.Bits
.Pres
= 1;
1873 entry
.HighWord
.Bits
.Type
= flags
;
1874 entry
.HighWord
.Bits
.Sys
= 0;
1875 entry
.HighWord
.Bits
.Reserved_0
= 0;
1876 entry
.HighWord
.Bits
.Default_Big
= (flags
& LDT_FLAGS_32BIT
) != 0;
1880 static void ldt_set_entry( WORD sel
, LDT_ENTRY entry
)
1882 int index
= sel
>> 3;
1885 struct modify_ldt_s ldt_info
= { index
};
1887 ldt_info
.base_addr
= ldt_get_base( entry
);
1888 ldt_info
.limit
= entry
.LimitLow
| (entry
.HighWord
.Bits
.LimitHi
<< 16);
1889 ldt_info
.seg_32bit
= entry
.HighWord
.Bits
.Default_Big
;
1890 ldt_info
.contents
= (entry
.HighWord
.Bits
.Type
>> 2) & 3;
1891 ldt_info
.read_exec_only
= !(entry
.HighWord
.Bits
.Type
& 2);
1892 ldt_info
.limit_in_pages
= entry
.HighWord
.Bits
.Granularity
;
1893 ldt_info
.seg_not_present
= !entry
.HighWord
.Bits
.Pres
;
1894 ldt_info
.usable
= entry
.HighWord
.Bits
.Sys
;
1895 if (modify_ldt( 0x11, &ldt_info
, sizeof(ldt_info
) ) < 0) perror( "modify_ldt" );
1896 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__)
1897 /* The kernel will only let us set LDTs with user priority level */
1898 if (entry
.HighWord
.Bits
.Pres
&& entry
.HighWord
.Bits
.Dpl
!= 3) entry
.HighWord
.Bits
.Dpl
= 3;
1899 if (i386_set_ldt(index
, (union descriptor
*)&entry
, 1) < 0)
1901 perror("i386_set_ldt");
1902 fprintf( stderr
, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" );
1905 #elif defined(__svr4__) || defined(_SCO_DS)
1909 ldt_mod
.bo
= (unsigned long)ldt_get_base( entry
);
1910 ldt_mod
.ls
= entry
.LimitLow
| (entry
.HighWord
.Bits
.LimitHi
<< 16);
1911 ldt_mod
.acc1
= entry
.HighWord
.Bytes
.Flags1
;
1912 ldt_mod
.acc2
= entry
.HighWord
.Bytes
.Flags2
>> 4;
1913 if (sysi86(SI86DSCR
, &ldt_mod
) == -1) perror("sysi86");
1914 #elif defined(__APPLE__)
1915 if (i386_set_ldt(index
, (union ldt_entry
*)&entry
, 1) < 0) perror("i386_set_ldt");
1916 #elif defined(__GNU__)
1917 if (i386_set_ldt(mach_thread_self(), sel
, (descriptor_list_t
)&entry
, 1) != KERN_SUCCESS
)
1918 perror("i386_set_ldt");
1920 fprintf( stderr
, "No LDT support on this platform\n" );
1924 __wine_ldt_copy
.base
[index
] = ldt_get_base( entry
);
1925 __wine_ldt_copy
.limit
[index
] = ldt_get_limit( entry
);
1926 __wine_ldt_copy
.flags
[index
] = (entry
.HighWord
.Bits
.Type
|
1927 (entry
.HighWord
.Bits
.Default_Big
? LDT_FLAGS_32BIT
: 0) |
1928 LDT_FLAGS_ALLOCATED
);
1931 static void ldt_set_fs( WORD sel
, TEB
*teb
)
1933 if (sel
== gdt_fs_sel
)
1936 struct modify_ldt_s ldt_info
= { sel
>> 3 };
1938 ldt_info
.base_addr
= teb
;
1939 ldt_info
.limit
= teb_size
- 1;
1940 ldt_info
.seg_32bit
= 1;
1941 if (set_thread_area( &ldt_info
) < 0) perror( "set_thread_area" );
1942 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
1943 i386_set_fsbase( teb
);
1950 /**********************************************************************
1951 * get_thread_ldt_entry
1953 NTSTATUS
get_thread_ldt_entry( HANDLE handle
, void *data
, ULONG len
, ULONG
*ret_len
)
1955 THREAD_DESCRIPTOR_INFORMATION
*info
= data
;
1956 NTSTATUS status
= STATUS_SUCCESS
;
1958 if (len
< sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
1959 if (info
->Selector
>> 16) return STATUS_UNSUCCESSFUL
;
1961 if (is_gdt_sel( info
->Selector
))
1963 if (!(info
->Selector
& ~3))
1964 info
->Entry
= null_entry
;
1965 else if ((info
->Selector
| 3) == get_cs())
1966 info
->Entry
= ldt_make_entry( 0, ~0u, LDT_FLAGS_CODE
| LDT_FLAGS_32BIT
);
1967 else if ((info
->Selector
| 3) == get_ds())
1968 info
->Entry
= ldt_make_entry( 0, ~0u, LDT_FLAGS_DATA
| LDT_FLAGS_32BIT
);
1969 else if ((info
->Selector
| 3) == get_fs())
1970 info
->Entry
= ldt_make_entry( NtCurrentTeb(), 0xfff, LDT_FLAGS_DATA
| LDT_FLAGS_32BIT
);
1972 return STATUS_UNSUCCESSFUL
;
1976 SERVER_START_REQ( get_selector_entry
)
1978 req
->handle
= wine_server_obj_handle( handle
);
1979 req
->entry
= info
->Selector
>> 3;
1980 status
= wine_server_call( req
);
1984 info
->Entry
= ldt_make_entry( (void *)reply
->base
, reply
->limit
, reply
->flags
);
1986 status
= STATUS_UNSUCCESSFUL
;
1991 if (status
== STATUS_SUCCESS
&& ret_len
)
1992 /* yes, that's a bit strange, but it's the way it is */
1993 *ret_len
= sizeof(info
->Entry
);
1999 /******************************************************************************
2000 * NtSetLdtEntries (NTDLL.@)
2001 * ZwSetLdtEntries (NTDLL.@)
2003 NTSTATUS WINAPI
NtSetLdtEntries( ULONG sel1
, LDT_ENTRY entry1
, ULONG sel2
, LDT_ENTRY entry2
)
2007 if (sel1
>> 16 || sel2
>> 16) return STATUS_INVALID_LDT_DESCRIPTOR
;
2008 if (sel1
&& (sel1
>> 3) < first_ldt_entry
) return STATUS_INVALID_LDT_DESCRIPTOR
;
2009 if (sel2
&& (sel2
>> 3) < first_ldt_entry
) return STATUS_INVALID_LDT_DESCRIPTOR
;
2011 server_enter_uninterrupted_section( &ldt_mutex
, &sigset
);
2012 if (sel1
) ldt_set_entry( sel1
, entry1
);
2013 if (sel2
) ldt_set_entry( sel2
, entry2
);
2014 server_leave_uninterrupted_section( &ldt_mutex
, &sigset
);
2015 return STATUS_SUCCESS
;
2019 /**********************************************************************
2020 * signal_init_threading
2022 void signal_init_threading(void)
2025 /* the preloader may have allocated it already */
2026 gdt_fs_sel
= get_fs();
2027 if (!gdt_fs_sel
|| !is_gdt_sel( gdt_fs_sel
))
2029 struct modify_ldt_s ldt_info
= { -1 };
2031 ldt_info
.seg_32bit
= 1;
2032 ldt_info
.usable
= 1;
2033 if (set_thread_area( &ldt_info
) >= 0) gdt_fs_sel
= (ldt_info
.entry_number
<< 3) | 3;
2034 else gdt_fs_sel
= 0;
2036 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
2037 gdt_fs_sel
= GSEL( GUFS_SEL
, SEL_UPL
);
2042 /**********************************************************************
2043 * signal_alloc_thread
2045 NTSTATUS
signal_alloc_thread( TEB
*teb
)
2047 struct x86_thread_data
*thread_data
= (struct x86_thread_data
*)teb
->SystemReserved2
;
2051 static int first_thread
= 1;
2054 LDT_ENTRY entry
= ldt_make_entry( teb
, teb_size
- 1, LDT_FLAGS_DATA
| LDT_FLAGS_32BIT
);
2056 if (first_thread
) /* no locking for first thread */
2058 /* leave some space if libc is using the LDT for %gs */
2059 if (!is_gdt_sel( get_gs() )) first_ldt_entry
= 512;
2060 idx
= first_ldt_entry
;
2061 ldt_set_entry( (idx
<< 3) | 7, entry
);
2066 server_enter_uninterrupted_section( &ldt_mutex
, &sigset
);
2067 for (idx
= first_ldt_entry
; idx
< LDT_SIZE
; idx
++)
2069 if (__wine_ldt_copy
.flags
[idx
]) continue;
2070 ldt_set_entry( (idx
<< 3) | 7, entry
);
2073 server_leave_uninterrupted_section( &ldt_mutex
, &sigset
);
2074 if (idx
== LDT_SIZE
) return STATUS_TOO_MANY_THREADS
;
2076 thread_data
->fs
= (idx
<< 3) | 7;
2078 else thread_data
->fs
= gdt_fs_sel
;
2080 return STATUS_SUCCESS
;
2084 /**********************************************************************
2085 * signal_free_thread
2087 void signal_free_thread( TEB
*teb
)
2089 struct x86_thread_data
*thread_data
= (struct x86_thread_data
*)teb
->SystemReserved2
;
2092 if (gdt_fs_sel
) return;
2094 server_enter_uninterrupted_section( &ldt_mutex
, &sigset
);
2095 __wine_ldt_copy
.flags
[thread_data
->fs
>> 3] = 0;
2096 server_leave_uninterrupted_section( &ldt_mutex
, &sigset
);
2100 /**********************************************************************
2101 * signal_init_thread
2103 void signal_init_thread( TEB
*teb
)
2105 const WORD fpu_cw
= 0x27f;
2106 struct x86_thread_data
*thread_data
= (struct x86_thread_data
*)teb
->SystemReserved2
;
2108 ldt_set_fs( thread_data
->fs
, teb
);
2109 thread_data
->gs
= get_gs();
2111 __asm__
volatile ("fninit; fldcw %0" : : "m" (fpu_cw
));
2115 /**********************************************************************
2116 * signal_init_process
2118 void signal_init_process(void)
2120 struct sigaction sig_act
;
2122 sig_act
.sa_mask
= server_block_set
;
2123 sig_act
.sa_flags
= SA_SIGINFO
| SA_RESTART
| SA_ONSTACK
;
2125 sig_act
.sa_flags
|= SA_RESTORER
;
2126 sig_act
.sa_restorer
= rt_sigreturn
;
2128 sig_act
.sa_sigaction
= int_handler
;
2129 if (sigaction( SIGINT
, &sig_act
, NULL
) == -1) goto error
;
2130 sig_act
.sa_sigaction
= fpe_handler
;
2131 if (sigaction( SIGFPE
, &sig_act
, NULL
) == -1) goto error
;
2132 sig_act
.sa_sigaction
= abrt_handler
;
2133 if (sigaction( SIGABRT
, &sig_act
, NULL
) == -1) goto error
;
2134 sig_act
.sa_sigaction
= quit_handler
;
2135 if (sigaction( SIGQUIT
, &sig_act
, NULL
) == -1) goto error
;
2136 sig_act
.sa_sigaction
= usr1_handler
;
2137 if (sigaction( SIGUSR1
, &sig_act
, NULL
) == -1) goto error
;
2138 sig_act
.sa_sigaction
= trap_handler
;
2139 if (sigaction( SIGTRAP
, &sig_act
, NULL
) == -1) goto error
;
2140 sig_act
.sa_sigaction
= segv_handler
;
2141 if (sigaction( SIGSEGV
, &sig_act
, NULL
) == -1) goto error
;
2142 if (sigaction( SIGILL
, &sig_act
, NULL
) == -1) goto error
;
2143 if (sigaction( SIGBUS
, &sig_act
, NULL
) == -1) goto error
;
2147 perror("sigaction");
2152 /***********************************************************************
2153 * init_thread_context
2155 static void init_thread_context( CONTEXT
*context
, LPTHREAD_START_ROUTINE entry
, void *arg
, void *relay
)
2157 context
->SegCs
= get_cs();
2158 context
->SegDs
= get_ds();
2159 context
->SegEs
= get_ds();
2160 context
->SegFs
= get_fs();
2161 context
->SegGs
= get_gs();
2162 context
->SegSs
= get_ds();
2163 context
->EFlags
= 0x202;
2164 context
->Eax
= (DWORD
)entry
;
2165 context
->Ebx
= (DWORD
)arg
;
2166 context
->Esp
= (DWORD
)NtCurrentTeb()->Tib
.StackBase
- 16;
2167 context
->Eip
= (DWORD
)relay
;
2168 context
->FloatSave
.ControlWord
= 0x27f;
2169 ((XMM_SAVE_AREA32
*)context
->ExtendedRegisters
)->ControlWord
= 0x27f;
2170 ((XMM_SAVE_AREA32
*)context
->ExtendedRegisters
)->MxCsr
= 0x1f80;
2174 /***********************************************************************
2177 PCONTEXT DECLSPEC_HIDDEN
attach_thread( LPTHREAD_START_ROUTINE entry
, void *arg
,
2178 BOOL suspend
, void *relay
)
2184 CONTEXT context
= { CONTEXT_ALL
};
2186 init_thread_context( &context
, entry
, arg
, relay
);
2187 wait_suspend( &context
);
2188 ctx
= (CONTEXT
*)((ULONG_PTR
)context
.Esp
& ~15) - 1;
2193 ctx
= (CONTEXT
*)((char *)NtCurrentTeb()->Tib
.StackBase
- 16) - 1;
2194 init_thread_context( ctx
, entry
, arg
, relay
);
2196 pthread_sigmask( SIG_UNBLOCK
, &server_block_set
, NULL
);
2197 ctx
->ContextFlags
= CONTEXT_FULL
| CONTEXT_FLOATING_POINT
| CONTEXT_EXTENDED_REGISTERS
;
2198 pLdrInitializeThunk( ctx
, (void **)&ctx
->Eax
, 0, 0 );
2203 /***********************************************************************
2204 * signal_start_thread
2206 __ASM_GLOBAL_FUNC( signal_start_thread
,
2208 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
2209 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2210 "movl %esp,%ebp\n\t"
2211 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
2213 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
2215 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
2217 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
2218 /* store exit frame */
2219 "movl %ebp,%fs:0x1f4\n\t" /* x86_thread_data()->exit_frame */
2220 /* switch to thread stack */
2221 "movl %fs:4,%eax\n\t" /* NtCurrentTeb()->StackBase */
2222 "leal -0x1000(%eax),%esp\n\t"
2224 "pushl 20(%ebp)\n\t" /* relay */
2225 "pushl 16(%ebp)\n\t" /* suspend */
2226 "pushl 12(%ebp)\n\t" /* arg */
2227 "pushl 8(%ebp)\n\t" /* entry */
2228 "xorl %ebp,%ebp\n\t"
2229 "call " __ASM_NAME("attach_thread") "\n\t"
2230 "movl %eax,%esi\n\t"
2231 "leal -12(%eax),%esp\n\t"
2232 /* clear the stack */
2233 "andl $~0xfff,%eax\n\t" /* round down to page size */
2234 "movl %eax,(%esp)\n\t"
2235 "call " __ASM_NAME("virtual_clear_thread_stack") "\n\t"
2236 /* switch to the initial context */
2237 "movl $1,4(%esp)\n\t"
2238 "movl %esi,(%esp)\n\t"
2239 "call " __ASM_NAME("NtContinue") )
2242 /***********************************************************************
2243 * signal_exit_thread
2245 __ASM_GLOBAL_FUNC( signal_exit_thread
,
2246 "movl 8(%esp),%ecx\n\t"
2247 /* fetch exit frame */
2248 "movl %fs:0x1f4,%edx\n\t" /* x86_thread_data()->exit_frame */
2249 "testl %edx,%edx\n\t"
2252 /* switch to exit frame stack */
2253 "1:\tmovl 4(%esp),%eax\n\t"
2254 "movl $0,%fs:0x1f4\n\t"
2255 "movl %edx,%ebp\n\t"
2256 __ASM_CFI(".cfi_def_cfa %ebp,4\n\t")
2257 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
2258 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
2259 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
2260 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
2261 "leal -20(%ebp),%esp\n\t"
2265 /**********************************************************************
2266 * NtCurrentTeb (NTDLL.@)
2268 __ASM_STDCALL_FUNC( NtCurrentTeb
, 0, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" )
2270 #endif /* __i386__ */