except.c 17.6 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 22
 *
 * NOTES:
 *
23 24 25
 * See http://www.microsoft.com/msj/0197/exception/exception.htm,
 * but don't believe all of it.
 *
26
 * FIXME: Incomplete support for nested exceptions/try block cleanup.
27
 */
28

29
#include "config.h"
30
#include "wine/port.h"
31

32 33 34 35 36
#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "winreg.h"
37
#include "winternl.h"
38
#include "wine/exception.h"
39
#include "msvcrt.h"
40
#include "excpt.h"
Juan Lang's avatar
Juan Lang committed
41 42
#include "wincon.h"
#include "msvcrt/float.h"
43 44
#include "wine/debug.h"

45
WINE_DEFAULT_DEBUG_CHANNEL(seh);
46 47 48 49

/* VC++ extensions to Win32 SEH */
typedef struct _SCOPETABLE
{
50
  int previousTryLevel;
51 52
  int (*lpfnFilter)(PEXCEPTION_POINTERS);
  int (*lpfnHandler)(void);
53 54
} SCOPETABLE, *PSCOPETABLE;

55
typedef struct _MSVCRT_EXCEPTION_FRAME
56
{
57
  EXCEPTION_REGISTRATION_RECORD *prev;
58
  void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*,
59 60
                  PCONTEXT, PEXCEPTION_RECORD);
  PSCOPETABLE scopetable;
61
  int trylevel;
62 63
  int _ebp;
  PEXCEPTION_POINTERS xpointers;
64
} MSVCRT_EXCEPTION_FRAME;
65

66
#define TRYLEVEL_END (-1) /* End of trylevel list */
67 68

#if defined(__GNUC__) && defined(__i386__)
69 70 71 72 73
inline static void call_finally_block( void *code_block, void *base_ptr )
{
    __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" \
                          : : "a" (code_block), "g" (base_ptr));
}
74

75
inline static DWORD call_filter( void *func, void *arg, void *ebp )
76 77 78
{
    DWORD ret;
    __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp"
79
                          : "=a" (ret)
80
                          : "0" (func), "r" (ebp), "r" (arg)
81
                          : "ecx", "edx", "memory" );
82 83
    return ret;
}
84
#endif
85

86
static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
87
                                   EXCEPTION_REGISTRATION_RECORD* frame,
88
                                   PCONTEXT context,
89
                                   EXCEPTION_REGISTRATION_RECORD** dispatch)
90
{
91 92 93 94 95 96
  if (rec->ExceptionFlags & 0x6)
    return ExceptionContinueSearch;
  *dispatch = frame;
  return ExceptionCollidedUnwind;
}

97

98 99 100 101
/*********************************************************************
 *		_EH_prolog (MSVCRT.@)
 */
#ifdef __i386__
102
/* Provided for VC++ binary compatibility only */
103
__ASM_GLOBAL_FUNC(_EH_prolog,
104
                  "pushl $-1\n\t"
105 106 107 108 109 110 111 112 113 114
                  "pushl %eax\n\t"
                  "pushl %fs:0\n\t"
                  "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"
                  "ret");
#endif

115 116 117
/*******************************************************************
 *		_global_unwind2 (MSVCRT.@)
 */
118
void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame)
119
{
120 121
    TRACE("(%p)\n",frame);
    RtlUnwind( frame, 0, 0, 0 );
122 123 124 125 126
}

/*******************************************************************
 *		_local_unwind2 (MSVCRT.@)
 */
127
void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
128
{
129
  MSVCRT_EXCEPTION_FRAME *curframe = frame;
130
  EXCEPTION_REGISTRATION_RECORD reg;
131

132
  TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
133 134 135

  /* Register a handler in case of a nested exception */
  reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
136
  reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
137 138 139 140
  __wine_push_frame(&reg);

  while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
  {
141
    int curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
142 143 144 145 146 147 148 149 150 151 152 153
    curframe = frame;
    curframe->trylevel = curtrylevel;
    if (!frame->scopetable[curtrylevel].lpfnFilter)
    {
      ERR("__try block cleanup not implemented - expect crash!\n");
      /* FIXME: Remove current frame, set ebp, call
       * frame->scopetable[curtrylevel].lpfnHandler()
       */
    }
  }
  __wine_pop_frame(&reg);
  TRACE("unwound OK\n");
154 155 156 157 158
}

