except.c 19.9 KB
Newer Older
1 2 3 4
/*
 * msvcrt.dll exception handling
 *
 * Copyright 2000 Jon Griffiths
Juan Lang's avatar
Juan Lang committed
5
 * Copyright 2005 Juan Lang
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
 *
21
 * FIXME: Incomplete support for nested exceptions/try block cleanup.
22
 */
23

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

27 28 29 30
#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
31
#include "winternl.h"
32
#include "wine/exception.h"
33
#include "msvcrt.h"
34
#include "excpt.h"
Juan Lang's avatar
Juan Lang committed
35
#include "wincon.h"
36 37
#include "wine/debug.h"

38
WINE_DEFAULT_DEBUG_CHANNEL(seh);
39 40 41 42

/* VC++ extensions to Win32 SEH */
typedef struct _SCOPETABLE
{
43
  int previousTryLevel;
44 45
  int (*lpfnFilter)(PEXCEPTION_POINTERS);
  int (*lpfnHandler)(void);
46 47
} SCOPETABLE, *PSCOPETABLE;

48
typedef struct _MSVCRT_EXCEPTION_FRAME
49
{
50
  EXCEPTION_REGISTRATION_RECORD *prev;
51
  void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*,
52 53
                  PCONTEXT, PEXCEPTION_RECORD);
  PSCOPETABLE scopetable;
54
  int trylevel;
55 56
  int _ebp;
  PEXCEPTION_POINTERS xpointers;
57
} MSVCRT_EXCEPTION_FRAME;
58

59
#define TRYLEVEL_END (-1) /* End of trylevel list */
60 61

#if defined(__GNUC__) && defined(__i386__)
62
static inline void call_finally_block( void *code_block, void *base_ptr )
63
{
64
    __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax"
65 66
                          : : "a" (code_block), "g" (base_ptr));
}
67

68
static inline int call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *ebp )
69
{
70
    int ret;
71
    __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp"
72
                          : "=a" (ret)
73
                          : "0" (func), "r" (ebp), "r" (arg)
74
                          : "ecx", "edx", "memory" );
75 76
    return ret;
}
77 78 79 80

static inline int call_unwind_func( int (*func)(void), void *ebp )
{
    int ret;
81 82 83 84 85 86 87 88 89 90
    __asm__ __volatile__ ("pushl %%ebp\n\t"
                          "pushl %%ebx\n\t"
                          "pushl %%esi\n\t"
                          "pushl %%edi\n\t"
                          "movl %2,%%ebp\n\t"
                          "call *%0\n\t"
                          "popl %%edi\n\t"
                          "popl %%esi\n\t"
                          "popl %%ebx\n\t"
                          "popl %%ebp"
91 92 93 94 95 96
                          : "=a" (ret)
                          : "0" (func), "r" (ebp)
                          : "ecx", "edx", "memory" );
    return ret;
}

97
#endif
98

99 100 101

#ifdef __i386__

102
static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
103
                                   EXCEPTION_REGISTRATION_RECORD* frame,
104
                                   PCONTEXT context,
105
                                   EXCEPTION_REGISTRATION_RECORD** dispatch)
106
{
107
  if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
108 109 110 111 112
    return ExceptionContinueSearch;
  *dispatch = frame;
  return ExceptionCollidedUnwind;
}

113

114 115 116
/*********************************************************************
 *		_EH_prolog (MSVCRT.@)
 */
117

118
/* Provided for VC++ binary compatibility only */
119
__ASM_GLOBAL_FUNC(_EH_prolog,
120
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")  /* skip ret addr */
121
                  "pushl $-1\n\t"
122
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
123
                  "pushl %eax\n\t"
124
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
125
                  "pushl %fs:0\n\t"
126
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
127 128 129 130 131
                  "movl  %esp, %fs:0\n\t"
                  "movl  12(%esp), %eax\n\t"
                  "movl  %ebp, 12(%esp)\n\t"
                  "leal  12(%esp), %ebp\n\t"
                  "pushl %eax\n\t"
132
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
133
                  "ret")
