Move the name directive from the .spec file to the Makefile.
[wine/gsoc_dplay.git] / dlls / msvcrt / except.c
blobffdc27114bd0d9c0f8a1befd717c919ddc285cc1
1 /*
2 * msvcrt.dll exception handling
4 * Copyright 2000 Jon Griffiths
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * NOTES:
22 * See http://www.microsoft.com/msj/0197/exception/exception.htm,
23 * but don't believe all of it.
25 * FIXME: Incomplete support for nested exceptions/try block cleanup.
28 #include "config.h"
29 #include "wine/port.h"
31 #include "ntddk.h"
32 #include "wine/exception.h"
33 #include "thread.h"
34 #include "msvcrt.h"
36 #include "msvcrt/setjmp.h"
37 #include "msvcrt/excpt.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
44 typedef void (*MSVCRT_sig_handler_func)(void);
46 /* VC++ extensions to Win32 SEH */
47 typedef struct _SCOPETABLE
49 DWORD previousTryLevel;
50 int (*lpfnFilter)(PEXCEPTION_POINTERS);
51 int (*lpfnHandler)(void);
52 } SCOPETABLE, *PSCOPETABLE;
54 typedef struct _MSVCRT_EXCEPTION_FRAME
56 EXCEPTION_FRAME *prev;
57 void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
58 PCONTEXT, PEXCEPTION_RECORD);
59 PSCOPETABLE scopetable;
60 DWORD trylevel;
61 int _ebp;
62 PEXCEPTION_POINTERS xpointers;
63 } MSVCRT_EXCEPTION_FRAME;
65 #define TRYLEVEL_END 0xffffffff /* End of trylevel list */
67 #if defined(__GNUC__) && defined(__i386__)
68 inline static void call_finally_block( void *code_block, void *base_ptr )
70 __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" \
71 : : "a" (code_block), "g" (base_ptr));
73 #endif
75 static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
76 struct __EXCEPTION_FRAME* frame,
77 PCONTEXT context WINE_UNUSED,
78 struct __EXCEPTION_FRAME** dispatch)
80 if (rec->ExceptionFlags & 0x6)
81 return ExceptionContinueSearch;
82 *dispatch = frame;
83 return ExceptionCollidedUnwind;
87 /*********************************************************************
88 * _XcptFilter (MSVCRT.@)
90 int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr)
92 FIXME("(%d,%p)semi-stub\n", ex, ptr);
93 return UnhandledExceptionFilter(ptr);
96 /*********************************************************************
97 * _EH_prolog (MSVCRT.@)
99 #ifdef __i386__
100 /* Provided for VC++ binary compatability only */
101 __ASM_GLOBAL_FUNC(_EH_prolog,
102 "pushl $0xff\n\t"
103 "pushl %eax\n\t"
104 "pushl %fs:0\n\t"
105 "movl %esp, %fs:0\n\t"
106 "movl 12(%esp), %eax\n\t"
107 "movl %ebp, 12(%esp)\n\t"
108 "leal 12(%esp), %ebp\n\t"
109 "pushl %eax\n\t"
110 "ret");
111 #endif
113 /*******************************************************************
114 * _global_unwind2 (MSVCRT.@)
116 void _global_unwind2(PEXCEPTION_FRAME frame)
118 TRACE("(%p)\n",frame);
119 RtlUnwind( frame, 0, 0, 0 );
122 /*******************************************************************
123 * _local_unwind2 (MSVCRT.@)
125 void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame,
126 DWORD trylevel)
128 MSVCRT_EXCEPTION_FRAME *curframe = frame;
129 DWORD curtrylevel = 0xfe;
130 EXCEPTION_FRAME reg;
132 TRACE("(%p,%ld,%ld)\n",frame, frame->trylevel, trylevel);
134 /* Register a handler in case of a nested exception */
135 reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
136 reg.Prev = NtCurrentTeb()->except;
137 __wine_push_frame(&reg);
139 while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
141 curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
142 curframe = frame;
143 curframe->trylevel = curtrylevel;
144 if (!frame->scopetable[curtrylevel].lpfnFilter)
146 ERR("__try block cleanup not implemented - expect crash!\n");
147 /* FIXME: Remove current frame, set ebp, call
148 * frame->scopetable[curtrylevel].lpfnHandler()
152 __wine_pop_frame(&reg);
153 TRACE("unwound OK\n");
156 /*********************************************************************
157 * _except_handler2 (MSVCRT.@)
159 int _except_handler2(PEXCEPTION_RECORD rec,
160 PEXCEPTION_FRAME frame,
161 PCONTEXT context,
162 PEXCEPTION_FRAME* dispatcher)
164 FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
165 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
166 frame->Handler, context, dispatcher);
167 return ExceptionContinueSearch;
170 /*********************************************************************
171 * _except_handler3 (MSVCRT.@)
173 int _except_handler3(PEXCEPTION_RECORD rec,
174 MSVCRT_EXCEPTION_FRAME* frame,
175 PCONTEXT context, void* dispatcher)
177 #if defined(__GNUC__) && defined(__i386__)
178 long retval, trylevel;
179 EXCEPTION_POINTERS exceptPtrs;
180 PSCOPETABLE pScopeTable;
182 TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
183 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
184 frame->handler, context, dispatcher);
186 __asm__ __volatile__ ("cld");
188 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
190 /* Unwinding the current frame */
191 _local_unwind2(frame, TRYLEVEL_END);
192 return ExceptionContinueSearch;
194 else
196 /* Hunting for handler */
197 exceptPtrs.ExceptionRecord = rec;
198 exceptPtrs.ContextRecord = context;
199 *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
200 trylevel = frame->trylevel;
201 pScopeTable = frame->scopetable;
203 while (trylevel != TRYLEVEL_END)
205 if (pScopeTable[trylevel].lpfnFilter)
207 TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
209 retval = pScopeTable[trylevel].lpfnFilter(&exceptPtrs);
211 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
212 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
213 "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
215 if (retval == EXCEPTION_CONTINUE_EXECUTION)
216 return ExceptionContinueExecution;
218 if (retval == EXCEPTION_EXECUTE_HANDLER)
220 /* Unwind all higher frames, this one will handle the exception */
221 _global_unwind2((PEXCEPTION_FRAME)frame);
222 _local_unwind2(frame, trylevel);
224 /* Set our trylevel to the enclosing block, and call the __finally
225 * code, which won't return
227 frame->trylevel = pScopeTable->previousTryLevel;
228 TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
229 call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
230 ERR("Returned from __finally block - expect crash!\n");
233 trylevel = pScopeTable->previousTryLevel;
236 #else
237 TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
238 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
239 frame->handler, context, dispatcher);
240 #endif
241 return ExceptionContinueSearch;
244 /*********************************************************************
245 * _abnormal_termination (MSVCRT.@)
247 int _abnormal_termination(void)
249 FIXME("(void)stub\n");
250 return 0;
254 * setjmp/longjmp implementation
257 #ifdef __i386__
258 #define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
259 typedef void (*MSVCRT_unwind_function)(const void*);
262 * The signatures of the setjmp/longjmp functions do not match that
263 * declared in the setjmp header so they don't follow the regular naming
264 * convention to avoid conflicts.
267 /*******************************************************************
268 * _setjmp (MSVCRT.@)
270 void _MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
272 TRACE("(%p)\n",jmp);
273 jmp->Ebp = context->Ebp;
274 jmp->Ebx = context->Ebx;
275 jmp->Edi = context->Edi;
276 jmp->Esi = context->Esi;
277 jmp->Esp = context->Esp;
278 jmp->Eip = context->Eip;
279 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
280 if (jmp->Registration == TRYLEVEL_END)
281 jmp->TryLevel = TRYLEVEL_END;
282 else
283 jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
284 TRACE("returning 0\n");
285 context->Eax=0;
288 /*******************************************************************
289 * _setjmp3 (MSVCRT.@)
291 void _MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
293 TRACE("(%p,%d)\n",jmp,nb_args);
294 jmp->Ebp = context->Ebp;
295 jmp->Ebx = context->Ebx;
296 jmp->Edi = context->Edi;
297 jmp->Esi = context->Esi;
298 jmp->Esp = context->Esp;
299 jmp->Eip = context->Eip;
300 jmp->Cookie = MSVCRT_JMP_MAGIC;
301 jmp->UnwindFunc = 0;
302 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
303 if (jmp->Registration == TRYLEVEL_END)
305 jmp->TryLevel = TRYLEVEL_END;
307 else
309 void **args = ((void**)context->Esp)+2;
311 if (nb_args > 0) jmp->UnwindFunc = (unsigned long)*args++;
312 if (nb_args > 1) jmp->TryLevel = (unsigned long)*args++;
313 else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
314 if (nb_args > 2)
316 size_t size = (nb_args - 2) * sizeof(DWORD);
317 memcpy( jmp->UnwindData, args, min( size, sizeof(jmp->UnwindData) ));
320 TRACE("returning 0\n");
321 context->Eax = 0;
324 /*********************************************************************
325 * longjmp (MSVCRT.@)
327 void _MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
329 unsigned long cur_frame = 0;
331 TRACE("(%p,%d)\n", jmp, retval);
333 cur_frame=(unsigned long)NtCurrentTeb()->except;
334 TRACE("cur_frame=%lx\n",cur_frame);
336 if (cur_frame != jmp->Registration)
337 _global_unwind2((PEXCEPTION_FRAME)jmp->Registration);
339 if (jmp->Registration)
341 if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
342 jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
344 MSVCRT_unwind_function unwind_func;
346 unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
347 unwind_func(jmp);
349 else
350 _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
351 jmp->TryLevel);
354 if (!retval)
355 retval = 1;
357 TRACE("Jump to %lx returning %d\n",jmp->Eip,retval);
358 context->Ebp = jmp->Ebp;
359 context->Ebx = jmp->Ebx;
360 context->Edi = jmp->Edi;
361 context->Esi = jmp->Esi;
362 context->Esp = jmp->Esp;
363 context->Eip = jmp->Eip;
364 context->Eax = retval;
366 #endif /* i386 */
368 /*********************************************************************
369 * signal (MSVCRT.@)
371 void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func)
373 FIXME("(%d %p):stub\n", sig, func);
374 return (void*)-1;