signal_i386.c 48.9 KB
Newer Older
1 2
/*
 * i386 signal handling routines
3
 *
4
 * Copyright 1999 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23
 */

#ifdef __i386__

#include "config.h"
24
#include "wine/port.h"
25 26 27 28

#include <errno.h>
#include <signal.h>
#include <stdlib.h>
29
#include <stdarg.h>
30
#include <stdio.h>
31
#include <sys/types.h>
32 33 34
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
35 36 37 38 39 40 41 42 43 44 45 46

#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
#  include <sys/syscall.h>
# endif
#endif

47 48 49 50
#ifdef HAVE_SYS_VM86_H
# include <sys/vm86.h>
#endif

51 52 53
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
54 55 56
#ifdef HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
57

58
#include "windef.h"
59
#include "thread.h"
60
#include "wine/library.h"
61
#include "ntdll_misc.h"
62

63 64 65 66
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif

67 68 69 70 71 72
/***********************************************************************
 * signal context platform-specific definitions
 */

#ifdef linux

73
typedef ucontext_t SIGCONTEXT;
74

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
#define EAX_sig(context)     ((context)->uc_mcontext.gregs[REG_EAX])
#define EBX_sig(context)     ((context)->uc_mcontext.gregs[REG_EBX])
#define ECX_sig(context)     ((context)->uc_mcontext.gregs[REG_ECX])
#define EDX_sig(context)     ((context)->uc_mcontext.gregs[REG_EDX])
#define ESI_sig(context)     ((context)->uc_mcontext.gregs[REG_ESI])
#define EDI_sig(context)     ((context)->uc_mcontext.gregs[REG_EDI])
#define EBP_sig(context)     ((context)->uc_mcontext.gregs[REG_EBP])
#define ESP_sig(context)     ((context)->uc_mcontext.gregs[REG_ESP])

#define CS_sig(context)      ((context)->uc_mcontext.gregs[REG_CS])
#define DS_sig(context)      ((context)->uc_mcontext.gregs[REG_DS])
#define ES_sig(context)      ((context)->uc_mcontext.gregs[REG_ES])
#define SS_sig(context)      ((context)->uc_mcontext.gregs[REG_SS])
#define FS_sig(context)      ((context)->uc_mcontext.gregs[REG_FS])
#define GS_sig(context)      ((context)->uc_mcontext.gregs[REG_GS])

#define EFL_sig(context)     ((context)->uc_mcontext.gregs[REG_EFL])
#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])

#define FPU_sig(context)     ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs))
97

98 99 100 101 102
#define VM86_EAX 0 /* the %eax value while vm86_enter is executing */

int vm86_enter( void **vm86_ptr );
void vm86_return(void);
void vm86_return_end(void);
103 104 105 106
__ASM_GLOBAL_FUNC(vm86_enter,
                  "pushl %ebp\n\t"
                  "movl %esp, %ebp\n\t"
                  "movl $166,%eax\n\t"  /*SYS_vm86*/
107 108
                  "movl 8(%ebp),%ecx\n\t" /* vm86_ptr */
                  "movl (%ecx),%ecx\n\t"
109 110 111
                  "pushl %ebx\n\t"
                  "movl $1,%ebx\n\t"    /*VM86_ENTER*/
                  "pushl %ecx\n\t"      /* put vm86plus_struct ptr somewhere we can find it */
112
                  "pushl %fs\n\t"
113
                  "pushl %gs\n\t"
114 115
                  "int $0x80\n"
                  ".globl " __ASM_NAME("vm86_return") "\n\t"
116
                  __ASM_FUNC("vm86_return") "\n"
117
                  __ASM_NAME("vm86_return") ":\n\t"
118
                  "popl %gs\n\t"
119
                  "popl %fs\n\t"
120 121 122
                  "popl %ecx\n\t"
                  "popl %ebx\n\t"
                  "popl %ebp\n\t"
123 124 125 126 127 128 129 130
                  "testl %eax,%eax\n\t"
                  "jl 0f\n\t"
                  "cmpb $0,%al\n\t" /* VM86_SIGNAL */
                  "je " __ASM_NAME("vm86_enter") "\n\t"
                  "0:\n\t"
                  "movl 4(%esp),%ecx\n\t"  /* vm86_ptr */
                  "movl $0,(%ecx)\n\t"
                  ".globl " __ASM_NAME("vm86_return_end") "\n\t"
131
                  __ASM_FUNC("vm86_return_end") "\n"
132
                  __ASM_NAME("vm86_return_end") ":\n\t"
133
                  "ret" );
134

135 136 137
#ifdef HAVE_SYS_VM86_H
# define __HAVE_VM86
#endif
138

139 140 141 142
#endif  /* linux */

#ifdef BSDI

143 144 145
#include <machine/frame.h>
typedef struct trapframe SIGCONTEXT;

146 147 148 149 150 151 152
#define EAX_sig(context)     ((context)->tf_eax)
#define EBX_sig(context)     ((context)->tf_ebx)
#define ECX_sig(context)     ((context)->tf_ecx)
#define EDX_sig(context)     ((context)->tf_edx)
#define ESI_sig(context)     ((context)->tf_esi)
#define EDI_sig(context)     ((context)->tf_edi)
#define EBP_sig(context)     ((context)->tf_ebp)
153

154 155 156 157 158 159 160 161 162 163 164 165
#define CS_sig(context)      ((context)->tf_cs)
#define DS_sig(context)      ((context)->tf_ds)
#define ES_sig(context)      ((context)->tf_es)
#define SS_sig(context)      ((context)->tf_ss)

#define EFL_sig(context)     ((context)->tf_eflags)

#define EIP_sig(context)     (*((unsigned long*)&(context)->tf_eip))
#define ESP_sig(context)     (*((unsigned long*)&(context)->tf_esp))

#endif /* bsdi */

166
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
167 168 169

typedef struct sigcontext SIGCONTEXT;

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
#define EAX_sig(context)     ((context)->sc_eax)
#define EBX_sig(context)     ((context)->sc_ebx)
#define ECX_sig(context)     ((context)->sc_ecx)
#define EDX_sig(context)     ((context)->sc_edx)
#define ESI_sig(context)     ((context)->sc_esi)
#define EDI_sig(context)     ((context)->sc_edi)
#define EBP_sig(context)     ((context)->sc_ebp)

#define CS_sig(context)      ((context)->sc_cs)
#define DS_sig(context)      ((context)->sc_ds)
#define ES_sig(context)      ((context)->sc_es)
#define FS_sig(context)      ((context)->sc_fs)
#define GS_sig(context)      ((context)->sc_gs)
#define SS_sig(context)      ((context)->sc_ss)

#define TRAP_sig(context)    ((context)->sc_trapno)
#define ERROR_sig(context)   ((context)->sc_err)
#define EFL_sig(context)     ((context)->sc_eflags)

#define EIP_sig(context)     ((context)->sc_eip)
#define ESP_sig(context)     ((context)->sc_esp)

192
#endif  /* *BSD */
193 194 195 196 197 198 199 200 201 202 203 204

#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)