/*********************************************************************
 *		_except_handler2 (MSVCRT.@)
 */
159 160 161 162
int CDECL _except_handler2(PEXCEPTION_RECORD rec,
                           EXCEPTION_REGISTRATION_RECORD* frame,
                           PCONTEXT context,
                           EXCEPTION_REGISTRATION_RECORD** dispatcher)
163
{
164
  FIXME("exception %x flags=%x at %p handler=%p %p %p stub\n",
165 166 167 168 169 170 171 172
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->Handler, context, dispatcher);
  return ExceptionContinueSearch;
}

/*********************************************************************
 *		_except_handler3 (MSVCRT.@)
 */
173 174 175
int CDECL _except_handler3(PEXCEPTION_RECORD rec,
                           MSVCRT_EXCEPTION_FRAME* frame,
                           PCONTEXT context, void* dispatcher)
176
{
177
#if defined(__GNUC__) && defined(__i386__)
178 179
  long retval;
  int trylevel;
180 181 182
  EXCEPTION_POINTERS exceptPtrs;
  PSCOPETABLE pScopeTable;

183
  TRACE("exception %x flags=%x at %p handler=%p %p %p semi-stub\n",
184 185
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->handler, context, dispatcher);
186 187 188 189 190 191

  __asm__ __volatile__ ("cld");

  if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
  {
    /* Unwinding the current frame */
192
     _local_unwind2(frame, TRYLEVEL_END);
193
    TRACE("unwound current frame, returning ExceptionContinueSearch\n");
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    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)
    {
      if (pScopeTable[trylevel].lpfnFilter)
      {
        TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);

211
        retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
212 213 214 215 216 217 218 219 220 221 222

        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 */
223
          _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
224
          _local_unwind2(frame, trylevel);
225 226 227 228 229 230

          /* Set our trylevel to the enclosing block, and call the __finally
           * code, which won't return
           */
          frame->trylevel = pScopeTable->previousTryLevel;
          TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
231
          call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
232 233 234 235 236 237 238 239 240 241 242
          ERR("Returned from __finally block - expect crash!\n");
       }
      }
      trylevel = pScopeTable->previousTryLevel;
    }
  }
#else
  TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
        rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
        frame->handler, context, dispatcher);
#endif
243
  TRACE("reached TRYLEVEL_END, returning ExceptionContinueSearch\n");
244 245 246 247 248 249
  return ExceptionContinueSearch;
}

/*********************************************************************
 *		_abnormal_termination (MSVCRT.@)
 */
250
int CDECL _abnormal_termination(void)
251 252 253 254 255
{
  FIXME("(void)stub\n");
  return 0;
}

256 257 258 259 260 261 262 263
/*
 * setjmp/longjmp implementation
 */

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

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
/* 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 */
                   "jmp *20(%ecx)\n\t"       /* jmp_buf.Eip */ );

291
/*
292 293
 * The signatures of the setjmp/longjmp functions do not match that
 * declared in the setjmp header so they don't follow the regular naming
294 295 296
 * convention to avoid conflicts.
 */

297 298 299
/*******************************************************************
 *		_setjmp (MSVCRT.@)
 */
300
DEFINE_SETJMP_ENTRYPOINT(MSVCRT__setjmp);
301
int CDECL __regs_MSVCRT__setjmp(struct MSVCRT___JUMP_BUFFER *jmp)
302
{
303
    jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
304 305 306 307
    if (jmp->Registration == TRYLEVEL_END)
        jmp->TryLevel = TRYLEVEL_END;
    else
        jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
308 309 310 311

    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;
312 313
}