134

135
static void msvcrt_local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp)
136
{
137
  EXCEPTION_REGISTRATION_RECORD reg;
138

139
  TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
140 141

  /* Register a handler in case of a nested exception */
142
  reg.Handler = MSVCRT_nested_handler;
143
  reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
144 145 146 147
  __wine_push_frame(&reg);

  while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
  {
148 149 150 151
      int level = frame->trylevel;
      frame->trylevel = frame->scopetable[level].previousTryLevel;
      if (!frame->scopetable[level].lpfnFilter)
      {
152 153 154
          TRACE( "__try block cleanup level %d handler %p ebp %p\n",
                 level, frame->scopetable[level].lpfnHandler, ebp );
          call_unwind_func( frame->scopetable[level].lpfnHandler, ebp );
155
      }
156 157 158
  }
  __wine_pop_frame(&reg);
  TRACE("unwound OK\n");
159 160
}

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/*******************************************************************
 *		_local_unwind2 (MSVCRT.@)
 */
void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
{
    msvcrt_local_unwind2( frame, trylevel, &frame->_ebp );
}

#endif  /* __i386__ */

/*******************************************************************
 *		_global_unwind2 (MSVCRT.@)
 */
void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame)
{
    TRACE("(%p)\n",frame);
    RtlUnwind( frame, 0, 0, 0 );
}

180 181 182
/*********************************************************************
 *		_except_handler2 (MSVCRT.@)
 */
183 184 185 186
int CDECL _except_handler2(PEXCEPTION_RECORD rec,
                           EXCEPTION_REGISTRATION_RECORD* frame,
                           PCONTEXT context,
                           EXCEPTION_REGISTRATION_RECORD** dispatcher)
187
{
188
  FIXME("exception %x flags=%x at %p handler=%p %p %p stub\n",
189 190 191 192 193 194 195 196
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->Handler, context, dispatcher);
  return ExceptionContinueSearch;
}

/*********************************************************************
 *		_except_handler3 (MSVCRT.@)
 */
197 198 199
int CDECL _except_handler3(PEXCEPTION_RECORD rec,
                           MSVCRT_EXCEPTION_FRAME* frame,
                           PCONTEXT context, void* dispatcher)
200
{
201
#if defined(__GNUC__) && defined(__i386__)
202
  int retval, trylevel;
203 204 205
  EXCEPTION_POINTERS exceptPtrs;
  PSCOPETABLE pScopeTable;

206
  TRACE("exception %x flags=%x at %p handler=%p %p %p semi-stub\n",
207 208
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->handler, context, dispatcher);
209 210 211 212 213 214

  __asm__ __volatile__ ("cld");

  if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
  {
    /* Unwinding the current frame */
215
    msvcrt_local_unwind2(frame, TRYLEVEL_END, &frame->_ebp);
216
    TRACE("unwound current frame, returning ExceptionContinueSearch\n");
217 218 219 220 221 222 223 224 225 226 227 228 229
    return ExceptionContinueSearch;
  }
  else
  {
    /* Hunting for handler */
    exceptPtrs.ExceptionRecord = rec;
    exceptPtrs.ContextRecord = context;
    *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
    trylevel = frame->trylevel;
    pScopeTable = frame->scopetable;

    while (trylevel != TRYLEVEL_END)
    {
230 231
      TRACE( "level %d prev %d filter %p\n", trylevel, pScopeTable[trylevel].previousTryLevel,
             pScopeTable[trylevel].lpfnFilter );
232 233
      if (pScopeTable[trylevel].lpfnFilter)
      {
234
        retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
235 236 237 238 239 240 241 242 243 244 245

        TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
              "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
              "EXECUTE_HANDLER" : "CONTINUE_SEARCH");

        if (retval == EXCEPTION_CONTINUE_EXECUTION)
          return ExceptionContinueExecution;

        if (retval == EXCEPTION_EXECUTE_HANDLER)
        {
          /* Unwind all higher frames, this one will handle the exception */
246
          _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
247
          msvcrt_local_unwind2(frame, trylevel, &frame->_ebp);
248 249 250 251

          /* Set our trylevel to the enclosing block, and call the __finally
           * code, which won't return
           */
252
          frame->trylevel = pScopeTable[trylevel].previousTryLevel;
253
          TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
254
          call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
255 256 257
          ERR("Returned from __finally block - expect crash!\n");
       }
      }
258
      trylevel = pScopeTable[trylevel].previousTryLevel;
259 260 261
    }
  }