#ifdef _SCO_DS
#include <sys/regset.h>
#endif
/* Solaris kludge */
#undef ERR
#include <sys/ucontext.h>
#undef ERR
typedef struct ucontext SIGCONTEXT;

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
#ifdef _SCO_DS
#define gregs regs
#endif

#define EAX_sig(context)     ((context)->uc_mcontext.gregs[EAX])
#define EBX_sig(context)     ((context)->uc_mcontext.gregs[EBX])
#define ECX_sig(context)     ((context)->uc_mcontext.gregs[ECX])
#define EDX_sig(context)     ((context)->uc_mcontext.gregs[EDX])
#define ESI_sig(context)     ((context)->uc_mcontext.gregs[ESI])
#define EDI_sig(context)     ((context)->uc_mcontext.gregs[EDI])
#define EBP_sig(context)     ((context)->uc_mcontext.gregs[EBP])

#define CS_sig(context)      ((context)->uc_mcontext.gregs[CS])
#define DS_sig(context)      ((context)->uc_mcontext.gregs[DS])
#define ES_sig(context)      ((context)->uc_mcontext.gregs[ES])
#define SS_sig(context)      ((context)->uc_mcontext.gregs[SS])

#define FS_sig(context)      ((context)->uc_mcontext.gregs[FS])
#define GS_sig(context)      ((context)->uc_mcontext.gregs[GS])

#define EFL_sig(context)     ((context)->uc_mcontext.gregs[EFL])

#define EIP_sig(context)     ((context)->uc_mcontext.gregs[EIP])
#ifdef UESP
#define ESP_sig(context)     ((context)->uc_mcontext.gregs[UESP])
#elif defined(R_ESP)
#define ESP_sig(context)     ((context)->uc_mcontext.gregs[R_ESP])
#else
#define ESP_sig(context)     ((context)->uc_mcontext.gregs[ESP])
#endif
#ifdef TRAPNO
#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[TRAPNO])
#endif

239 240
#endif  /* svr4 || SCO_DS */

241 242 243
#ifdef __APPLE__
# include <sys/ucontext.h>

244
typedef ucontext_t SIGCONTEXT;
245

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
#define EAX_sig(context)     ((context)->uc_mcontext->ss.eax)
#define EBX_sig(context)     ((context)->uc_mcontext->ss.ebx)
#define ECX_sig(context)     ((context)->uc_mcontext->ss.ecx)
#define EDX_sig(context)     ((context)->uc_mcontext->ss.edx)
#define ESI_sig(context)     ((context)->uc_mcontext->ss.esi)
#define EDI_sig(context)     ((context)->uc_mcontext->ss.edi)
#define EBP_sig(context)     ((context)->uc_mcontext->ss.ebp)

#define CS_sig(context)      ((context)->uc_mcontext->ss.cs)
#define DS_sig(context)      ((context)->uc_mcontext->ss.ds)
#define ES_sig(context)      ((context)->uc_mcontext->ss.es)
#define FS_sig(context)      ((context)->uc_mcontext->ss.fs)
#define GS_sig(context)      ((context)->uc_mcontext->ss.gs)
#define SS_sig(context)      ((context)->uc_mcontext->ss.ss)

#define EFL_sig(context)     ((context)->uc_mcontext->ss.eflags)

#define EIP_sig(context)     (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
#define ESP_sig(context)     (*((unsigned long*)&(context)->uc_mcontext->ss.esp))
265

266 267 268
#define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
#define ERROR_sig(context)   ((context)->uc_mcontext->es.err)

269 270
#endif /* __APPLE__ */

271
#include "wine/exception.h"
272
#include "wine/debug.h"
Patrik Stridvall's avatar
Patrik Stridvall committed
273

274
WINE_DEFAULT_DEBUG_CHANNEL(seh);
Patrik Stridvall's avatar
Patrik Stridvall committed
275

276
typedef int (*wine_signal_handler)(unsigned int sig);
277

278 279 280
static size_t signal_stack_mask;
static size_t signal_stack_size;

281 282
static wine_signal_handler handlers[256];

283
extern void DECLSPEC_NORETURN __wine_call_from_32_restore_regs( const CONTEXT *context );
284

285 286 287
enum i386_trap_code
{
    TRAP_x86_UNKNOWN    = -1,  /* Unknown fault (TRAP_sig not defined) */
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
    TRAP_x86_DIVIDE     = T_DIVIDE,     /* Division by zero exception */
    TRAP_x86_TRCTRAP    = T_TRCTRAP,    /* Single-step exception */
    TRAP_x86_NMI        = T_NMI,        /* NMI interrupt */
    TRAP_x86_BPTFLT     = T_BPTFLT,     /* Breakpoint exception */
    TRAP_x86_OFLOW      = T_OFLOW,      /* Overflow exception */
    TRAP_x86_BOUND      = T_BOUND,      /* Bound range exception */
    TRAP_x86_PRIVINFLT  = T_PRIVINFLT,  /* Invalid opcode exception */
    TRAP_x86_DNA        = T_DNA,        /* Device not available exception */
    TRAP_x86_DOUBLEFLT  = T_DOUBLEFLT,  /* Double fault exception */
    TRAP_x86_FPOPFLT    = T_FPOPFLT,    /* Coprocessor segment overrun */
    TRAP_x86_TSSFLT     = T_TSSFLT,     /* Invalid TSS exception */
    TRAP_x86_SEGNPFLT   = T_SEGNPFLT,   /* Segment not present exception */
    TRAP_x86_STKFLT     = T_STKFLT,     /* Stack fault */
    TRAP_x86_PROTFLT    = T_PROTFLT,    /* General protection fault */
    TRAP_x86_PAGEFLT    = T_PAGEFLT,    /* Page fault */
    TRAP_x86_ARITHTRAP  = T_ARITHTRAP,  /* Floating point exception */
    TRAP_x86_ALIGNFLT   = T_ALIGNFLT,   /* Alignment check exception */
    TRAP_x86_MCHK       = T_MCHK,       /* Machine check exception */
    TRAP_x86_CACHEFLT   = T_XMMFLT      /* Cache flush exception */
#else
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    TRAP_x86_DIVIDE     = 0,   /* Division by zero exception */
    TRAP_x86_TRCTRAP    = 1,   /* Single-step exception */
    TRAP_x86_NMI        = 2,   /* NMI interrupt */
    TRAP_x86_BPTFLT     = 3,   /* Breakpoint exception */
    TRAP_x86_OFLOW      = 4,   /* Overflow exception */
    TRAP_x86_BOUND      = 5,   /* Bound range exception */
    TRAP_x86_PRIVINFLT  = 6,   /* Invalid opcode exception */
    TRAP_x86_DNA        = 7,   /* Device not available exception */
    TRAP_x86_DOUBLEFLT  = 8,   /* Double fault exception */
    TRAP_x86_FPOPFLT    = 9,   /* Coprocessor segment overrun */
    TRAP_x86_TSSFLT     = 10,  /* Invalid TSS exception */
    TRAP_x86_SEGNPFLT   = 11,  /* Segment not present exception */
    TRAP_x86_STKFLT     = 12,  /* Stack fault */
    TRAP_x86_PROTFLT    = 13,  /* General protection fault */
    TRAP_x86_PAGEFLT    = 14,  /* Page fault */
    TRAP_x86_ARITHTRAP  = 16,  /* Floating point exception */
    TRAP_x86_ALIGNFLT   = 17,  /* Alignment check exception */
    TRAP_x86_MCHK       = 18,  /* Machine check exception */
    TRAP_x86_CACHEFLT   = 19   /* Cache flush exception */
328
#endif
329 330
};

