2 * msvcrt.dll exception handling
4 * Copyright 2000 Jon Griffiths
6 * See http://www.microsoft.com/msj/0197/exception/exception.htm,
7 * but don't believe all of it.
9 * FIXME: Incomplete support for nested exceptions/try block cleanup.
14 #include "wine/exception.h"
18 #include "msvcrt/setjmp.h"
21 #include "wine/debug.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
25 typedef void (*MSVCRT_sig_handler_func)(void);
27 /* VC++ extensions to Win32 SEH */
28 typedef struct _SCOPETABLE
30 DWORD previousTryLevel;
31 int (*lpfnFilter)(PEXCEPTION_POINTERS);
32 int (*lpfnHandler)(void);
33 } SCOPETABLE, *PSCOPETABLE;
35 typedef struct _MSVCRT_EXCEPTION_FRAME
37 EXCEPTION_FRAME *prev;
38 void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
39 PCONTEXT, PEXCEPTION_RECORD);
40 PSCOPETABLE scopetable;
43 PEXCEPTION_POINTERS xpointers;
44 } MSVCRT_EXCEPTION_FRAME;
46 #define TRYLEVEL_END 0xffffffff /* End of trylevel list */
48 #if defined(__GNUC__) && defined(__i386__)
50 inline static void call_finally_block( void *code_block, void *base_ptr )
52 __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" \
53 : : "a" (code_block), "g" (base_ptr));
56 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
57 struct __EXCEPTION_FRAME* frame,
58 PCONTEXT context WINE_UNUSED,
59 struct __EXCEPTION_FRAME** dispatch)
61 if (rec->ExceptionFlags & 0x6)
62 return ExceptionContinueSearch;
64 return ExceptionCollidedUnwind;
69 /*********************************************************************
70 * _XcptFilter (MSVCRT.@)
72 int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr)
74 FIXME("(%d,%p)semi-stub\n", ex, ptr);
75 return UnhandledExceptionFilter(ptr);
78 /*********************************************************************
79 * _EH_prolog (MSVCRT.@)
82 /* Provided for VC++ binary compatability only */
83 __ASM_GLOBAL_FUNC(_EH_prolog,
87 "movl %esp, %fs:0\n\t"
88 "movl 12(%esp), %eax\n\t"
89 "movl %ebp, 12(%esp)\n\t"
90 "leal 12(%esp), %ebp\n\t"
95 /*******************************************************************
96 * _global_unwind2 (MSVCRT.@)
98 void _global_unwind2(PEXCEPTION_FRAME frame)
100 TRACE("(%p)\n",frame);
101 RtlUnwind( frame, 0, 0, 0 );
104 /*******************************************************************
105 * _local_unwind2 (MSVCRT.@)
107 void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame,
110 MSVCRT_EXCEPTION_FRAME *curframe = frame;
111 DWORD curtrylevel = 0xfe;
114 TRACE("(%p,%ld,%ld)\n",frame, frame->trylevel, trylevel);
116 /* Register a handler in case of a nested exception */
117 reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
118 reg.Prev = NtCurrentTeb()->except;
119 __wine_push_frame(®);
121 while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
123 curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
125 curframe->trylevel = curtrylevel;
126 if (!frame->scopetable[curtrylevel].lpfnFilter)
128 ERR("__try block cleanup not implemented - expect crash!\n");
129 /* FIXME: Remove current frame, set ebp, call
130 * frame->scopetable[curtrylevel].lpfnHandler()
134 __wine_pop_frame(®);
135 TRACE("unwound OK\n");
138 /*********************************************************************
139 * _except_handler2 (MSVCRT.@)
141 int _except_handler2(PEXCEPTION_RECORD rec,
142 PEXCEPTION_FRAME frame,
144 PEXCEPTION_FRAME* dispatcher)
146 FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
147 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
148 frame->Handler, context, dispatcher);
149 return ExceptionContinueSearch;
152 /*********************************************************************
153 * _except_handler3 (MSVCRT.@)
155 int _except_handler3(PEXCEPTION_RECORD rec,
156 MSVCRT_EXCEPTION_FRAME* frame,
157 PCONTEXT context, void* dispatcher)
159 #if defined(__GNUC__) && defined(__i386__)
160 long retval, trylevel;
161 EXCEPTION_POINTERS exceptPtrs;
162 PSCOPETABLE pScopeTable;
164 TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
165 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
166 frame->handler, context, dispatcher);
168 __asm__ __volatile__ ("cld");
170 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
172 /* Unwinding the current frame */
173 _local_unwind2(frame, TRYLEVEL_END);
174 return ExceptionContinueSearch;
178 /* Hunting for handler */
179 exceptPtrs.ExceptionRecord = rec;
180 exceptPtrs.ContextRecord = context;
181 *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
182 trylevel = frame->trylevel;
183 pScopeTable = frame->scopetable;
185 while (trylevel != TRYLEVEL_END)
187 if (pScopeTable[trylevel].lpfnFilter)
189 TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
191 retval = pScopeTable[trylevel].lpfnFilter(&exceptPtrs);
193 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
194 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
195 "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
197 if (retval == EXCEPTION_CONTINUE_EXECUTION)
198 return ExceptionContinueExecution;
200 if (retval == EXCEPTION_EXECUTE_HANDLER)
202 /* Unwind all higher frames, this one will handle the exception */
203 _global_unwind2((PEXCEPTION_FRAME)frame);
204 _local_unwind2(frame, trylevel);
206 /* Set our trylevel to the enclosing block, and call the __finally
207 * code, which won't return
209 frame->trylevel = pScopeTable->previousTryLevel;
210 TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
211 call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
212 ERR("Returned from __finally block - expect crash!\n");
215 trylevel = pScopeTable->previousTryLevel;
219 TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
220 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
221 frame->handler, context, dispatcher);
223 return ExceptionContinueSearch;
226 /*********************************************************************
227 * _abnormal_termination (MSVCRT.@)
229 int _abnormal_termination(void)
231 FIXME("(void)stub\n");
236 * setjmp/longjmp implementation
240 #define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
241 typedef void (*MSVCRT_unwind_function)(const void*);
244 * The signatures of the setjmp/longjmp functions do not match that
245 * declared in the setjmp header so they don't follow the regular naming
246 * convention to avoid conflicts.
249 /*******************************************************************
252 void _MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
255 jmp->Ebp = context->Ebp;
256 jmp->Ebx = context->Ebx;
257 jmp->Edi = context->Edi;
258 jmp->Esi = context->Esi;
259 jmp->Esp = context->Esp;
260 jmp->Eip = context->Eip;
261 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
262 if (jmp->Registration == TRYLEVEL_END)
263 jmp->TryLevel = TRYLEVEL_END;
265 jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
266 TRACE("returning 0\n");
270 /*******************************************************************
271 * _setjmp3 (MSVCRT.@)
273 void _MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
275 TRACE("(%p,%d)\n",jmp,nb_args);
276 jmp->Ebp = context->Ebp;
277 jmp->Ebx = context->Ebx;
278 jmp->Edi = context->Edi;
279 jmp->Esi = context->Esi;
280 jmp->Esp = context->Esp;
281 jmp->Eip = context->Eip;
282 jmp->Cookie = MSVCRT_JMP_MAGIC;
284 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
285 if (jmp->Registration == TRYLEVEL_END)
287 jmp->TryLevel = TRYLEVEL_END;
291 void **args = ((void**)context->Esp)+2;
293 if (nb_args > 0) jmp->UnwindFunc = (unsigned long)*args++;
294 if (nb_args > 1) jmp->TryLevel = (unsigned long)*args++;
295 else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
298 size_t size = (nb_args - 2) * sizeof(DWORD);
299 memcpy( jmp->UnwindData, args, min( size, sizeof(jmp->UnwindData) ));
302 TRACE("returning 0\n");
306 /*********************************************************************
309 void _MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
311 unsigned long cur_frame = 0;
313 TRACE("(%p,%d)\n", jmp, retval);
315 cur_frame=(unsigned long)NtCurrentTeb()->except;
316 TRACE("cur_frame=%lx\n",cur_frame);
318 if (cur_frame != jmp->Registration)
319 _global_unwind2((PEXCEPTION_FRAME)jmp->Registration);
321 if (jmp->Registration)
323 if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
324 jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
326 MSVCRT_unwind_function unwind_func;
328 unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
332 _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
339 TRACE("Jump to %lx returning %d\n",jmp->Eip,retval);
340 context->Ebp = jmp->Ebp;
341 context->Ebx = jmp->Ebx;
342 context->Edi = jmp->Edi;
343 context->Esi = jmp->Esi;
344 context->Esp = jmp->Esp;
345 context->Eip = jmp->Eip;
346 context->Eax = retval;
350 /*********************************************************************
353 void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func)
355 FIXME("(%d %p):stub\n", sig, func);
359 /*********************************************************************
360 * __CxxFrameHandler (MSVCRT.@)
362 DWORD __CxxFrameHandler(PEXCEPTION_RECORD rec, struct __EXCEPTION_FRAME* frame,
363 PCONTEXT context, struct __EXCEPTION_FRAME** dispatch)
365 FIXME("(%p,%p,%p,%p):stub?\n",rec,frame,context,dispatch);
367 /* Copied from MSVCRT_nested_handler, I hope this is more
368 * or less the right thing to do
370 if (rec->ExceptionFlags & 0x6)
371 return ExceptionContinueSearch;
373 return ExceptionCollidedUnwind;