#else
262
  FIXME("exception %x flags=%x at %p handler=%p %p %p stub\n",
263 264 265
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->handler, context, dispatcher);
#endif
266
  TRACE("reached TRYLEVEL_END, returning ExceptionContinueSearch\n");
267 268 269 270 271 272
  return ExceptionContinueSearch;
}

/*********************************************************************
 *		_abnormal_termination (MSVCRT.@)
 */
273
int CDECL _abnormal_termination(void)
274 275 276 277 278
{
  FIXME("(void)stub\n");
  return 0;
}

279 280 281 282 283 284
/*
 * setjmp/longjmp implementation
 */

#ifdef __i386__
#define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
285
typedef void (__stdcall *MSVCRT_unwind_function)(const struct MSVCRT___JUMP_BUFFER *);
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
/* define an entrypoint for setjmp/setjmp3 that stores the registers in the jmp buf */
/* and then jumps to the C backend function */
#define DEFINE_SETJMP_ENTRYPOINT(name) \
    __ASM_GLOBAL_FUNC( name, \
                       "movl 4(%esp),%ecx\n\t"   /* jmp_buf */      \
                       "movl %ebp,0(%ecx)\n\t"   /* jmp_buf.Ebp */  \
                       "movl %ebx,4(%ecx)\n\t"   /* jmp_buf.Ebx */  \
                       "movl %edi,8(%ecx)\n\t"   /* jmp_buf.Edi */  \
                       "movl %esi,12(%ecx)\n\t"  /* jmp_buf.Esi */  \
                       "movl %esp,16(%ecx)\n\t"  /* jmp_buf.Esp */  \
                       "movl 0(%esp),%eax\n\t"                      \
                       "movl %eax,20(%ecx)\n\t"  /* jmp_buf.Eip */  \
                       "jmp " __ASM_NAME("__regs_") # name )

/* restore the registers from the jmp buf upon longjmp */
extern void DECLSPEC_NORETURN longjmp_set_regs( struct MSVCRT___JUMP_BUFFER *jmp, int retval );
__ASM_GLOBAL_FUNC( longjmp_set_regs,
                   "movl 4(%esp),%ecx\n\t"   /* jmp_buf */
                   "movl 8(%esp),%eax\n\t"   /* retval */
                   "movl 0(%ecx),%ebp\n\t"   /* jmp_buf.Ebp */
                   "movl 4(%ecx),%ebx\n\t"   /* jmp_buf.Ebx */
                   "movl 8(%ecx),%edi\n\t"   /* jmp_buf.Edi */
                   "movl 12(%ecx),%esi\n\t"  /* jmp_buf.Esi */
                   "movl 16(%ecx),%esp\n\t"  /* jmp_buf.Esp */
                   "addl $4,%esp\n\t"        /* get rid of return address */
312
                   "jmp *20(%ecx)\n\t"       /* jmp_buf.Eip */ )
313

314
/*
315 316
 * The signatures of the setjmp/longjmp functions do not match that
 * declared in the setjmp header so they don't follow the regular naming
317 318 319
 * convention to avoid conflicts.
 */

320 321 322
/*******************************************************************
 *		_setjmp (MSVCRT.@)
 */
323
DEFINE_SETJMP_ENTRYPOINT(MSVCRT__setjmp)
324
int CDECL __regs_MSVCRT__setjmp(struct MSVCRT___JUMP_BUFFER *jmp)
325
{
326
    jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
327
    if (jmp->Registration == ~0UL)
328 329 330
        jmp->TryLevel = TRYLEVEL_END;
    else
        jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
331 332 333 334

    TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
          jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
    return 0;
335 336
}

Eric Kohl's avatar
Eric Kohl committed
337 338 339
/*******************************************************************
 *		_setjmp3 (MSVCRT.@)
 */
340
DEFINE_SETJMP_ENTRYPOINT( MSVCRT__setjmp3 )
341
int CDECL __regs_MSVCRT__setjmp3(struct MSVCRT___JUMP_BUFFER *jmp, int nb_args, ...)
Eric Kohl's avatar
Eric Kohl committed
342
{
343 344
    jmp->Cookie = MSVCRT_JMP_MAGIC;
    jmp->UnwindFunc = 0;
345
    jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
346
    if (jmp->Registration == ~0UL)
347 348 349 350 351
    {
        jmp->TryLevel = TRYLEVEL_END;
    }
    else
    {
352 353
        int i;
        va_list args;
354

355 356 357
        va_start( args, nb_args );
        if (nb_args > 0) jmp->UnwindFunc = va_arg( args, unsigned long );
        if (nb_args > 1) jmp->TryLevel = va_arg( args, unsigned long );
358
        else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
359 360 361
        for (i = 0; i < 6 && i < nb_args - 2; i++)
            jmp->UnwindData[i] = va_arg( args, unsigned long );
        va_end( args );
362
    }
363 364 365 366

    TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
          jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
    return 0;
Eric Kohl's avatar
Eric Kohl committed
367 368
}

369 370 371
/*********************************************************************
 *		longjmp (MSVCRT.@)
 */
372
int CDECL MSVCRT_longjmp(struct MSVCRT___JUMP_BUFFER *jmp, int retval)
373
{
374 375
    unsigned long cur_frame = 0;

376 377
    TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx retval=%08x\n",
          jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration, retval );
378

379
    cur_frame=(unsigned long)NtCurrentTeb()->Tib.ExceptionList;
380 381 382
    TRACE("cur_frame=%lx\n",cur_frame);

    if (cur_frame != jmp->Registration)
383
        _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)jmp->Registration);
