Adjust the 'MSVCRT_' prefix to match the msvcrt headers
[wine] / dlls / msvcrt / except.c
1 /*
2  * msvcrt.dll exception handling
3  *
4  * Copyright 2000 Jon Griffiths
5  *
6  * See http://www.microsoft.com/msj/0197/exception/exception.htm,
7  * but don't believe all of it.
8  *
9  * FIXME: Incomplete support for nested exceptions/try block cleanup.
10  */
11 #include "ntddk.h"
12 #include "wine/exception.h"
13 #include "thread.h"
14 #include "msvcrt.h"
15
16 DEFAULT_DEBUG_CHANNEL(msvcrt);
17
18 typedef void (*MSVCRT_sig_handler_func)(void);
19
20 /* VC++ extensions to Win32 SEH */
21 typedef struct _SCOPETABLE
22 {
23   DWORD previousTryLevel;
24   int (*lpfnFilter)(PEXCEPTION_POINTERS);
25   int (*lpfnHandler)(void);
26 } SCOPETABLE, *PSCOPETABLE;
27
28 typedef struct _MSVCRT_EXCEPTION_FRAME
29 {
30   EXCEPTION_FRAME *prev;
31   void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
32                   PCONTEXT, PEXCEPTION_RECORD);
33   PSCOPETABLE scopetable;
34   DWORD trylevel;
35   int _ebp;
36   PEXCEPTION_POINTERS xpointers;
37 } MSVCRT_EXCEPTION_FRAME;
38
39 #define TRYLEVEL_END 0xff /* End of trylevel list */
40
41 #if defined(__GNUC__) && defined(__i386__)
42
43 #define CALL_FINALLY_BLOCK(code_block, base_ptr) \
44   __asm__ __volatile__ ("movl %0,%%eax; movl %1,%%ebp; call *%%eax" \
45                         : : "g" (code_block), "g" (base_ptr))
46
47 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
48                                    struct __EXCEPTION_FRAME* frame,
49                                    PCONTEXT context WINE_UNUSED,
50                                    struct __EXCEPTION_FRAME** dispatch)
51 {
52   if (rec->ExceptionFlags & 0x6)
53     return ExceptionContinueSearch;
54   *dispatch = frame;
55   return ExceptionCollidedUnwind;
56 }
57 #endif
58
59
60 /*********************************************************************
61  *              _XcptFilter (MSVCRT.@)
62  */
63 int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr)
64 {
65   FIXME("(%d,%p)semi-stub\n", ex, ptr);
66   return UnhandledExceptionFilter(ptr);
67 }
68
69 /*********************************************************************
70  *              _EH_prolog (MSVCRT.@)
71  */
72 #ifdef __i386__
73 /* Provided for VC++ binary compatability only */
74 __ASM_GLOBAL_FUNC(_EH_prolog,
75                   "pushl $0xff\n\t"
76                   "pushl %eax\n\t"
77                   "pushl %fs:0\n\t"
78                   "movl  %esp, %fs:0\n\t"
79                   "movl  12(%esp), %eax\n\t"
80                   "movl  %ebp, 12(%esp)\n\t"
81                   "leal  12(%esp), %ebp\n\t"
82                   "pushl %eax\n\t"
83                   "ret");
84 #endif
85
86 /*******************************************************************
87  *              _global_unwind2 (MSVCRT.@)
88  */
89 void _global_unwind2(PEXCEPTION_FRAME frame)
90 {
91     TRACE("(%p)\n",frame);
92     RtlUnwind( frame, 0, 0, 0 );
93 }
94
95 /*******************************************************************
96  *              _local_unwind2 (MSVCRT.@)
97  */
98 void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame,
99                     DWORD trylevel)
100 {
101   MSVCRT_EXCEPTION_FRAME *curframe = frame;
102   DWORD curtrylevel = 0xfe;
103   EXCEPTION_FRAME reg;
104
105   TRACE("(%p,%ld,%ld)\n",frame, frame->trylevel, trylevel);
106
107   /* Register a handler in case of a nested exception */
108   reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
109   reg.Prev = NtCurrentTeb()->except;
110   __wine_push_frame(&reg);
111
112   while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
113   {
114     curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
115     curframe = frame;
116     curframe->trylevel = curtrylevel;
117     if (!frame->scopetable[curtrylevel].lpfnFilter)
118     {
119       ERR("__try block cleanup not implemented - expect crash!\n");
120       /* FIXME: Remove current frame, set ebp, call
121        * frame->scopetable[curtrylevel].lpfnHandler()
122        */
123     }
124   }
125   __wine_pop_frame(&reg);
126   TRACE("unwound OK\n");
127 }
128
129 /*********************************************************************
130  *              _except_handler2 (MSVCRT.@)
131  */
132 int _except_handler2(PEXCEPTION_RECORD rec,
133                      PEXCEPTION_FRAME frame,
134                      PCONTEXT context,
135                      PEXCEPTION_FRAME* dispatcher)
136 {
137   FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
138         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
139         frame->Handler, context, dispatcher);
140   return ExceptionContinueSearch;
141 }
142
143 /*********************************************************************
144  *              _except_handler3 (MSVCRT.@)
145  */
146 int _except_handler3(PEXCEPTION_RECORD rec,
147                      MSVCRT_EXCEPTION_FRAME* frame,
148                      PCONTEXT context, void* dispatcher)
149 {
150 #if defined(__GNUC__) && defined(__i386__)
151   long retval, trylevel;
152   EXCEPTION_POINTERS exceptPtrs;
153   PSCOPETABLE pScopeTable;
154
155   TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
156         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
157         frame->handler, context, dispatcher);
158
159   __asm__ __volatile__ ("cld");
160
161   if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
162   {
163     /* Unwinding the current frame */
164      _local_unwind2(frame, TRYLEVEL_END);
165     return ExceptionContinueSearch;
166   }
167   else
168   {
169     /* Hunting for handler */
170     exceptPtrs.ExceptionRecord = rec;
171     exceptPtrs.ContextRecord = context;
172     *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
173     trylevel = frame->trylevel;
174     pScopeTable = frame->scopetable;
175
176     while (trylevel != TRYLEVEL_END)
177     {
178       if (pScopeTable[trylevel].lpfnFilter)
179       {
180         TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
181
182         retval = pScopeTable[trylevel].lpfnFilter(&exceptPtrs);
183
184         TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
185               "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
186               "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
187
188         if (retval == EXCEPTION_CONTINUE_EXECUTION)
189           return ExceptionContinueExecution;
190
191         if (retval == EXCEPTION_EXECUTE_HANDLER)
192         {
193           /* Unwind all higher frames, this one will handle the exception */
194           _global_unwind2((PEXCEPTION_FRAME)frame);
195           _local_unwind2(frame, trylevel);
196
197           /* Set our trylevel to the enclosing block, and call the __finally
198            * code, which won't return
199            */
200           frame->trylevel = pScopeTable->previousTryLevel;
201           TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
202           CALL_FINALLY_BLOCK(pScopeTable[trylevel].lpfnHandler, frame->_ebp);
203           ERR("Returned from __finally block - expect crash!\n");
204        }
205       }
206       trylevel = pScopeTable->previousTryLevel;
207     }
208   }
209 #else
210   TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
211         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
212         frame->handler, context, dispatcher);
213 #endif
214   return ExceptionContinueSearch;
215 }
216
217 /*********************************************************************
218  *              _abnormal_termination (MSVCRT.@)
219  */
220 int _abnormal_termination(void)
221 {
222   FIXME("(void)stub\n");
223   return 0;
224 }
225
226 /*******************************************************************
227  *              _setjmp (MSVCRT.@)
228  */
229 int MSVCRT__setjmp(LPDWORD* jmpbuf)
230 {
231   FIXME(":(%p): stub\n",jmpbuf);
232   return 0;
233 }
234
235 /*******************************************************************
236  *              _setjmp3 (MSVCRT.@)
237  */
238 int __cdecl MSVCRT__setjmp3(LPDWORD *jmpbuf, int x)
239 {
240   FIXME(":(%p %x): stub\n",jmpbuf,x);
241   return 0;
242 }
243
244 /*********************************************************************
245  *              longjmp (MSVCRT.@)
246  */
247 void MSVCRT_longjmp(jmp_buf env, int val)
248 {
249   FIXME("MSVCRT_longjmp semistub, expect crash\n");
250   longjmp(env, val);
251 }
252
253 /*********************************************************************
254  *              signal (MSVCRT.@)
255  */
256 void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func)
257 {
258   FIXME("(%d %p):stub\n", sig, func);
259   return (void*)-1;
260 }