331

332 333 334
/***********************************************************************
 *           dispatch_signal
 */
335
inline static int dispatch_signal(unsigned int sig)
336 337 338 339 340 341
{
    if (handlers[sig] == NULL) return 0;
    return handlers[sig](sig);
}


342 343 344 345 346
/***********************************************************************
 *           get_trap_code
 *
 * Get the trap code for a signal.
 */
347
static inline enum i386_trap_code get_trap_code( const SIGCONTEXT *sigcontext )
348 349 350 351
{
#ifdef TRAP_sig
    return TRAP_sig(sigcontext);
#else
352
    return TRAP_x86_UNKNOWN;  /* unknown trap code */
353 354
#endif
}
355

356 357 358 359 360
/***********************************************************************
 *           get_error_code
 *
 * Get the error code for a signal.
 */
361
static inline WORD get_error_code( const SIGCONTEXT *sigcontext )
362 363 364 365 366 367 368 369
{
#ifdef ERROR_sig
    return ERROR_sig(sigcontext);
#else
    return 0;
#endif
}

370 371 372 373 374 375 376
/***********************************************************************
 *           get_signal_stack
 *
 * Get the base of the signal stack for the current thread.
 */
static inline void *get_signal_stack(void)
{
377
    return (char *)NtCurrentTeb() + 4096;
378 379 380
}


381 382 383 384 385 386 387 388 389
/***********************************************************************
 *           get_current_teb
 *
 * Get the current teb based on the stack pointer.
 */
static inline TEB *get_current_teb(void)
{
    unsigned long esp;
    __asm__("movl %%esp,%0" : "=g" (esp) );
390
    return (TEB *)(esp & ~signal_stack_mask);
391 392 393
}


394
#ifdef __HAVE_VM86
395 396 397 398 399 400 401
/***********************************************************************
 *           save_vm86_context
 *
 * Set the register values from a vm86 structure.
 */
static void save_vm86_context( CONTEXT *context, const struct vm86plus_struct *vm86 )
{
402
    context->ContextFlags = CONTEXT_FULL;
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
    context->Eax    = vm86->regs.eax;
    context->Ebx    = vm86->regs.ebx;
    context->Ecx    = vm86->regs.ecx;
    context->Edx    = vm86->regs.edx;
    context->Esi    = vm86->regs.esi;
    context->Edi    = vm86->regs.edi;
    context->Esp    = vm86->regs.esp;
    context->Ebp    = vm86->regs.ebp;
    context->Eip    = vm86->regs.eip;
    context->SegCs  = vm86->regs.cs;
    context->SegDs  = vm86->regs.ds;
    context->SegEs  = vm86->regs.es;
    context->SegFs  = vm86->regs.fs;
    context->SegGs  = vm86->regs.gs;
    context->SegSs  = vm86->regs.ss;
    context->EFlags = vm86->regs.eflags;
}


/***********************************************************************
 *           restore_vm86_context
 *
 * Build a vm86 structure from the register values.
 */
static void restore_vm86_context( const CONTEXT *context, struct vm86plus_struct *vm86 )
{
    vm86->regs.eax    = context->Eax;
    vm86->regs.ebx    = context->Ebx;
    vm86->regs.ecx    = context->Ecx;
    vm86->regs.edx    = context->Edx;
    vm86->regs.esi    = context->Esi;
    vm86->regs.edi    = context->Edi;
    vm86->regs.esp    = context->Esp;
    vm86->regs.ebp    = context->Ebp;
    vm86->regs.eip    = context->Eip;
    vm86->regs.cs     = context->SegCs;
    vm86->regs.ds     = context->SegDs;
    vm86->regs.es     = context->SegEs;
    vm86->regs.fs     = context->SegFs;
    vm86->regs.gs     = context->SegGs;
    vm86->regs.ss     = context->SegSs;
    vm86->regs.eflags = context->EFlags;
}
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464


/**********************************************************************
 *		merge_vm86_pending_flags
 *
 * Merges TEB.vm86_ptr and TEB.vm86_pending VIP flags and
 * raises exception if there are pending events and VIF flag
 * has been turned on.
 *
 * Called from __wine_enter_vm86 because vm86_enter
 * doesn't check for pending events. 
 *
 * Called from raise_vm86_sti_exception to check for
 * pending events in a signal safe way.
 */
static void merge_vm86_pending_flags( EXCEPTION_RECORD *rec )
{
    BOOL check_pending = TRUE;
    struct vm86plus_struct *vm86 =
465
        (struct vm86plus_struct*)(ntdll_get_thread_data()->vm86_ptr);
466 467 468 469 470 471 472 473 474

    /*
     * In order to prevent a race when SIGUSR2 occurs while
     * we are returning from exception handler, pending events
     * will be rechecked after each raised exception.
     */
    while (check_pending && NtCurrentTeb()->vm86_pending)
    {
        check_pending = FALSE;
475
        ntdll_get_thread_data()->vm86_ptr = NULL;
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
            
        /*
         * If VIF is set, throw exception.
         * Note that SIGUSR2 may turn VIF flag off so
         * VIF check must occur only when TEB.vm86_ptr is NULL.
         */
        if (vm86->regs.eflags & VIF_MASK)
        {
            CONTEXT vcontext;
            save_vm86_context( &vcontext, vm86 );
            
            rec->ExceptionCode    = EXCEPTION_VM86_STI;
            rec->ExceptionFlags   = EXCEPTION_CONTINUABLE;
            rec->ExceptionRecord  = NULL;
            rec->NumberParameters = 0;
            rec->ExceptionAddress = (LPVOID)vcontext.Eip;

            vcontext.EFlags &= ~VIP_MASK;
            NtCurrentTeb()->vm86_pending = 0;
495
            __regs_RtlRaiseException( rec, &vcontext );
496 497 498 499 500

            restore_vm86_context( &vcontext, vm86 );
            check_pending = TRUE;
        }

501
        ntdll_get_thread_data()->vm86_ptr = vm86;
502 503 504 505 506 507 508 509 510
    }

    /*
     * Merge VIP flags in a signal safe way. This requires
     * that the following operation compiles into atomic
     * instruction.
     */
    vm86->regs.eflags |= NtCurrentTeb()->vm86_pending;
}
511
#endif /* __HAVE_VM86 */
512 513


514 515
typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );

516

517 518 519 520 521
/***********************************************************************
 *           init_handler
 *
 * Handler initialization when the full context is not needed.
 */