384 385 386 387 388 389 390 391 392 393 394 395

    if (jmp->Registration)
    {
        if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
            jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
        {
            MSVCRT_unwind_function unwind_func;

            unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
            unwind_func(jmp);
        }
        else
396 397
            msvcrt_local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
                                 jmp->TryLevel, (void *)jmp->Ebp);
398 399 400 401 402
    }

    if (!retval)
        retval = 1;

403
    longjmp_set_regs( jmp, retval );
404 405
}

406 407 408
/*********************************************************************
 *		_seh_longjmp_unwind (MSVCRT.@)
 */
409
void __stdcall _seh_longjmp_unwind(struct MSVCRT___JUMP_BUFFER *jmp)
410
{
411
    msvcrt_local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel, (void *)jmp->Ebp );
412
}
413
#endif /* i386 */
414

415
static MSVCRT___sighandler_t sighandlers[MSVCRT_NSIG] = { MSVCRT_SIG_DFL };
Juan Lang's avatar
Juan Lang committed
416 417 418 419 420 421 422 423

static BOOL WINAPI msvcrt_console_handler(DWORD ctrlType)
{
    BOOL ret = FALSE;

    switch (ctrlType)
    {
    case CTRL_C_EVENT:
424
        if (sighandlers[MSVCRT_SIGINT])
Juan Lang's avatar
Juan Lang committed
425
        {
426 427
            if (sighandlers[MSVCRT_SIGINT] != MSVCRT_SIG_IGN)
                sighandlers[MSVCRT_SIGINT](MSVCRT_SIGINT);
Juan Lang's avatar
Juan Lang committed
428 429 430 431 432 433 434 435 436 437
            ret = TRUE;
        }
        break;
    }
    return ret;
}

typedef void (*float_handler)(int, int);

