msvcrt: Return child exit code in _pclose function.
[wine] / dlls / winecrt0 / exception.c
1 /*
2  * Support functions for Wine exception handling
3  *
4  * Copyright (c) 1999, 2010 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include <stdarg.h>
23 #include "winternl.h"
24 #include "wine/exception.h"
25
26 #if defined(__x86_64__) && defined(__ASM_GLOBAL_FUNC)
27 extern void __wine_unwind_trampoline(void);
28 /* we need an extra call to make sure the stack is correctly aligned */
29 __ASM_GLOBAL_FUNC( __wine_unwind_trampoline, "callq *%rax" );
30 #endif
31
32 /* wrapper for RtlUnwind since it clobbers registers on Windows */
33 void __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, EXCEPTION_RECORD *record,
34                         void (*target)(void) )
35 {
36 #if defined(__GNUC__) && defined(__i386__)
37     int dummy1, dummy2, dummy3, dummy4;
38     __asm__ __volatile__("pushl %%ebp\n\t"
39                          "pushl %%ebx\n\t"
40                          "pushl $0\n\t"
41                          "pushl %3\n\t"
42                          "pushl %2\n\t"
43                          "pushl %1\n\t"
44                          "call *%0\n\t"
45                          "popl %%ebx\n\t"
46                          "popl %%ebp"
47                          : "=a" (dummy1), "=S" (dummy2), "=D" (dummy3), "=c" (dummy4)
48                          : "0" (RtlUnwind), "1" (frame), "2" (target), "3" (record)
49                          : "edx", "memory" );
50 #elif defined(__x86_64__) && defined(__ASM_GLOBAL_FUNC)
51     RtlUnwind( frame, __wine_unwind_trampoline, record, target );
52 #else
53     RtlUnwind( frame, target, record, 0 );
54 #endif
55     for (;;) target();
56 }
57
58 static void DECLSPEC_NORETURN unwind_target(void)
59 {
60     __WINE_FRAME *wine_frame = (__WINE_FRAME *)__wine_get_frame();
61     __wine_pop_frame( &wine_frame->frame );
62     siglongjmp( wine_frame->jmp, 1 );
63 }
64
65 static void DECLSPEC_NORETURN unwind_frame( EXCEPTION_RECORD *record,
66                                             EXCEPTION_REGISTRATION_RECORD *frame )
67 {
68     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
69
70     /* hack to make GetExceptionCode() work in handler */
71     wine_frame->ExceptionCode   = record->ExceptionCode;
72     wine_frame->ExceptionRecord = wine_frame;
73
74     __wine_rtl_unwind( frame, record, unwind_target );
75 }
76
77 DWORD __wine_exception_handler( EXCEPTION_RECORD *record,
78                                 EXCEPTION_REGISTRATION_RECORD *frame,
79                                 CONTEXT *context,
80                                 EXCEPTION_REGISTRATION_RECORD **pdispatcher )
81 {
82     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
83     EXCEPTION_POINTERS ptrs;
84
85     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
86         return ExceptionContinueSearch;
87
88     ptrs.ExceptionRecord = record;
89     ptrs.ContextRecord = context;
90     switch(wine_frame->u.filter( &ptrs ))
91     {
92     case EXCEPTION_CONTINUE_SEARCH:
93         return ExceptionContinueSearch;
94     case EXCEPTION_CONTINUE_EXECUTION:
95         return ExceptionContinueExecution;
96     case EXCEPTION_EXECUTE_HANDLER:
97         break;
98     }
99     unwind_frame( record, frame );
100 }
101
102 DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record,
103                                            EXCEPTION_REGISTRATION_RECORD *frame,
104                                            CONTEXT *context,
105                                            EXCEPTION_REGISTRATION_RECORD **pdispatcher )
106 {
107     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
108         return ExceptionContinueSearch;
109     if (record->ExceptionCode != STATUS_ACCESS_VIOLATION)
110         return ExceptionContinueSearch;
111     unwind_frame( record, frame );
112 }
113
114 DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record,
115                                     EXCEPTION_REGISTRATION_RECORD *frame,
116                                     CONTEXT *context,
117                                     EXCEPTION_REGISTRATION_RECORD **pdispatcher )
118 {
119     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
120         return ExceptionContinueSearch;
121     unwind_frame( record, frame );
122 }
123
124 DWORD __wine_finally_handler( EXCEPTION_RECORD *record,
125                               EXCEPTION_REGISTRATION_RECORD *frame,
126                               CONTEXT *context,
127                               EXCEPTION_REGISTRATION_RECORD **pdispatcher )
128 {
129     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
130     {
131         __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
132         wine_frame->u.finally_func( FALSE );
133     }
134     return ExceptionContinueSearch;
135 }