522
inline static void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD *gs )
523
{
524
    void *stack = (void *)(ESP_sig(sigcontext) & ~3);
525
    TEB *teb = get_current_teb();
526
    struct ntdll_thread_regs *thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1;
527

528 529 530 531 532 533 534 535 536 537 538 539
    /* get %fs and %gs at time of the fault */
#ifdef FS_sig
    *fs = LOWORD(FS_sig(sigcontext));
#else
    *fs = wine_get_fs();
#endif
#ifdef GS_sig
    *gs = LOWORD(GS_sig(sigcontext));
#else
    *gs = wine_get_gs();
#endif

540
    wine_set_fs( thread_regs->fs );
541 542

    /* now restore a proper %gs for the fault handler */
543 544
    if (!wine_ldt_is_system(CS_sig(sigcontext)) ||
        !wine_ldt_is_system(SS_sig(sigcontext)))  /* 16-bit mode */
545
    {
546 547 548 549 550 551 552
        /*
         * Win16 or DOS protected mode. Note that during switch
         * from 16-bit mode to linear mode, CS may be set to system
         * segment before FS is restored. Fortunately, in this case
         * SS is still non-system segment. This is why both CS and SS
         * are checked.
         */
553
        wine_set_gs( thread_regs->gs );
554
        stack = teb->WOW32Reserved;
555 556 557 558
    }
#ifdef __HAVE_VM86
    else if ((void *)EIP_sig(sigcontext) == vm86_return)  /* vm86 mode */
    {
559
        unsigned int *int_stack = stack;
560
        /* fetch the saved %gs from the stack */
561 562 563 564
        wine_set_gs( int_stack[0] );
    }
#endif
    else  /* 32-bit mode */
565
    {
566 567 568
#ifdef GS_sig
        wine_set_gs( GS_sig(sigcontext) );
#endif
569
    }
570
    return stack;
571 572 573
}


574 575 576 577 578 579 580 581 582 583 584 585 586 587
/***********************************************************************
 *           save_fpu
 *
 * Save the thread FPU context.
 */
inline static void save_fpu( CONTEXT *context )
{
#ifdef __GNUC__
    context->ContextFlags |= CONTEXT_FLOATING_POINT;
    __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
#endif
}


588 589 590
/***********************************************************************
 *           restore_fpu
 *
591
 * Restore the FPU context to a sigcontext.
592
 */
593
inline static void restore_fpu( const CONTEXT *context )
594
{
595
    FLOATING_SAVE_AREA float_status = context->FloatSave;
596
    /* reset the current interrupt status */
597
    float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
598
#ifdef __GNUC__
599
    __asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) );
600 601 602 603
#endif  /* __GNUC__ */
}


604 605 606 607 608 609 610
/***********************************************************************
 *           save_context
 *
 * Build a context structure from the signal info.
 */
inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
{
611 612
    struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();

613
    memset(context, 0, sizeof(*context));
614
    context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
    context->Eax          = EAX_sig(sigcontext);
    context->Ebx          = EBX_sig(sigcontext);
    context->Ecx          = ECX_sig(sigcontext);
    context->Edx          = EDX_sig(sigcontext);
    context->Esi          = ESI_sig(sigcontext);
    context->Edi          = EDI_sig(sigcontext);
    context->Ebp          = EBP_sig(sigcontext);
    context->EFlags       = EFL_sig(sigcontext);
    context->Eip          = EIP_sig(sigcontext);
    context->Esp          = ESP_sig(sigcontext);
    context->SegCs        = LOWORD(CS_sig(sigcontext));
    context->SegDs        = LOWORD(DS_sig(sigcontext));
    context->SegEs        = LOWORD(ES_sig(sigcontext));
    context->SegFs        = fs;
    context->SegGs        = gs;
    context->SegSs        = LOWORD(SS_sig(sigcontext));
631 632 633 634 635 636
    context->Dr0          = regs->dr0;
    context->Dr1          = regs->dr1;
    context->Dr2          = regs->dr2;
    context->Dr3          = regs->dr3;
    context->Dr6          = regs->dr6;
    context->Dr7          = regs->dr7;
637 638 639 640 641 642 643 644 645 646

#ifdef FPU_sig
    if (FPU_sig(sigcontext))
    {
        context->ContextFlags |= CONTEXT_FLOATING_POINT;
        context->FloatSave = *FPU_sig(sigcontext);
    }
    else
#endif
    {
647
        save_fpu( context );
648
    }
649 650 651 652 653 654 655 656 657 658
}


/***********************************************************************
 *           restore_context
 *
 * Restore the signal info from the context.
 */
inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
{
659 660 661 662 663 664 665 666
    struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();

    regs->dr0 = context->Dr0;
    regs->dr1 = context->Dr1;
    regs->dr2 = context->Dr2;
    regs->dr3 = context->Dr3;
    regs->dr6 = context->Dr6;
    regs->dr7 = context->Dr7;
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
    EAX_sig(sigcontext) = context->Eax;
    EBX_sig(sigcontext) = context->Ebx;
    ECX_sig(sigcontext) = context->Ecx;
    EDX_sig(sigcontext) = context->Edx;
    ESI_sig(sigcontext) = context->Esi;
    EDI_sig(sigcontext) = context->Edi;
    EBP_sig(sigcontext) = context->Ebp;
    EFL_sig(sigcontext) = context->EFlags;
    EIP_sig(sigcontext) = context->Eip;
    ESP_sig(sigcontext) = context->Esp;
    CS_sig(sigcontext)  = context->SegCs;
    DS_sig(sigcontext)  = context->SegDs;
    ES_sig(sigcontext)  = context->SegEs;
    SS_sig(sigcontext)  = context->SegSs;
#ifdef GS_sig
    GS_sig(sigcontext)  = context->SegGs;
#else
    wine_set_gs( context->SegGs );
#endif
#ifdef FS_sig
    FS_sig(sigcontext)  = context->SegFs;
#else
    wine_set_fs( context->SegFs );
#endif
691 692 693 694 695 696 697 698 699 700 701

#ifdef FPU_sig
    if (FPU_sig(sigcontext))
    {
        *FPU_sig(sigcontext) = context->FloatSave;
    }
    else
#endif
    {
        restore_fpu( context );
    }
702 703 704
}


705 706 707 708 709 710 711 712 713 714 715 716 717
/***********************************************************************
 *              get_cpu_context
 *
 * Register function to get the context of the current thread.
 */
void WINAPI __regs_get_cpu_context( CONTEXT *context, CONTEXT *regs )
{
    *context = *regs;
    save_fpu( context );
}
DEFINE_REGS_ENTRYPOINT( get_cpu_context, 4, 4 );


718 719 720
/***********************************************************************
 *           set_cpu_context
 *
721
 * Set the new CPU context. Used by NtSetContextThread.
722
 */
723
void set_cpu_context( const CONTEXT *context )
724 725 726 727
{
    DWORD flags = context->ContextFlags & ~CONTEXT_i386;

    if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
728

729 730 731 732 733 734 735 736 737 738
    if (flags & CONTEXT_DEBUG_REGISTERS)
    {
        struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
        regs->dr0 = context->Dr0;
        regs->dr1 = context->Dr1;
        regs->dr2 = context->Dr2;
        regs->dr3 = context->Dr3;
        regs->dr6 = context->Dr6;
        regs->dr7 = context->Dr7;
    }
739 740 741
    if (flags & CONTEXT_FULL)
    {
        if ((flags & CONTEXT_FULL) != (CONTEXT_FULL & ~CONTEXT_i386))
742
            FIXME( "setting partial context (%x) not supported\n", flags );
743 744 745
        else
            __wine_call_from_32_restore_regs( context );
    }
746 747 748
}