Eric Kohl's avatar
Eric Kohl committed
314 315 316
/*******************************************************************
 *		_setjmp3 (MSVCRT.@)
 */
317
DEFINE_SETJMP_ENTRYPOINT( MSVCRT__setjmp3 );
318
int CDECL __regs_MSVCRT__setjmp3(struct MSVCRT___JUMP_BUFFER *jmp, int nb_args, ...)
Eric Kohl's avatar
Eric Kohl committed
319
{
320 321
    jmp->Cookie = MSVCRT_JMP_MAGIC;
    jmp->UnwindFunc = 0;
322
    jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
323 324 325 326 327 328
    if (jmp->Registration == TRYLEVEL_END)
    {
        jmp->TryLevel = TRYLEVEL_END;
    }
    else
    {
329 330
        int i;
        va_list args;
331

332 333 334
        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 );
335
        else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
336 337 338
        for (i = 0; i < 6 && i < nb_args - 2; i++)
            jmp->UnwindData[i] = va_arg( args, unsigned long );
        va_end( args );
339
    }
340 341 342 343

    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
344 345
}

346 347 348
/*********************************************************************
 *		longjmp (MSVCRT.@)
 */
349
int CDECL MSVCRT_longjmp(struct MSVCRT___JUMP_BUFFER *jmp, int retval)
350
{
351 352
    unsigned long cur_frame = 0;

353 354
    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 );
355

356
    cur_frame=(unsigned long)NtCurrentTeb()->Tib.ExceptionList;
357 358 359
    TRACE("cur_frame=%lx\n",cur_frame);

    if (cur_frame != jmp->Registration)
360
        _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)jmp->Registration);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    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
            _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
                           jmp->TryLevel);
    }

    if (!retval)
        retval = 1;

380
    longjmp_set_regs( jmp, retval );
381 382
}

383 384 385
/*********************************************************************
 *		_seh_longjmp_unwind (MSVCRT.@)
 */
386
void __stdcall _seh_longjmp_unwind(struct MSVCRT___JUMP_BUFFER *jmp)
387 388 389
{
    _local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel );
}
390
#endif /* i386 */
391

392
static MSVCRT___sighandler_t sighandlers[MSVCRT_NSIG] = { MSVCRT_SIG_DFL };
Juan Lang's avatar
Juan Lang committed
393 394 395 396 397 398 399 400

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

    switch (ctrlType)
    {
    case CTRL_C_EVENT:
401
        if (sighandlers[MSVCRT_SIGINT])
Juan Lang's avatar
Juan Lang committed
402
        {
403 404
            if (sighandlers[MSVCRT_SIGINT] != MSVCRT_SIG_IGN)
                sighandlers[MSVCRT_SIGINT](MSVCRT_SIGINT);
Juan Lang's avatar
Juan Lang committed
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
            ret = TRUE;
        }
        break;
    }
    return ret;
}

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

/* The exception codes are actually NTSTATUS values */
struct
{
    NTSTATUS status;
    int signal;
} float_exception_map[] = {
 { EXCEPTION_FLT_DENORMAL_OPERAND, _FPE_DENORMAL },
 { EXCEPTION_FLT_DIVIDE_BY_ZERO, _FPE_ZERODIVIDE },
 { EXCEPTION_FLT_INEXACT_RESULT, _FPE_INEXACT },
 { EXCEPTION_FLT_INVALID_OPERATION, _FPE_INVALID },
 { EXCEPTION_FLT_OVERFLOW, _FPE_OVERFLOW },
 { EXCEPTION_FLT_STACK_CHECK, _FPE_STACKOVERFLOW },
 { EXCEPTION_FLT_UNDERFLOW, _FPE_UNDERFLOW },
};