/* The exception codes are actually NTSTATUS values */
438
static const struct
Juan Lang's avatar
Juan Lang committed
439 440 441 442
{
    NTSTATUS status;
    int signal;
} float_exception_map[] = {
443 444 445 446 447 448 449
 { EXCEPTION_FLT_DENORMAL_OPERAND, MSVCRT__FPE_DENORMAL },
 { EXCEPTION_FLT_DIVIDE_BY_ZERO, MSVCRT__FPE_ZERODIVIDE },
 { EXCEPTION_FLT_INEXACT_RESULT, MSVCRT__FPE_INEXACT },
 { EXCEPTION_FLT_INVALID_OPERATION, MSVCRT__FPE_INVALID },
 { EXCEPTION_FLT_OVERFLOW, MSVCRT__FPE_OVERFLOW },
 { EXCEPTION_FLT_STACK_CHECK, MSVCRT__FPE_STACKOVERFLOW },
 { EXCEPTION_FLT_UNDERFLOW, MSVCRT__FPE_UNDERFLOW },
Juan Lang's avatar
Juan Lang committed
450 451 452 453 454
};

static LONG WINAPI msvcrt_exception_filter(struct _EXCEPTION_POINTERS *except)
{
    LONG ret = EXCEPTION_CONTINUE_SEARCH;
455
    MSVCRT___sighandler_t handler;
Juan Lang's avatar
Juan Lang committed
456

457 458 459
    if (!except || !except->ExceptionRecord)
        return EXCEPTION_CONTINUE_SEARCH;

Juan Lang's avatar
Juan Lang committed
460 461 462
    switch (except->ExceptionRecord->ExceptionCode)
    {
    case EXCEPTION_ACCESS_VIOLATION:
463
        if ((handler = sighandlers[MSVCRT_SIGSEGV]) != MSVCRT_SIG_DFL)
Juan Lang's avatar
Juan Lang committed
464
        {
465 466 467 468 469
            if (handler != MSVCRT_SIG_IGN)
            {
                sighandlers[MSVCRT_SIGSEGV] = MSVCRT_SIG_DFL;
                handler(MSVCRT_SIGSEGV);
            }
Juan Lang's avatar
Juan Lang committed
470 471 472
            ret = EXCEPTION_CONTINUE_EXECUTION;
        }
        break;
473
    /* According to msdn,
Juan Lang's avatar
Juan Lang committed
474 475 476 477 478 479 480 481 482 483
     * the FPE signal handler takes as a second argument the type of
     * floating point exception.
     */
    case EXCEPTION_FLT_DENORMAL_OPERAND:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_INEXACT_RESULT:
    case EXCEPTION_FLT_INVALID_OPERATION:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_STACK_CHECK:
    case EXCEPTION_FLT_UNDERFLOW:
484
        if ((handler = sighandlers[MSVCRT_SIGFPE]) != MSVCRT_SIG_DFL)
Juan Lang's avatar
Juan Lang committed
485
        {
486
            if (handler != MSVCRT_SIG_IGN)
Juan Lang's avatar
Juan Lang committed
487
            {
488
                unsigned int i;
489
                int float_signal = MSVCRT__FPE_INVALID;
Juan Lang's avatar
Juan Lang committed
490

491
                sighandlers[MSVCRT_SIGFPE] = MSVCRT_SIG_DFL;
Juan Lang's avatar
Juan Lang committed
492
                for (i = 0; i < sizeof(float_exception_map) /
493 494
                         sizeof(float_exception_map[0]); i++)
                {
Juan Lang's avatar
Juan Lang committed
495
                    if (float_exception_map[i].status ==
496
                        except->ExceptionRecord->ExceptionCode)
Juan Lang's avatar
Juan Lang committed
497 498 499 500
                    {
                        float_signal = float_exception_map[i].signal;
                        break;
                    }
501 502
                }
                ((float_handler)handler)(MSVCRT_SIGFPE, float_signal);
Juan Lang's avatar
Juan Lang committed
503 504 505 506 507
            }
            ret = EXCEPTION_CONTINUE_EXECUTION;
        }
        break;
    case EXCEPTION_ILLEGAL_INSTRUCTION:
508
    case EXCEPTION_PRIV_INSTRUCTION:
509
        if ((handler = sighandlers[MSVCRT_SIGILL]) != MSVCRT_SIG_DFL)
Juan Lang's avatar
Juan Lang committed
510
        {
511 512 513 514 515
            if (handler != MSVCRT_SIG_IGN)
            {
                sighandlers[MSVCRT_SIGILL] = MSVCRT_SIG_DFL;
                handler(MSVCRT_SIGILL);
            }
Juan Lang's avatar
Juan Lang committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
            ret = EXCEPTION_CONTINUE_EXECUTION;
        }
        break;
    }
    return ret;
}