749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
/***********************************************************************
 *           is_privileged_instr
 *
 * Check if the fault location is a privileged instruction.
 * Based on the instruction emulation code in dlls/kernel/instr.c.
 */
static inline int is_privileged_instr( CONTEXT86 *context )
{
    const BYTE *instr;
    unsigned int prefix_count = 0;

    if (!wine_ldt_is_system( context->SegCs )) return 0;
    instr = (BYTE *)context->Eip;

    for (;;) switch(*instr)
    {
    /* instruction prefixes */
    case 0x2e:  /* %cs: */
    case 0x36:  /* %ss: */
    case 0x3e:  /* %ds: */
    case 0x26:  /* %es: */
    case 0x64:  /* %fs: */
    case 0x65:  /* %gs: */
    case 0x66:  /* opcode size */
    case 0x67:  /* addr size */
    case 0xf0:  /* lock */
    case 0xf2:  /* repne */
    case 0xf3:  /* repe */
        if (++prefix_count >= 15) return 0;
        instr++;
        continue;

    case 0x0f: /* extended instruction */
        switch(instr[1])
        {
        case 0x20: /* mov crX, reg */
        case 0x21: /* mov drX, reg */
        case 0x22: /* mov reg, crX */
        case 0x23: /* mov reg drX */
            return 1;
        }
        return 0;
    case 0x6c: /* insb (%dx) */
    case 0x6d: /* insl (%dx) */
    case 0x6e: /* outsb (%dx) */
    case 0x6f: /* outsl (%dx) */
    case 0xcd: /* int $xx */
    case 0xe4: /* inb al,XX */
    case 0xe5: /* in (e)ax,XX */
    case 0xe6: /* outb XX,al */
    case 0xe7: /* out XX,(e)ax */
    case 0xec: /* inb (%dx),%al */
    case 0xed: /* inl (%dx),%eax */
    case 0xee: /* outb %al,(%dx) */
    case 0xef: /* outl %eax,(%dx) */
    case 0xf4: /* hlt */
    case 0xfa: /* cli */
    case 0xfb: /* sti */
        return 1;
    default:
        return 0;
    }
}


814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
#include "pshpack1.h"
struct atl_thunk
{
    DWORD movl;  /* movl this,4(%esp) */
    DWORD this;
    BYTE  jmp;   /* jmp func */
    int   func;
};
#include "poppack.h"

/**********************************************************************
 *		check_atl_thunk
 *
 * Check if code destination is an ATL thunk, and emulate it if so.
 */
static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
{
831 832 833 834 835 836 837 838 839
    const struct atl_thunk *thunk = (const struct atl_thunk *)rec->ExceptionInformation[1];
    BOOL ret = FALSE;

    __TRY
    {
        if (thunk->movl == 0x042444c7 && thunk->jmp == 0xe9)
        {
            *((DWORD *)context->Esp + 1) = thunk->this;
            context->Eip = (DWORD_PTR)(&thunk->func + 1) + thunk->func;
840
            TRACE( "emulating ATL thunk at %p, func=%08x arg=%08x\n",
841 842 843 844 845 846 847 848 849 850
                   thunk, context->Eip, *((DWORD *)context->Esp + 1) );
            ret = TRUE;
        }
    }
    __EXCEPT_PAGE_FAULT
    {
        return FALSE;
    }
    __ENDTRY
    return ret;
851 852 853
}


854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
/***********************************************************************
 *           setup_exception
 *
 * Setup a proper stack frame for the raise function, and modify the
 * sigcontext so that the return from the signal handler will call
 * the raise function.
 */