static LONG WINAPI msvcrt_exception_filter(struct _EXCEPTION_POINTERS *except)
{
    LONG ret = EXCEPTION_CONTINUE_SEARCH;

433 434 435
    if (!except || !except->ExceptionRecord)
        return EXCEPTION_CONTINUE_SEARCH;

Juan Lang's avatar
Juan Lang committed
436 437 438
    switch (except->ExceptionRecord->ExceptionCode)
    {
    case EXCEPTION_ACCESS_VIOLATION:
439
        if (sighandlers[MSVCRT_SIGSEGV])
Juan Lang's avatar
Juan Lang committed
440
        {
441 442
            if (sighandlers[MSVCRT_SIGSEGV] != MSVCRT_SIG_IGN)
                sighandlers[MSVCRT_SIGSEGV](MSVCRT_SIGSEGV);
Juan Lang's avatar
Juan Lang committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
            ret = EXCEPTION_CONTINUE_EXECUTION;
        }
        break;
    /* According to
     * http://msdn.microsoft.com/library/en-us/vclib/html/_CRT_signal.asp
     * 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:
458
        if (sighandlers[MSVCRT_SIGFPE])
Juan Lang's avatar
Juan Lang committed
459
        {
460
            if (sighandlers[MSVCRT_SIGFPE] != MSVCRT_SIG_IGN)
Juan Lang's avatar
Juan Lang committed
461 462 463
            {
                int i, float_signal = _FPE_INVALID;

464
                float_handler handler = (float_handler)sighandlers[MSVCRT_SIGFPE];
Juan Lang's avatar
Juan Lang committed
465 466 467 468 469 470 471 472
                for (i = 0; i < sizeof(float_exception_map) /
                 sizeof(float_exception_map[0]); i++)
                    if (float_exception_map[i].status ==
                     except->ExceptionRecord->ExceptionCode)
                    {
                        float_signal = float_exception_map[i].signal;
                        break;
                    }
473
                handler(MSVCRT_SIGFPE, float_signal);
Juan Lang's avatar
Juan Lang committed
474 475 476 477 478
            }
            ret = EXCEPTION_CONTINUE_EXECUTION;
        }
        break;
    case EXCEPTION_ILLEGAL_INSTRUCTION:
479
        if (sighandlers[MSVCRT_SIGILL])
Juan Lang's avatar
Juan Lang committed
480
        {
481 482
            if (sighandlers[MSVCRT_SIGILL] != MSVCRT_SIG_IGN)
                sighandlers[MSVCRT_SIGILL](MSVCRT_SIGILL);
Juan Lang's avatar
Juan Lang committed
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
            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);
}

502 503
/*********************************************************************
 *		signal (MSVCRT.@)
Juan Lang's avatar
Juan Lang committed
504 505 506 507
 * MS signal handling is described here:
 * http://msdn.microsoft.com/library/en-us/vclib/html/_CRT_signal.asp
 * Some signals may never be generated except through an explicit call to
 * raise.
508
 */
509
MSVCRT___sighandler_t CDECL MSVCRT_signal(int sig, MSVCRT___sighandler_t func)
510
{
511
    MSVCRT___sighandler_t ret = MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
512 513 514

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

515
    if (func == MSVCRT_SIG_ERR) return MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
516 517 518 519 520 521

    switch (sig)
    {
    /* Cases handled internally.  Note SIGTERM is never generated by Windows,
     * so we effectively mask it.
     */
522 523 524 525 526 527
    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
528 529 530 531
        ret = sighandlers[sig];
        sighandlers[sig] = func;
        break;
    default:
532
        ret = MSVCRT_SIG_ERR;
Juan Lang's avatar
Juan Lang committed
533 534
    }
    return ret;
535
}
536 537 538 539

/*********************************************************************
 *		_XcptFilter (MSVCRT.@)
 */
540
int CDECL _XcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr)
541
{
542
    TRACE("(%08x,%p)\n", ex, ptr);
543 544 545
    /* I assume ptr->ExceptionRecord->ExceptionCode is the same as ex */
    return msvcrt_exception_filter(ptr);
}