mshtml: Added IHTMLWindow2::focus implementation.
[wine] / dlls / msvcrt / except.c
1 /*
2  * msvcrt.dll exception handling
3  *
4  * Copyright 2000 Jon Griffiths
5  * Copyright 2005 Juan Lang
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * 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 #include <stdarg.h>
28
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winternl.h"
34 #include "wine/exception.h"
35 #include "msvcrt.h"
36 #include "excpt.h"
37 #include "wincon.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(seh);
41
42 /* VC++ extensions to Win32 SEH */
43 typedef struct _SCOPETABLE
44 {
45   int previousTryLevel;
46   int (*lpfnFilter)(PEXCEPTION_POINTERS);
47   int (*lpfnHandler)(void);
48 } SCOPETABLE, *PSCOPETABLE;
49
50 typedef struct _MSVCRT_EXCEPTION_FRAME
51 {
52   EXCEPTION_REGISTRATION_RECORD *prev;
53   void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*,
54                   PCONTEXT, PEXCEPTION_RECORD);
55   PSCOPETABLE scopetable;
56   int trylevel;
57   int _ebp;
58   PEXCEPTION_POINTERS xpointers;
59 } MSVCRT_EXCEPTION_FRAME;
60
61 typedef struct
62 {
63   int   gs_cookie_offset;
64   ULONG gs_cookie_xor;
65   int   eh_cookie_offset;
66   ULONG eh_cookie_xor;
67   SCOPETABLE entries[1];
68 } SCOPETABLE_V4;
69
70 #define TRYLEVEL_END (-1) /* End of trylevel list */
71
72 #if defined(__GNUC__) && defined(__i386__)
73 static inline void call_finally_block( void *code_block, void *base_ptr )
74 {
75     __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax"
76                           : : "a" (code_block), "g" (base_ptr));
77 }
78
79 static inline int call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *ebp )
80 {
81     int ret;
82     __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp"
83                           : "=a" (ret)
84                           : "0" (func), "r" (ebp), "r" (arg)
85                           : "ecx", "edx", "memory" );
86     return ret;
87 }
88
89 static inline int call_unwind_func( int (*func)(void), void *ebp )
90 {
91     int ret;
92     __asm__ __volatile__ ("pushl %%ebp\n\t"
93                           "pushl %%ebx\n\t"
94                           "pushl %%esi\n\t"
95                           "pushl %%edi\n\t"
96                           "movl %2,%%ebp\n\t"
97                           "call *%0\n\t"
98                           "popl %%edi\n\t"
99                           "popl %%esi\n\t"
100                           "popl %%ebx\n\t"
101                           "popl %%ebp"
102                           : "=a" (ret)
103                           : "0" (func), "r" (ebp)
104                           : "ecx", "edx", "memory" );
105     return ret;
106 }
107
108 #endif
109
110
111 #ifdef __i386__
112
113 static const SCOPETABLE_V4 *get_scopetable_v4( MSVCRT_EXCEPTION_FRAME *frame, ULONG_PTR cookie )
114 {
115     return (const SCOPETABLE_V4 *)((ULONG_PTR)frame->scopetable ^ cookie);
116 }
117
118 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
119                                    EXCEPTION_REGISTRATION_RECORD* frame,
120                                    PCONTEXT context,
121                                    EXCEPTION_REGISTRATION_RECORD** dispatch)
122 {
123   if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
124     return ExceptionContinueSearch;
125   *dispatch = frame;
126   return ExceptionCollidedUnwind;
127 }
128
129
130 /*********************************************************************
131  *              _EH_prolog (MSVCRT.@)
132  */
133
134 /* Provided for VC++ binary compatibility only */
135 __ASM_GLOBAL_FUNC(_EH_prolog,
136                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")  /* skip ret addr */
137                   "pushl $-1\n\t"
138                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
139                   "pushl %eax\n\t"
140                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
141                   "pushl %fs:0\n\t"
142                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
143                   "movl  %esp, %fs:0\n\t"
144                   "movl  12(%esp), %eax\n\t"
145                   "movl  %ebp, 12(%esp)\n\t"
146                   "leal  12(%esp), %ebp\n\t"
147                   "pushl %eax\n\t"
148                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
149                   "ret")
150
151 static void msvcrt_local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp)
152 {
153   EXCEPTION_REGISTRATION_RECORD reg;
154
155   TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
156
157   /* Register a handler in case of a nested exception */
158   reg.Handler = MSVCRT_nested_handler;
159   reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
160   __wine_push_frame(&reg);
161
162   while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
163   {
164       int level = frame->trylevel;
165       frame->trylevel = frame->scopetable[level].previousTryLevel;
166       if (!frame->scopetable[level].lpfnFilter)
167       {
168           TRACE( "__try block cleanup level %d handler %p ebp %p\n",
169                  level, frame->scopetable[level].lpfnHandler, ebp );
170           call_unwind_func( frame->scopetable[level].lpfnHandler, ebp );
171       }
172   }
173   __wine_pop_frame(&reg);
174   TRACE("unwound OK\n");
175 }
176
177 static void msvcrt_local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp )
178 {
179     EXCEPTION_REGISTRATION_RECORD reg;
180     const SCOPETABLE_V4 *scopetable = get_scopetable_v4( frame, *cookie );
181
182     TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
183
184     /* Register a handler in case of a nested exception */
185     reg.Handler = MSVCRT_nested_handler;
186     reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
187     __wine_push_frame(&reg);
188
189     while (frame->trylevel != -2 && frame->trylevel != trylevel)
190     {
191         int level = frame->trylevel;
192         frame->trylevel = scopetable->entries[level].previousTryLevel;
193         if (!scopetable->entries[level].lpfnFilter)
194         {
195             TRACE( "__try block cleanup level %d handler %p ebp %p\n",
196                    level, scopetable->entries[level].lpfnHandler, ebp );
197             call_unwind_func( scopetable->entries[level].lpfnHandler, ebp );
198         }
199     }
200     __wine_pop_frame(&reg);
201     TRACE("unwound OK\n");
202 }
203
204 /*******************************************************************
205  *              _local_unwind2 (MSVCRT.@)
206  */
207 void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
208 {
209     msvcrt_local_unwind2( frame, trylevel, &frame->_ebp );
210 }
211
212 /*******************************************************************
213  *              _local_unwind4 (MSVCRT.@)
214  */
215 void CDECL _local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel )
216 {
217     msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp );
218 }
219
220 /*******************************************************************
221  *              _global_unwind2 (MSVCRT.@)
222  */
223 void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame)
224 {
225     TRACE("(%p)\n",frame);
226     RtlUnwind( frame, 0, 0, 0 );
227 }
228
229 /*********************************************************************
230  *              _except_handler2 (MSVCRT.@)
231  */
232 int CDECL _except_handler2(PEXCEPTION_RECORD rec,
233                            EXCEPTION_REGISTRATION_RECORD* frame,
234                            PCONTEXT context,
235                            EXCEPTION_REGISTRATION_RECORD** dispatcher)
236 {
237   FIXME("exception %x flags=%x at %p handler=%p %p %p stub\n",
238         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
239         frame->Handler, context, dispatcher);
240   return ExceptionContinueSearch;
241 }
242
243 /*********************************************************************
244  *              _except_handler3 (MSVCRT.@)
245  */
246 int CDECL _except_handler3(PEXCEPTION_RECORD rec,
247                            MSVCRT_EXCEPTION_FRAME* frame,
248                            PCONTEXT context, void* dispatcher)
249 {
250   int retval, trylevel;
251   EXCEPTION_POINTERS exceptPtrs;
252   PSCOPETABLE pScopeTable;
253
254   TRACE("exception %x flags=%x at %p handler=%p %p %p semi-stub\n",
255         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
256         frame->handler, context, dispatcher);
257
258   __asm__ __volatile__ ("cld");
259
260   if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
261   {
262     /* Unwinding the current frame */
263     msvcrt_local_unwind2(frame, TRYLEVEL_END, &frame->_ebp);
264     TRACE("unwound current frame, returning ExceptionContinueSearch\n");
265     return ExceptionContinueSearch;
266   }
267   else
268   {
269     /* Hunting for handler */
270     exceptPtrs.ExceptionRecord = rec;
271     exceptPtrs.ContextRecord = context;
272     *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
273     trylevel = frame->trylevel;
274     pScopeTable = frame->scopetable;
275
276     while (trylevel != TRYLEVEL_END)
277     {
278       TRACE( "level %d prev %d filter %p\n", trylevel, pScopeTable[trylevel].previousTryLevel,
279              pScopeTable[trylevel].lpfnFilter );
280       if (pScopeTable[trylevel].lpfnFilter)
281       {
282         retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
283
284         TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
285               "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
286               "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
287
288         if (retval == EXCEPTION_CONTINUE_EXECUTION)
289           return ExceptionContinueExecution;
290
291         if (retval == EXCEPTION_EXECUTE_HANDLER)
292         {
293           /* Unwind all higher frames, this one will handle the exception */
294           _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
295           msvcrt_local_unwind2(frame, trylevel, &frame->_ebp);
296
297           /* Set our trylevel to the enclosing block, and call the __finally
298            * code, which won't return
299            */
300           frame->trylevel = pScopeTable[trylevel].previousTryLevel;
301           TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
302           call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
303           ERR("Returned from __finally block - expect crash!\n");
304        }
305       }
306       trylevel = pScopeTable[trylevel].previousTryLevel;
307     }
308   }
309   TRACE("reached TRYLEVEL_END, returning ExceptionContinueSearch\n");
310   return ExceptionContinueSearch;
311 }
312
313 /*********************************************************************
314  *              _except_handler4_common (MSVCRT.@)
315  */
316 int CDECL _except_handler4_common( ULONG *cookie, void (*check_cookie)(void),
317                                    EXCEPTION_RECORD *rec, MSVCRT_EXCEPTION_FRAME *frame,
318                                    CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
319 {
320     int retval, trylevel;
321     EXCEPTION_POINTERS exceptPtrs;
322     const SCOPETABLE_V4 *scope_table = get_scopetable_v4( frame, *cookie );
323
324     TRACE( "exception %x flags=%x at %p handler=%p %p %p cookie=%x scope table=%p cookies=%d/%x,%d/%x\n",
325            rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
326            frame->handler, context, dispatcher, *cookie, scope_table,
327            scope_table->gs_cookie_offset, scope_table->gs_cookie_xor,
328            scope_table->eh_cookie_offset, scope_table->eh_cookie_xor );
329
330     /* FIXME: no cookie validation yet */
331
332     if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
333     {
334         /* Unwinding the current frame */
335         msvcrt_local_unwind4( cookie, frame, -2, &frame->_ebp );
336         TRACE("unwound current frame, returning ExceptionContinueSearch\n");
337         return ExceptionContinueSearch;
338     }
339     else
340     {
341         /* Hunting for handler */
342         exceptPtrs.ExceptionRecord = rec;
343         exceptPtrs.ContextRecord = context;
344         *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
345         trylevel = frame->trylevel;
346
347         while (trylevel != -2)
348         {
349             TRACE( "level %d prev %d filter %p\n", trylevel,
350                    scope_table->entries[trylevel].previousTryLevel,
351                    scope_table->entries[trylevel].lpfnFilter );
352             if (scope_table->entries[trylevel].lpfnFilter)
353             {
354                 retval = call_filter( scope_table->entries[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
355
356                 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
357                       "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
358                       "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
359
360                 if (retval == EXCEPTION_CONTINUE_EXECUTION)
361                     return ExceptionContinueExecution;
362
363                 if (retval == EXCEPTION_EXECUTE_HANDLER)
364                 {
365                     /* Unwind all higher frames, this one will handle the exception */
366                     _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
367                     msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp );
368
369                     /* Set our trylevel to the enclosing block, and call the __finally
370                      * code, which won't return
371                      */
372                     frame->trylevel = scope_table->entries[trylevel].previousTryLevel;
373                     TRACE("__finally block %p\n",scope_table->entries[trylevel].lpfnHandler);
374                     call_finally_block(scope_table->entries[trylevel].lpfnHandler, &frame->_ebp);
375                     ERR("Returned from __finally block - expect crash!\n");
376                 }
377             }
378             trylevel = scope_table->entries[trylevel].previousTryLevel;
379         }
380     }
381     TRACE("reached -2, returning ExceptionContinueSearch\n");
382     return ExceptionContinueSearch;
383 }
384
385
386 /*
387  * setjmp/longjmp implementation
388  */
389
390 #define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
391 typedef void (__stdcall *MSVCRT_unwind_function)(const struct MSVCRT___JUMP_BUFFER *);
392
393 /* define an entrypoint for setjmp/setjmp3 that stores the registers in the jmp buf */
394 /* and then jumps to the C backend function */
395 #define DEFINE_SETJMP_ENTRYPOINT(name) \
396     __ASM_GLOBAL_FUNC( name, \
397                        "movl 4(%esp),%ecx\n\t"   /* jmp_buf */      \
398                        "movl %ebp,0(%ecx)\n\t"   /* jmp_buf.Ebp */  \
399                        "movl %ebx,4(%ecx)\n\t"   /* jmp_buf.Ebx */  \
400                        "movl %edi,8(%ecx)\n\t"   /* jmp_buf.Edi */  \
401                        "movl %esi,12(%ecx)\n\t"  /* jmp_buf.Esi */  \
402                        "movl %esp,16(%ecx)\n\t"  /* jmp_buf.Esp */  \
403                        "movl 0(%esp),%eax\n\t"                      \
404                        "movl %eax,20(%ecx)\n\t"  /* jmp_buf.Eip */  \
405                        "jmp " __ASM_NAME("__regs_") # name )
406
407 /* restore the registers from the jmp buf upon longjmp */
408 extern void DECLSPEC_NORETURN longjmp_set_regs( struct MSVCRT___JUMP_BUFFER *jmp, int retval );
409 __ASM_GLOBAL_FUNC( longjmp_set_regs,
410                    "movl 4(%esp),%ecx\n\t"   /* jmp_buf */
411                    "movl 8(%esp),%eax\n\t"   /* retval */
412                    "movl 0(%ecx),%ebp\n\t"   /* jmp_buf.Ebp */
413                    "movl 4(%ecx),%ebx\n\t"   /* jmp_buf.Ebx */
414                    "movl 8(%ecx),%edi\n\t"   /* jmp_buf.Edi */
415                    "movl 12(%ecx),%esi\n\t"  /* jmp_buf.Esi */
416                    "movl 16(%ecx),%esp\n\t"  /* jmp_buf.Esp */
417                    "addl $4,%esp\n\t"        /* get rid of return address */
418                    "jmp *20(%ecx)\n\t"       /* jmp_buf.Eip */ )
419
420 /*
421  * The signatures of the setjmp/longjmp functions do not match that
422  * declared in the setjmp header so they don't follow the regular naming
423  * convention to avoid conflicts.
424  */
425
426 /*******************************************************************
427  *              _setjmp (MSVCRT.@)
428  */
429 DEFINE_SETJMP_ENTRYPOINT(MSVCRT__setjmp)
430 int CDECL __regs_MSVCRT__setjmp(struct MSVCRT___JUMP_BUFFER *jmp)
431 {
432     jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
433     if (jmp->Registration == ~0UL)
434         jmp->TryLevel = TRYLEVEL_END;
435     else
436         jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
437
438     TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
439           jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
440     return 0;
441 }
442
443 /*******************************************************************
444  *              _setjmp3 (MSVCRT.@)
445  */
446 DEFINE_SETJMP_ENTRYPOINT( MSVCRT__setjmp3 )
447 int CDECL __regs_MSVCRT__setjmp3(struct MSVCRT___JUMP_BUFFER *jmp, int nb_args, ...)
448 {
449     jmp->Cookie = MSVCRT_JMP_MAGIC;
450     jmp->UnwindFunc = 0;
451     jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
452     if (jmp->Registration == ~0UL)
453     {
454         jmp->TryLevel = TRYLEVEL_END;
455     }
456     else
457     {
458         int i;
459         va_list args;
460
461         va_start( args, nb_args );
462         if (nb_args > 0) jmp->UnwindFunc = va_arg( args, unsigned long );
463         if (nb_args > 1) jmp->TryLevel = va_arg( args, unsigned long );
464         else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
465         for (i = 0; i < 6 && i < nb_args - 2; i++)
466             jmp->UnwindData[i] = va_arg( args, unsigned long );
467         va_end( args );
468     }
469
470     TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
471           jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
472     return 0;
473 }
474
475 /*********************************************************************
476  *              longjmp (MSVCRT.@)
477  */
478 void CDECL MSVCRT_longjmp(struct MSVCRT___JUMP_BUFFER *jmp, int retval)
479 {
480     unsigned long cur_frame = 0;
481
482     TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx retval=%08x\n",
483           jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration, retval );
484
485     cur_frame=(unsigned long)NtCurrentTeb()->Tib.ExceptionList;
486     TRACE("cur_frame=%lx\n",cur_frame);
487
488     if (cur_frame != jmp->Registration)
489         _global_unwind2((EXCEPTION_REGISTRATION_RECORD*)jmp->Registration);
490
491     if (jmp->Registration)
492     {
493         if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
494             jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
495         {
496             MSVCRT_unwind_function unwind_func;
497
498             unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
499             unwind_func(jmp);
500         }
501         else
502             msvcrt_local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
503                                  jmp->TryLevel, (void *)jmp->Ebp);
504     }
505
506     if (!retval)
507         retval = 1;
508
509     longjmp_set_regs( jmp, retval );
510 }
511
512 /*********************************************************************
513  *              _seh_longjmp_unwind (MSVCRT.@)
514  */
515 void __stdcall _seh_longjmp_unwind(struct MSVCRT___JUMP_BUFFER *jmp)
516 {
517     msvcrt_local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel, (void *)jmp->Ebp );
518 }
519
520 #elif defined(__x86_64__)
521
522 /*******************************************************************
523  *              _setjmp (MSVCRT.@)
524  */
525 __ASM_GLOBAL_FUNC( MSVCRT__setjmp,
526                    "xorq %rdx,%rdx\n\t"  /* frame */
527                    "jmp " __ASM_NAME("MSVCRT__setjmpex") );
528
529 /*******************************************************************
530  *              _setjmpex (MSVCRT.@)
531  */
532 __ASM_GLOBAL_FUNC( MSVCRT__setjmpex,
533                    "movq %rdx,(%rcx)\n\t"          /* jmp_buf->Frame */
534                    "movq %rbx,0x8(%rcx)\n\t"       /* jmp_buf->Rbx */
535                    "leaq 0x8(%rsp),%rax\n\t"
536                    "movq %rax,0x10(%rcx)\n\t"      /* jmp_buf->Rsp */
537                    "movq %rbp,0x18(%rcx)\n\t"      /* jmp_buf->Rbp */
538                    "movq %rsi,0x20(%rcx)\n\t"      /* jmp_buf->Rsi */
539                    "movq %rdi,0x28(%rcx)\n\t"      /* jmp_buf->Rdi */
540                    "movq %r12,0x30(%rcx)\n\t"      /* jmp_buf->R12 */
541                    "movq %r13,0x38(%rcx)\n\t"      /* jmp_buf->R13 */
542                    "movq %r14,0x40(%rcx)\n\t"      /* jmp_buf->R14 */
543                    "movq %r15,0x48(%rcx)\n\t"      /* jmp_buf->R15 */
544                    "movq (%rsp),%rax\n\t"
545                    "movq %rax,0x50(%rcx)\n\t"      /* jmp_buf->Rip */
546                    "movdqa %xmm6,0x60(%rcx)\n\t"   /* jmp_buf->Xmm6 */
547                    "movdqa %xmm7,0x70(%rcx)\n\t"   /* jmp_buf->Xmm7 */
548                    "movdqa %xmm8,0x80(%rcx)\n\t"   /* jmp_buf->Xmm8 */
549                    "movdqa %xmm9,0x90(%rcx)\n\t"   /* jmp_buf->Xmm9 */
550                    "movdqa %xmm10,0xa0(%rcx)\n\t"  /* jmp_buf->Xmm10 */
551                    "movdqa %xmm11,0xb0(%rcx)\n\t"  /* jmp_buf->Xmm11 */
552                    "movdqa %xmm12,0xc0(%rcx)\n\t"  /* jmp_buf->Xmm12 */
553                    "movdqa %xmm13,0xd0(%rcx)\n\t"  /* jmp_buf->Xmm13 */
554                    "movdqa %xmm14,0xe0(%rcx)\n\t"  /* jmp_buf->Xmm14 */
555                    "movdqa %xmm15,0xf0(%rcx)\n\t"  /* jmp_buf->Xmm15 */
556                    "xorq %rax,%rax\n\t"
557                    "retq" );
558
559
560 extern void DECLSPEC_NORETURN CDECL longjmp_set_regs( struct MSVCRT___JUMP_BUFFER *jmp, int retval );
561 __ASM_GLOBAL_FUNC( longjmp_set_regs,
562                    "movq %rdx,%rax\n\t"            /* retval */
563                    "movq 0x8(%rcx),%rbx\n\t"       /* jmp_buf->Rbx */
564                    "movq 0x18(%rcx),%rbp\n\t"      /* jmp_buf->Rbp */
565                    "movq 0x20(%rcx),%rsi\n\t"      /* jmp_buf->Rsi */
566                    "movq 0x28(%rcx),%rdi\n\t"      /* jmp_buf->Rdi */
567                    "movq 0x30(%rcx),%r12\n\t"      /* jmp_buf->R12 */
568                    "movq 0x38(%rcx),%r13\n\t"      /* jmp_buf->R13 */
569                    "movq 0x40(%rcx),%r14\n\t"      /* jmp_buf->R14 */
570                    "movq 0x48(%rcx),%r15\n\t"      /* jmp_buf->R15 */
571                    "movdqa 0x60(%rcx),%xmm6\n\t"   /* jmp_buf->Xmm6 */
572                    "movdqa 0x70(%rcx),%xmm7\n\t"   /* jmp_buf->Xmm7 */
573                    "movdqa 0x80(%rcx),%xmm8\n\t"   /* jmp_buf->Xmm8 */
574                    "movdqa 0x90(%rcx),%xmm9\n\t"   /* jmp_buf->Xmm9 */
575                    "movdqa 0xa0(%rcx),%xmm10\n\t"  /* jmp_buf->Xmm10 */
576                    "movdqa 0xb0(%rcx),%xmm11\n\t"  /* jmp_buf->Xmm11 */
577                    "movdqa 0xc0(%rcx),%xmm12\n\t"  /* jmp_buf->Xmm12 */
578                    "movdqa 0xd0(%rcx),%xmm13\n\t"  /* jmp_buf->Xmm13 */
579                    "movdqa 0xe0(%rcx),%xmm14\n\t"  /* jmp_buf->Xmm14 */
580                    "movdqa 0xf0(%rcx),%xmm15\n\t"  /* jmp_buf->Xmm15 */
581                    "movq 0x50(%rcx),%rdx\n\t"      /* jmp_buf->Rip */
582                    "movq 0x10(%rcx),%rsp\n\t"      /* jmp_buf->Rsp */
583                    "jmp *%rdx" );
584
585 /*******************************************************************
586  *              longjmp (MSVCRT.@)
587  */
588 void __cdecl MSVCRT_longjmp( struct MSVCRT___JUMP_BUFFER *jmp, int retval )
589 {
590     EXCEPTION_RECORD rec;
591
592     if (!retval) retval = 1;
593     if (jmp->Frame)
594     {
595         rec.ExceptionCode = STATUS_LONGJUMP;
596         rec.ExceptionFlags = 0;
597         rec.ExceptionRecord = NULL;
598         rec.ExceptionAddress = NULL;
599         rec.NumberParameters = 1;
600         rec.ExceptionInformation[0] = (DWORD_PTR)jmp;
601         RtlUnwind( (void *)jmp->Frame, (void *)jmp->Rip, &rec, IntToPtr(retval) );
602     }
603     longjmp_set_regs( jmp, retval );
604 }
605
606 #endif /* __x86_64__ */
607
608 static MSVCRT___sighandler_t sighandlers[MSVCRT_NSIG] = { MSVCRT_SIG_DFL };
609
610 static BOOL WINAPI msvcrt_console_handler(DWORD ctrlType)
611 {
612     BOOL ret = FALSE;
613
614     switch (ctrlType)
615     {
616     case CTRL_C_EVENT:
617         if (sighandlers[MSVCRT_SIGINT])
618         {
619             if (sighandlers[MSVCRT_SIGINT] != MSVCRT_SIG_IGN)
620                 sighandlers[MSVCRT_SIGINT](MSVCRT_SIGINT);
621             ret = TRUE;
622         }
623         break;
624     }
625     return ret;
626 }
627
628 typedef void (CDECL *float_handler)(int, int);
629
630 /* The exception codes are actually NTSTATUS values */
631 static const struct
632 {
633     NTSTATUS status;
634     int signal;
635 } float_exception_map[] = {
636  { EXCEPTION_FLT_DENORMAL_OPERAND, MSVCRT__FPE_DENORMAL },
637  { EXCEPTION_FLT_DIVIDE_BY_ZERO, MSVCRT__FPE_ZERODIVIDE },
638  { EXCEPTION_FLT_INEXACT_RESULT, MSVCRT__FPE_INEXACT },
639  { EXCEPTION_FLT_INVALID_OPERATION, MSVCRT__FPE_INVALID },
640  { EXCEPTION_FLT_OVERFLOW, MSVCRT__FPE_OVERFLOW },
641  { EXCEPTION_FLT_STACK_CHECK, MSVCRT__FPE_STACKOVERFLOW },
642  { EXCEPTION_FLT_UNDERFLOW, MSVCRT__FPE_UNDERFLOW },
643 };
644
645 static LONG WINAPI msvcrt_exception_filter(struct _EXCEPTION_POINTERS *except)
646 {
647     LONG ret = EXCEPTION_CONTINUE_SEARCH;
648     MSVCRT___sighandler_t handler;
649
650     if (!except || !except->ExceptionRecord)
651         return EXCEPTION_CONTINUE_SEARCH;
652
653     switch (except->ExceptionRecord->ExceptionCode)
654     {
655     case EXCEPTION_ACCESS_VIOLATION:
656         if ((handler = sighandlers[MSVCRT_SIGSEGV]) != MSVCRT_SIG_DFL)
657         {
658             if (handler != MSVCRT_SIG_IGN)
659             {
660                 sighandlers[MSVCRT_SIGSEGV] = MSVCRT_SIG_DFL;
661                 handler(MSVCRT_SIGSEGV);
662             }
663             ret = EXCEPTION_CONTINUE_EXECUTION;
664         }
665         break;
666     /* According to msdn,
667      * the FPE signal handler takes as a second argument the type of
668      * floating point exception.
669      */
670     case EXCEPTION_FLT_DENORMAL_OPERAND:
671     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
672     case EXCEPTION_FLT_INEXACT_RESULT:
673     case EXCEPTION_FLT_INVALID_OPERATION:
674     case EXCEPTION_FLT_OVERFLOW:
675     case EXCEPTION_FLT_STACK_CHECK:
676     case EXCEPTION_FLT_UNDERFLOW:
677         if ((handler = sighandlers[MSVCRT_SIGFPE]) != MSVCRT_SIG_DFL)
678         {
679             if (handler != MSVCRT_SIG_IGN)
680             {
681                 unsigned int i;
682                 int float_signal = MSVCRT__FPE_INVALID;
683
684                 sighandlers[MSVCRT_SIGFPE] = MSVCRT_SIG_DFL;
685                 for (i = 0; i < sizeof(float_exception_map) /
686                          sizeof(float_exception_map[0]); i++)
687                 {
688                     if (float_exception_map[i].status ==
689                         except->ExceptionRecord->ExceptionCode)
690                     {
691                         float_signal = float_exception_map[i].signal;
692                         break;
693                     }
694                 }
695                 ((float_handler)handler)(MSVCRT_SIGFPE, float_signal);
696             }
697             ret = EXCEPTION_CONTINUE_EXECUTION;
698         }
699         break;
700     case EXCEPTION_ILLEGAL_INSTRUCTION:
701     case EXCEPTION_PRIV_INSTRUCTION:
702         if ((handler = sighandlers[MSVCRT_SIGILL]) != MSVCRT_SIG_DFL)
703         {
704             if (handler != MSVCRT_SIG_IGN)
705             {
706                 sighandlers[MSVCRT_SIGILL] = MSVCRT_SIG_DFL;
707                 handler(MSVCRT_SIGILL);
708             }
709             ret = EXCEPTION_CONTINUE_EXECUTION;
710         }
711         break;
712     }
713     return ret;
714 }
715
716 void msvcrt_init_signals(void)
717 {
718     SetConsoleCtrlHandler(msvcrt_console_handler, TRUE);
719     SetUnhandledExceptionFilter(msvcrt_exception_filter);
720 }
721
722 void msvcrt_free_signals(void)
723 {
724     SetConsoleCtrlHandler(msvcrt_console_handler, FALSE);
725     SetUnhandledExceptionFilter(NULL);
726 }
727
728 /*********************************************************************
729  *              signal (MSVCRT.@)
730  * Some signals may never be generated except through an explicit call to
731  * raise.
732  */
733 MSVCRT___sighandler_t CDECL MSVCRT_signal(int sig, MSVCRT___sighandler_t func)
734 {
735     MSVCRT___sighandler_t ret = MSVCRT_SIG_ERR;
736
737     TRACE("(%d, %p)\n", sig, func);
738
739     if (func == MSVCRT_SIG_ERR) return MSVCRT_SIG_ERR;
740
741     switch (sig)
742     {
743     /* Cases handled internally.  Note SIGTERM is never generated by Windows,
744      * so we effectively mask it.
745      */
746     case MSVCRT_SIGABRT:
747     case MSVCRT_SIGFPE:
748     case MSVCRT_SIGILL:
749     case MSVCRT_SIGSEGV:
750     case MSVCRT_SIGINT:
751     case MSVCRT_SIGTERM:
752     case MSVCRT_SIGBREAK:
753         ret = sighandlers[sig];
754         sighandlers[sig] = func;
755         break;
756     default:
757         ret = MSVCRT_SIG_ERR;
758     }
759     return ret;
760 }
761
762 /*********************************************************************
763  *              raise (MSVCRT.@)
764  */
765 int CDECL MSVCRT_raise(int sig)
766 {
767     MSVCRT___sighandler_t handler;
768
769     TRACE("(%d)\n", sig);
770
771     switch (sig)
772     {
773     case MSVCRT_SIGABRT:
774     case MSVCRT_SIGFPE:
775     case MSVCRT_SIGILL:
776     case MSVCRT_SIGSEGV:
777     case MSVCRT_SIGINT:
778     case MSVCRT_SIGTERM:
779     case MSVCRT_SIGBREAK:
780         handler = sighandlers[sig];
781         if (handler == MSVCRT_SIG_DFL) MSVCRT__exit(3);
782         if (handler != MSVCRT_SIG_IGN)
783         {
784             sighandlers[sig] = MSVCRT_SIG_DFL;
785             if (sig == MSVCRT_SIGFPE)
786                 ((float_handler)handler)(sig, MSVCRT__FPE_EXPLICITGEN);
787             else
788                 handler(sig);
789         }
790         break;
791     default:
792         return -1;
793     }
794     return 0;
795 }
796
797 /*********************************************************************
798  *              _XcptFilter (MSVCRT.@)
799  */
800 int CDECL _XcptFilter(NTSTATUS ex, PEXCEPTION_POINTERS ptr)
801 {
802     TRACE("(%08x,%p)\n", ex, ptr);
803     /* I assume ptr->ExceptionRecord->ExceptionCode is the same as ex */
804     return msvcrt_exception_filter(ptr);
805 }
806
807 /*********************************************************************
808  *              _abnormal_termination (MSVCRT.@)
809  */
810 int CDECL _abnormal_termination(void)
811 {
812   FIXME("(void)stub\n");
813   return 0;
814 }
815
816 /******************************************************************
817  *              MSVCRT___uncaught_exception
818  */
819 BOOL CDECL MSVCRT___uncaught_exception(void)
820 {
821     return FALSE;
822 }