static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
{
    struct stack_layout
    {
        void             *ret_addr;      /* return address from raise_func */
        EXCEPTION_RECORD *rec_ptr;       /* first arg for raise_func */
        CONTEXT          *context_ptr;   /* second arg for raise_func */
        CONTEXT           context;
        EXCEPTION_RECORD  rec;
        DWORD             ebp;
        DWORD             eip;
    } *stack;

    WORD fs, gs;

876
    stack = init_handler( sigcontext, &fs, &gs );
877 878 879

    /* stack sanity checks */

880
    if ((char *)stack >= (char *)get_signal_stack() &&
881
        (char *)stack < (char *)get_signal_stack() + signal_stack_size)
882
    {
883
        ERR( "nested exception on signal stack in thread %04x eip %08x esp %08x stack %p-%p\n",
884 885 886
             GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
             (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
             NtCurrentTeb()->Tib.StackBase );
887
        server_abort_thread(1);
888 889
    }

890
    if (stack - 1 > stack || /* check for overflow in subtraction */
891
        (char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit ||
892 893
        (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
    {
894
        UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)stack;
895
        if (diff < 4096)
896
        {
897
            ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p\n",
898 899 900
                 diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
                 (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
                 NtCurrentTeb()->Tib.StackBase );
901
            server_abort_thread(1);
902
        }
903
        else WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n",
904 905 906
                   GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
                   (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
                   NtCurrentTeb()->Tib.StackBase );
907 908 909
    }

    stack--;  /* push the stack_layout structure */
910 911 912
#ifdef HAVE_VALGRIND_MEMCHECK_H
    VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
#endif
913
    stack->ret_addr     = (void *)0xdeadbabe;  /* raise_func must not return */
914 915 916 917 918 919 920 921
    stack->rec_ptr      = &stack->rec;
    stack->context_ptr  = &stack->context;

    stack->rec.ExceptionRecord  = NULL;
    stack->rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
    stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
    stack->rec.NumberParameters = 0;

922
    save_context( &stack->context, sigcontext, fs, gs );
923 924 925 926

    /* now modify the sigcontext to return to the raise function */
    ESP_sig(sigcontext) = (DWORD)stack;
    EIP_sig(sigcontext) = (DWORD)func;
927 928
    /* clear single-step and align check flag */
    EFL_sig(sigcontext) &= ~(0x100|0x40000); 
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
    CS_sig(sigcontext)  = wine_get_cs();
    DS_sig(sigcontext)  = wine_get_ds();
    ES_sig(sigcontext)  = wine_get_es();
    FS_sig(sigcontext)  = wine_get_fs();
    GS_sig(sigcontext)  = wine_get_gs();
    SS_sig(sigcontext)  = wine_get_ss();

    return stack->rec_ptr;
}


/***********************************************************************
 *           get_exception_context
 *
 * Get a pointer to the context built by setup_exception.
 */
static inline CONTEXT *get_exception_context( EXCEPTION_RECORD *rec )
{
    return (CONTEXT *)rec - 1;  /* cf. stack_layout structure */
}


951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
/**********************************************************************
 *		get_fpu_code
 *
 * Get the FPU exception code from the FPU status.
 */
static inline DWORD get_fpu_code( const CONTEXT *context )
{
    DWORD status = context->FloatSave.StatusWord;

    if (status & 0x01)  /* IE */
    {
        if (status & 0x40)  /* SF */
            return EXCEPTION_FLT_STACK_CHECK;
        else
            return EXCEPTION_FLT_INVALID_OPERATION;
    }
    if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND;  /* DE flag */
    if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO;    /* ZE flag */
    if (status & 0x08) return EXCEPTION_FLT_OVERFLOW;          /* OE flag */
    if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW;         /* UE flag */
    if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT;    /* PE flag */
    return EXCEPTION_FLT_INVALID_OPERATION;  /* generic error */
}


/**********************************************************************
977
 *		raise_segv_exception
978
 */
979
static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
980
{
981
    switch(rec->ExceptionCode)
982
    {
983 984
    case EXCEPTION_ACCESS_VIOLATION:
        if (rec->NumberParameters == 2)
985
        {
986 987
            if (rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT && check_atl_thunk( rec, context ))
                goto done;
988
            rec->ExceptionCode = VIRTUAL_HandleFault( (void *)rec->ExceptionInformation[1] );
989
        }
990
        break;
991
    case EXCEPTION_DATATYPE_MISALIGNMENT:
992
        /* FIXME: pass through exception handler first? */
993
        if (context->EFlags & 0x00040000)
994 995
        {
            /* Disable AC flag, return */
996
            context->EFlags &= ~0x00040000;
997
            goto done;
998
        }
999 1000
        break;
    }
1001
    __regs_RtlRaiseException( rec, context );
1002
done:
1003
    NtSetContextThread( GetCurrentThread(), context );
1004 1005 1006 1007
}


/**********************************************************************
1008
 *		raise_trap_exception
1009
 */
1010
static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1011
{
1012
    if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
1013
    {
1014 1015 1016 1017
        if (context->EFlags & 0x100)
        {
            context->EFlags &= ~0x100;  /* clear single-step flag */
        }
1018
        else  /* hardware breakpoint, fetch the debug registers */
1019
        {
1020
            context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
1021
            NtGetContextThread(GetCurrentThread(), context);
1022 1023 1024 1025
            /* do we really have a bp from a debug register ?
             * if not, then someone did a kill(SIGTRAP) on us, and we
             * shall return a breakpoint, not a single step exception
             */
1026
            if (!(context->Dr6 & 0xf)) rec->ExceptionCode = EXCEPTION_BREAKPOINT;
1027
            context->ContextFlags |= CONTEXT_FULL;  /* restore flags */
1028
        }
1029
    }
1030

1031
    __regs_RtlRaiseException( rec, context );
1032
    NtSetContextThread( GetCurrentThread(), context );
1033 1034 1035 1036
}


/**********************************************************************
1037 1038 1039
 *		raise_exception
 *
 * Generic raise function for exceptions that don't need special treatment.
1040
 */
1041
static void WINAPI raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1042
{
1043
    __regs_RtlRaiseException( rec, context );
1044
    NtSetContextThread( GetCurrentThread(), context );
1045 1046 1047
}


1048
#ifdef __HAVE_VM86
1049
/**********************************************************************
1050
 *		raise_vm86_sti_exception
1051
 */
1052
static void WINAPI raise_vm86_sti_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1053
{
1054
    /* merge_vm86_pending_flags merges the vm86_pending flag in safely */
1055 1056
    NtCurrentTeb()->vm86_pending |= VIP_MASK;

1057
    if (ntdll_get_thread_data()->vm86_ptr)
1058
    {
1059 1060 1061 1062
        if (((char*)context->Eip >= (char*)vm86_return) &&
            ((char*)context->Eip <= (char*)vm86_return_end) &&
            (VM86_TYPE(context->Eax) != VM86_SIGNAL)) {
            /* exiting from VM86, can't throw */
1063
            goto done;
1064
        }
1065
        merge_vm86_pending_flags( rec );
1066
    }
1067
    else if (NtCurrentTeb()->dpmi_vif &&
1068 1069
             !wine_ldt_is_system(context->SegCs) &&
             !wine_ldt_is_system(context->SegSs))
1070 1071 1072
    {
        /* Executing DPMI code and virtual interrupts are enabled. */
        NtCurrentTeb()->vm86_pending = 0;
1073
        __regs_RtlRaiseException( rec, context );
1074
    }
1075
done:
1076
    NtSetContextThread( GetCurrentThread(), context );
1077 1078 1079
}


1080 1081 1082 1083 1084 1085 1086 1087
/**********************************************************************
 *		usr2_handler
 *
 * Handler for SIGUSR2.
 * We use it to signal that the running __wine_enter_vm86() should
 * immediately set VIP_MASK, causing pending events to be handled
 * as early as possible.
 */
1088
static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1089
{
1090
    EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_vm86_sti_exception );
1091
    rec->ExceptionCode = EXCEPTION_VM86_STI;
1092
}
1093
#endif /* __HAVE_VM86 */
1094 1095


1096 1097 1098 1099 1100
/**********************************************************************
 *		segv_handler
 *
 * Handler for SIGSEGV and related errors.
 */
1101
static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1102
{
1103 1104
    SIGCONTEXT *context = sigcontext;
    EXCEPTION_RECORD *rec = setup_exception( context, raise_segv_exception );
1105

1106
    switch(get_trap_code(context))
1107
    {
1108
    case TRAP_x86_OFLOW:   /* Overflow exception */
1109 1110
        rec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
        break;
1111
    case TRAP_x86_BOUND:   /* Bound range exception */
1112 1113
        rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
        break;
1114
    case TRAP_x86_PRIVINFLT:   /* Invalid opcode exception */
1115 1116
        rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
        break;
1117
    case TRAP_x86_STKFLT:  /* Stack fault */
1118 1119
        rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
        break;
1120 1121 1122
    case TRAP_x86_SEGNPFLT:  /* Segment not present exception */
    case TRAP_x86_PROTFLT:   /* General protection fault */
    case TRAP_x86_UNKNOWN:   /* Unknown fault code */
1123
        if (!get_error_code(context) && is_privileged_instr( get_exception_context(rec) ))
1124 1125 1126
            rec->ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
        else
        {
1127
            WORD err = get_error_code(context);
1128 1129 1130 1131 1132 1133
            rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
            rec->NumberParameters = 2;
            rec->ExceptionInformation[0] = 0;
            /* if error contains a LDT selector, use that as fault address */
            rec->ExceptionInformation[1] = (err & 7) == 4 ? (err & ~7) : 0xffffffff;
        }
1134
        break;
1135
    case TRAP_x86_PAGEFLT:  /* Page fault */
1136 1137
        rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
        rec->NumberParameters = 2;
1138 1139
        rec->ExceptionInformation[0] = (get_error_code(context) >> 1) & 0x09;
        rec->ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
1140
        break;
1141
    case TRAP_x86_ALIGNFLT:  /* Alignment check exception */
1142 1143 1144
        rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
        break;
    default:
1145
        ERR( "Got unexpected trap %d\n", get_trap_code(context) );
1146
        /* fall through */
1147 1148 1149 1150 1151 1152
    case TRAP_x86_NMI:       /* NMI interrupt */
    case TRAP_x86_DNA:       /* Device not available exception */
    case TRAP_x86_DOUBLEFLT: /* Double fault exception */
    case TRAP_x86_TSSFLT:    /* Invalid TSS exception */
    case TRAP_x86_MCHK:      /* Machine check exception */
    case TRAP_x86_CACHEFLT:  /* Cache flush exception */
1153 1154 1155
        rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
        break;
    }
1156 1157 1158 1159 1160 1161 1162 1163
}


/**********************************************************************
 *		trap_handler
 *
 * Handler for SIGTRAP.
 */
1164
static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1165
{
1166 1167
    SIGCONTEXT *context = sigcontext;
    EXCEPTION_RECORD *rec = setup_exception( context, raise_trap_exception );
1168

1169
    switch(get_trap_code(context))
1170
    {
1171
    case TRAP_x86_TRCTRAP:  /* Single-step exception */
1172 1173
        rec->ExceptionCode = EXCEPTION_SINGLE_STEP;
        break;
1174
    case TRAP_x86_BPTFLT:   /* Breakpoint exception */
1175 1176 1177 1178 1179 1180
        rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1;  /* back up over the int3 instruction */
        /* fall through */
    default:
        rec->ExceptionCode = EXCEPTION_BREAKPOINT;
        break;
    }
1181 1182 1183 1184 1185 1186 1187 1188
}


/**********************************************************************
 *		fpe_handler
 *
 * Handler for SIGFPE.
 */
1189
static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1190
{
1191 1192 1193
    CONTEXT *win_context;
    SIGCONTEXT *context = sigcontext;
    EXCEPTION_RECORD *rec = setup_exception( context, raise_exception );
1194

1195
    win_context = get_exception_context( rec );
1196

1197
    switch(get_trap_code(context))
1198
    {
1199
    case TRAP_x86_DIVIDE:   /* Division by zero exception */
1200 1201
        rec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
        break;
1202
    case TRAP_x86_FPOPFLT:   /* Coprocessor segment overrun */
1203 1204
        rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
        break;
1205 1206
    case TRAP_x86_ARITHTRAP:  /* Floating point exception */
    case TRAP_x86_UNKNOWN:    /* Unknown fault code */
1207
        rec->ExceptionCode = get_fpu_code( win_context );
1208 1209
        break;
    default:
1210
        ERR( "Got unexpected trap %d\n", get_trap_code(context) );
1211 1212 1213
        rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
        break;
    }
1214 1215 1216 1217 1218 1219 1220
}


/**********************************************************************
 *		int_handler
 *
 * Handler for SIGINT.
1221 1222
 *
 * FIXME: should not be calling external functions on the signal stack.
1223
 */
1224
static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1225
{
1226
    WORD fs, gs;
1227
    init_handler( sigcontext, &fs, &gs );
1228
    if (!dispatch_signal(SIGINT))
1229
    {
1230
        EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_exception );
1231
        rec->ExceptionCode = CONTROL_C_EXIT;
1232
    }
1233 1234
}

1235 1236 1237 1238 1239
/**********************************************************************
 *		abrt_handler
 *
 * Handler for SIGABRT.
 */
1240
static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1241
{
1242
    EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_exception );
1243 1244
    rec->ExceptionCode  = EXCEPTION_WINE_ASSERTION;
    rec->ExceptionFlags = EH_NONCONTINUABLE;
1245 1246
}