void msvcrt_init_signals(void)
{
    SetConsoleCtrlHandler(msvcrt_console_handler, TRUE);
    SetUnhandledExceptionFilter(msvcrt_exception_filter);
}

void msvcrt_free_signals(void)
{
    SetConsoleCtrlHandler(msvcrt_console_handler, FALSE);
    SetUnhandledExceptionFilter(NULL);
}

535 536
/*********************************************************************
 *		signal (MSVCRT.@)
Juan Lang's avatar
Juan Lang committed
537 538
 * Some signals may never be generated except through an explicit call to
 * raise.
539
 */
540
MSVCRT___sighandler_t CDECL MSVCRT_signal(int sig, MSVCRT___sighandler_t func)
541
{
542
    MSVCRT___sighandler_t ret = MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
543 544 545

    TRACE("(%d, %p)\n", sig, func);

546
    if (func == MSVCRT_SIG_ERR) return MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
547 548 549 550 551 552

    switch (sig)
    {
    /* Cases handled internally.  Note SIGTERM is never generated by Windows,
     * so we effectively mask it.
     */
553 554 555 556 557 558
    case MSVCRT_SIGABRT:
    case MSVCRT_SIGFPE:
    case MSVCRT_SIGILL:
    case MSVCRT_SIGSEGV:
    case MSVCRT_SIGINT:
    case MSVCRT_SIGTERM:
Juan Lang's avatar
Juan Lang committed
559 560 561 562
        ret = sighandlers[sig];
        sighandlers[sig] = func;
        break;
    default:
563
        ret = MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
564 565
    }
    return ret;
566
}
567

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
/*********************************************************************
 *		raise (MSVCRT.@)
 */
int CDECL MSVCRT_raise(int sig)
{
    MSVCRT___sighandler_t handler;

    TRACE("(%d)\n", sig);

    switch (sig)
    {
    case MSVCRT_SIGABRT:
    case MSVCRT_SIGFPE:
    case MSVCRT_SIGILL:
    case MSVCRT_SIGSEGV:
    case MSVCRT_SIGINT:
    case MSVCRT_SIGTERM:
        handler = sighandlers[sig];
        if (handler == MSVCRT_SIG_DFL) MSVCRT__exit(3);
        if (handler != MSVCRT_SIG_IGN)
        {
            sighandlers[sig] = MSVCRT_SIG_DFL;
            if (sig == MSVCRT_SIGFPE)
591
                ((float_handler)handler)(sig, MSVCRT__FPE_EXPLICITGEN);
592 593 594 595 596 597 598 599 600 601
            else
                handler(sig);
        }
        break;
    default:
        return -1;
    }
    return 0;
}

602 603 604
/*********************************************************************
 *		_XcptFilter (MSVCRT.@)
 */
605
int CDECL _XcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr)
606
{
607
    TRACE("(%08x,%p)\n", ex, ptr);
608 609 610
    /* I assume ptr->ExceptionRecord->ExceptionCode is the same as ex */
    return msvcrt_exception_filter(ptr);
}
611 612 613 614 615 616 617 618

/******************************************************************
 *		MSVCRT___uncaught_exception
 */
BOOL CDECL MSVCRT___uncaught_exception(void)
{
    return FALSE;
}