1247

1248 1249 1250 1251 1252
/**********************************************************************
 *		term_handler
 *
 * Handler for SIGTERM.
 */
1253
static void term_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1254
{
1255
    WORD fs, gs;
1256
    init_handler( sigcontext, &fs, &gs );
1257
    server_abort_thread(0);
1258 1259 1260
}


1261 1262 1263 1264 1265
/**********************************************************************
 *		usr1_handler
 *
 * Handler for SIGUSR1, used to signal a thread that it got suspended.
 */
1266
static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1267
{
1268
    CONTEXT context;
1269
    WORD fs, gs;
1270

1271 1272
    init_handler( sigcontext, &fs, &gs );
    save_context( &context, sigcontext, fs, gs );
1273
    wait_suspend( &context );
1274
    restore_context( &context, sigcontext );
1275 1276 1277
}


1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
/**********************************************************************
 *		get_signal_stack_total_size
 *
 * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
 * Must be a power of two.
 */
size_t get_signal_stack_total_size(void)
{
    static const size_t teb_size = 4096;  /* we reserve one page for the TEB */

    if (!signal_stack_size)
    {
        size_t size = 4096, min_size = teb_size + max( MINSIGSTKSZ, 4096 );
        /* find the first power of two not smaller than min_size */
        while (size < min_size) size *= 2;
        signal_stack_mask = size - 1;
        signal_stack_size = size - teb_size;
    }
    return signal_stack_size + teb_size;
}


1300 1301 1302
/***********************************************************************
 *           __wine_set_signal_handler   (NTDLL.@)
 */
1303
int __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
1304
{
1305
    if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1;
1306 1307 1308 1309 1310 1311
    if (handlers[sig] != NULL) return -2;
    handlers[sig] = wsh;
    return 0;
}


1312 1313 1314 1315 1316
/**********************************************************************
 *		SIGNAL_Init
 */
BOOL SIGNAL_Init(void)
{
1317
    struct sigaction sig_act;
1318 1319

#ifdef HAVE_SIGALTSTACK
1320
    struct sigaltstack ss;
1321 1322 1323 1324 1325 1326 1327 1328 1329

#ifdef __APPLE__
    int mib[2], val = 1;

    mib[0] = CTL_KERN;
    mib[1] = KERN_THALTSTACK;
    sysctl( mib, 2, NULL, NULL, &val, sizeof(val) );
#endif

1330
    ss.ss_sp    = get_signal_stack();
1331
    ss.ss_size  = signal_stack_size;
1332
    ss.ss_flags = 0;
1333 1334 1335 1336 1337
    if (sigaltstack(&ss, NULL) == -1)
    {
        perror( "sigaltstack" );
        return FALSE;
    }
1338
#endif  /* HAVE_SIGALTSTACK */
1339

1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
    sigemptyset( &sig_act.sa_mask );
    sigaddset( &sig_act.sa_mask, SIGINT );
    sigaddset( &sig_act.sa_mask, SIGUSR1 );
    sigaddset( &sig_act.sa_mask, SIGUSR2 );
    sig_act.sa_flags = SA_SIGINFO | SA_RESTART;

#ifdef SA_ONSTACK
    sig_act.sa_flags |= SA_ONSTACK;
#endif

1350
    sig_act.sa_sigaction = int_handler;
1351
    if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
1352
    sig_act.sa_sigaction = fpe_handler;
1353
    if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
1354
    sig_act.sa_sigaction = abrt_handler;
1355
    if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
1356
    sig_act.sa_sigaction = term_handler;
1357
    if (sigaction( SIGTERM, &sig_act, NULL ) == -1) goto error;
1358
    sig_act.sa_sigaction = usr1_handler;
1359 1360
    if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;

1361
    sig_act.sa_sigaction = segv_handler;
1362 1363
    if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
    if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
1364
#ifdef SIGBUS
1365
    if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
1366
#endif
1367

1368
#ifdef SIGTRAP
1369
    sig_act.sa_sigaction = trap_handler;
1370
    if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1371
#endif
1372

1373
#ifdef __HAVE_VM86
1374
    sig_act.sa_sigaction = usr2_handler;
1375
    if (sigaction( SIGUSR2, &sig_act, NULL ) == -1) goto error;
1376 1377
#endif

1378 1379 1380 1381 1382 1383 1384
    return TRUE;

 error:
    perror("sigaction");
    return FALSE;
}

1385

1386
#ifdef __HAVE_VM86
1387
/**********************************************************************
1388
 *		__wine_enter_vm86   (NTDLL.@)
1389 1390 1391 1392 1393 1394 1395 1396 1397
 *
 * Enter vm86 mode with the specified register context.
 */
void __wine_enter_vm86( CONTEXT *context )
{
    EXCEPTION_RECORD rec;
    int res;
    struct vm86plus_struct vm86;

1398
    memset( &vm86, 0, sizeof(vm86) );
1399 1400
    for (;;)
    {
1401
        restore_vm86_context( context, &vm86 );
1402

1403
        ntdll_get_thread_data()->vm86_ptr = &vm86;
1404
        merge_vm86_pending_flags( &rec );
1405

1406
        res = vm86_enter( &ntdll_get_thread_data()->vm86_ptr ); /* uses and clears teb->vm86_ptr */
1407
        if (res < 0)
1408
        {
1409 1410 1411
            errno = -res;
            return;
        }
1412

1413
        save_vm86_context( context, &vm86 );
1414

1415 1416 1417 1418 1419
        rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
        rec.ExceptionRecord  = NULL;
        rec.ExceptionAddress = (LPVOID)context->Eip;
        rec.NumberParameters = 0;

1420 1421 1422
        switch(VM86_TYPE(res))
        {
        case VM86_UNKNOWN: /* unhandled GP fault - IO-instruction or similar */
1423 1424
            rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
            raise_segv_exception( &rec, context );
1425 1426
            continue;
        case VM86_TRAP: /* return due to DOS-debugger request */
1427 1428
            switch(VM86_ARG(res))
            {
1429
            case TRAP_x86_TRCTRAP:  /* Single-step exception */
1430 1431
                rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
                break;
1432
            case TRAP_x86_BPTFLT:   /* Breakpoint exception */
1433 1434 1435 1436 1437 1438
                rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1;  /* back up over the int3 instruction */
                /* fall through */
            default:
                rec.ExceptionCode = EXCEPTION_BREAKPOINT;
                break;
            }
1439
            break;
1440 1441
        case VM86_INTx: /* int3/int x instruction (ARG = x) */
            rec.ExceptionCode = EXCEPTION_VM86_INTx;
1442 1443
            rec.NumberParameters = 1;
            rec.ExceptionInformation[0] = VM86_ARG(res);
1444 1445
            break;
        case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */
1446 1447
            context->EFlags |= VIF_MASK;
            context->EFlags &= ~VIP_MASK;
1448
            NtCurrentTeb()->vm86_pending = 0;
1449 1450 1451 1452 1453
            rec.ExceptionCode = EXCEPTION_VM86_STI;
            break;
        case VM86_PICRETURN: /* return due to pending PIC request */
            rec.ExceptionCode = EXCEPTION_VM86_PICRETURN;
            break;
1454
        case VM86_SIGNAL: /* cannot happen because vm86_enter handles this case */
1455 1456 1457 1458
        default:
            ERR( "unhandled result from vm86 mode %x\n", res );
            continue;
        }
1459
        __regs_RtlRaiseException( &rec, context );
1460 1461 1462
    }
}

1463
#else /* __HAVE_VM86 */
1464 1465 1466
/**********************************************************************
 *		__wine_enter_vm86   (NTDLL.@)
 */
1467 1468 1469 1470
void __wine_enter_vm86( CONTEXT *context )
{
    MESSAGE("vm86 mode not supported on this platform\n");
}
1471
#endif /* __HAVE_VM86 */
1472

1473
/**********************************************************************
1474
 *		DbgBreakPoint   (NTDLL.@)
1475
 */
1476
__ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret");
1477 1478

/**********************************************************************
1479
 *		DbgUserBreakPoint   (NTDLL.@)
1480
 */
1481
__ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret");
1482

1483 1484 1485

/**********************************************************************
 *		EXC_CallHandler   (internal)
1486 1487 1488 1489 1490 1491 1492
 *
 * Some exception handlers depend on EBP to have a fixed position relative to
 * the exception frame.
 * Shrinker depends on (*1) doing what it does,
 * (*2) being the exact instruction it is and (*3) beginning with 0x64
 * (i.e. the %fs prefix to the movl instruction). It also depends on the
 * function calling the handler having only 5 parameters (*4).
1493 1494 1495 1496
 */
__ASM_GLOBAL_FUNC( EXC_CallHandler,
"	pushl	%ebp\n"
"	movl	%esp, %ebp\n"
1497
"	pushl	%ebx\n"
1498 1499 1500 1501 1502 1503
"	movl	28(%ebp), %edx\n" /* ugly hack to pass the 6th param needed because of Shrinker */
"	pushl	24(%ebp)\n"
"	pushl	20(%ebp)\n"
"	pushl	16(%ebp)\n"
"	pushl	12(%ebp)\n"
"	pushl	8(%ebp)\n"
1504
"	call	" __ASM_NAME("call_exception_handler") "\n"
1505
"	popl	%ebx\n"
1506 1507 1508
"	leave\n"
"	ret\n"
);
1509 1510 1511
__ASM_GLOBAL_FUNC(call_exception_handler,
"	pushl	%ebp\n"
"	movl	%esp, %ebp\n"
1512
"	subl    $12,%esp\n"
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
"	pushl	12(%ebp)\n"       /* make any exceptions in this... */
"	pushl	%edx\n"           /* handler be handled by... */
"	.byte	0x64\n"
"	pushl	(0)\n"            /* nested_handler (passed in edx). */
"	.byte	0x64\n"
"	movl	%esp,(0)\n"       /* push the new exception frame onto the exception stack. */
"	pushl	20(%ebp)\n"
"	pushl	16(%ebp)\n"
"	pushl	12(%ebp)\n"
"	pushl	8(%ebp)\n"
"	movl	24(%ebp), %ecx\n" /* (*1) */
"	call	*%ecx\n"          /* call handler. (*2) */
"	.byte	0x64\n"
"	movl	(0), %esp\n"      /* restore previous... (*3) */
"	.byte	0x64\n"
"	popl	(0)\n"            /* exception frame. */
"	movl	%ebp, %esp\n"     /* restore saved stack, in case it was corrupted */
"	popl	%ebp\n"
"	ret	$20\n"            /* (*4) */
);
1533
#endif  /* __i386__ */