source: trunk/src/msvcrt/except.c@ 9633

Last change on this file since 9633 was 9633, checked in by sandervl, 23 years ago

PF: Msvcrt Wine port with GCC

File size: 12.2 KB
Line 
1/*
2 * msvcrt.dll exception handling
3 *
4 * Copyright 2000 Jon Griffiths
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * NOTES:
21 *
22 * See http://www.microsoft.com/msj/0197/exception/exception.htm,
23 * but don't believe all of it.
24 *
25 * FIXME: Incomplete support for nested exceptions/try block cleanup.
26 */
27
28#ifdef __WIN32OS2__
29#include <emxheader.h>
30#include <winbase.h>
31#else
32#include "config.h"
33#endif
34
35#include "wine/port.h"
36
37#include "winternl.h"
38#include "wine/exception.h"
39#include "thread.h"
40#include "msvcrt.h"
41
42#include "msvcrt/setjmp.h"
43#include "excpt.h"
44
45
46#include "wine/debug.h"
47
48WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
49
50typedef void (*MSVCRT_sig_handler_func)(void);
51
52/* VC++ extensions to Win32 SEH */
53typedef struct _SCOPETABLE
54{
55 int previousTryLevel;
56 int (*lpfnFilter)(PEXCEPTION_POINTERS);
57 int (*lpfnHandler)(void);
58} SCOPETABLE, *PSCOPETABLE;
59
60typedef struct _MSVCRT_EXCEPTION_FRAME
61{
62 EXCEPTION_FRAME *prev;
63 void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME,
64 PCONTEXT, PEXCEPTION_RECORD);
65 PSCOPETABLE scopetable;
66 int trylevel;
67 int _ebp;
68 PEXCEPTION_POINTERS xpointers;
69} MSVCRT_EXCEPTION_FRAME;
70
71#define TRYLEVEL_END (-1) /* End of trylevel list */
72
73#if defined(__GNUC__) && defined(__i386__)
74inline static void call_finally_block( void *code_block, void *base_ptr )
75{
76 __asm__ __volatile__ ("movl %1,%%ebp; call *%%eax" \
77 : : "a" (code_block), "g" (base_ptr));
78}
79
80inline static DWORD call_filter( void *func, void *arg, void *ebp )
81{
82 DWORD ret;
83 __asm__ __volatile__ ("pushl %%ebp; pushl %3; movl %2,%%ebp; call *%%eax; popl %%ebp; popl %%ebp"
84 : "=a" (ret)
85 : "0" (func), "g" (ebp), "g" (arg)
86 : "ecx", "edx", "memory" );
87 return ret;
88}
89#endif
90
91static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
92 struct __EXCEPTION_FRAME* frame,
93 PCONTEXT context WINE_UNUSED,
94 struct __EXCEPTION_FRAME** dispatch)
95{
96 if (rec->ExceptionFlags & 0x6)
97 return ExceptionContinueSearch;
98 *dispatch = frame;
99 return ExceptionCollidedUnwind;
100}
101
102
103/*********************************************************************
104 * _XcptFilter (MSVCRT.@)
105 */
106int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr)
107{
108 FIXME("(%d,%p)semi-stub\n", ex, ptr);
109 return UnhandledExceptionFilter(ptr);
110}
111
112/*********************************************************************
113 * _EH_prolog (MSVCRT.@)
114 */
115#ifdef __i386__
116/* Provided for VC++ binary compatability only */
117__ASM_GLOBAL_FUNC(_EH_prolog,
118 "pushl $-1\n\t"
119 "pushl %eax\n\t"
120 "pushl %fs:0\n\t"
121 "movl %esp, %fs:0\n\t"
122 "movl 12(%esp), %eax\n\t"
123 "movl %ebp, 12(%esp)\n\t"
124 "leal 12(%esp), %ebp\n\t"
125 "pushl %eax\n\t"
126 "ret");
127#endif
128
129/*******************************************************************
130 * _global_unwind2 (MSVCRT.@)
131 */
132void _global_unwind2(PEXCEPTION_FRAME frame)
133{
134 TRACE("(%p)\n",frame);
135 RtlUnwind( frame, 0, 0, 0 );
136}
137
138/*******************************************************************
139 * _local_unwind2 (MSVCRT.@)
140 */
141void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
142{
143 MSVCRT_EXCEPTION_FRAME *curframe = frame;
144 EXCEPTION_FRAME reg;
145
146 TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
147
148 /* Register a handler in case of a nested exception */
149 reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler;
150 reg.Prev = NtCurrentTeb()->except;
151 __wine_push_frame(&reg);
152
153 while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
154 {
155 int curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
156 curframe = frame;
157 curframe->trylevel = curtrylevel;
158 if (!frame->scopetable[curtrylevel].lpfnFilter)
159 {
160 ERR("__try block cleanup not implemented - expect crash!\n");
161 /* FIXME: Remove current frame, set ebp, call
162 * frame->scopetable[curtrylevel].lpfnHandler()
163 */
164 }
165 }
166 __wine_pop_frame(&reg);
167 TRACE("unwound OK\n");
168}
169
170/*********************************************************************
171 * _except_handler2 (MSVCRT.@)
172 */
173int _except_handler2(PEXCEPTION_RECORD rec,
174 PEXCEPTION_FRAME frame,
175 PCONTEXT context,
176 PEXCEPTION_FRAME* dispatcher)
177{
178 FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
179 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
180 frame->Handler, context, dispatcher);
181 return ExceptionContinueSearch;
182}
183
184/*********************************************************************
185 * _except_handler3 (MSVCRT.@)
186 */
187int _except_handler3(PEXCEPTION_RECORD rec,
188 MSVCRT_EXCEPTION_FRAME* frame,
189 PCONTEXT context, void* dispatcher)
190{
191#if defined(__GNUC__) && defined(__i386__)
192 long retval;
193 int trylevel;
194 EXCEPTION_POINTERS exceptPtrs;
195 PSCOPETABLE pScopeTable;
196
197 TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
198 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
199 frame->handler, context, dispatcher);
200
201 __asm__ __volatile__ ("cld");
202
203 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
204 {
205 /* Unwinding the current frame */
206 _local_unwind2(frame, TRYLEVEL_END);
207 return ExceptionContinueSearch;
208 }
209 else
210 {
211 /* Hunting for handler */
212 exceptPtrs.ExceptionRecord = rec;
213 exceptPtrs.ContextRecord = context;
214 *((DWORD *)frame-1) = (DWORD)&exceptPtrs;
215 trylevel = frame->trylevel;
216 pScopeTable = frame->scopetable;
217
218 while (trylevel != TRYLEVEL_END)
219 {
220 if (pScopeTable[trylevel].lpfnFilter)
221 {
222 TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter);
223
224 retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
225
226 TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
227 "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
228 "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
229
230 if (retval == EXCEPTION_CONTINUE_EXECUTION)
231 return ExceptionContinueExecution;
232
233 if (retval == EXCEPTION_EXECUTE_HANDLER)
234 {
235 /* Unwind all higher frames, this one will handle the exception */
236 _global_unwind2((PEXCEPTION_FRAME)frame);
237 _local_unwind2(frame, trylevel);
238
239 /* Set our trylevel to the enclosing block, and call the __finally
240 * code, which won't return
241 */
242 frame->trylevel = pScopeTable->previousTryLevel;
243 TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
244 call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
245 ERR("Returned from __finally block - expect crash!\n");
246 }
247 }
248 trylevel = pScopeTable->previousTryLevel;
249 }
250 }
251#else
252 TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
253 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
254 frame->handler, context, dispatcher);
255#endif
256 return ExceptionContinueSearch;
257}
258
259/*********************************************************************
260 * _abnormal_termination (MSVCRT.@)
261 */
262int _abnormal_termination(void)
263{
264 FIXME("(void)stub\n");
265 return 0;
266}
267
268/*
269 * setjmp/longjmp implementation
270 */
271
272#ifdef __i386__
273#define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
274typedef void (*MSVCRT_unwind_function)(const void*);
275
276/*
277 * The signatures of the setjmp/longjmp functions do not match that
278 * declared in the setjmp header so they don't follow the regular naming
279 * convention to avoid conflicts.
280 */
281
282/*******************************************************************
283 * _setjmp (MSVCRT.@)
284 */
285#ifdef __WIN32OS2__
286DEFINE_REGS_ENTRYPOINT_1( _MSVCRT__setjmp, EXC_MSVCRT__setjmp, _JUMP_BUFFER);
287void EXC_MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
288#else
289void _MSVCRT__setjmp(_JUMP_BUFFER *jmp, CONTEXT86* context)
290#endif
291{
292 TRACE("(%p)\n",jmp);
293 jmp->Ebp = context->Ebp;
294 jmp->Ebx = context->Ebx;
295 jmp->Edi = context->Edi;
296 jmp->Esi = context->Esi;
297 jmp->Esp = context->Esp;
298 jmp->Eip = context->Eip;
299 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
300 if (jmp->Registration == TRYLEVEL_END)
301 jmp->TryLevel = TRYLEVEL_END;
302 else
303 jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
304 TRACE("returning 0\n");
305 context->Eax=0;
306}
307
308/*******************************************************************
309 * _setjmp3 (MSVCRT.@)
310 */
311#ifdef __WIN32OS2__
312DEFINE_REGS_ENTRYPOINT_2( _MSVCRT__setjmp3, EXC_MSVCRT__setjmp3, _JUMP_BUFFER *, int );
313void EXC_MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
314#else
315void _MSVCRT__setjmp3(_JUMP_BUFFER *jmp, int nb_args, CONTEXT86* context)
316#endif
317{
318 TRACE("(%p,%d)\n",jmp,nb_args);
319 jmp->Ebp = context->Ebp;
320 jmp->Ebx = context->Ebx;
321 jmp->Edi = context->Edi;
322 jmp->Esi = context->Esi;
323 jmp->Esp = context->Esp;
324 jmp->Eip = context->Eip;
325 jmp->Cookie = MSVCRT_JMP_MAGIC;
326 jmp->UnwindFunc = 0;
327 jmp->Registration = (unsigned long)NtCurrentTeb()->except;
328 if (jmp->Registration == TRYLEVEL_END)
329 {
330 jmp->TryLevel = TRYLEVEL_END;
331 }
332 else
333 {
334 void **args = ((void**)context->Esp)+2;
335
336 if (nb_args > 0) jmp->UnwindFunc = (unsigned long)*args++;
337 if (nb_args > 1) jmp->TryLevel = (unsigned long)*args++;
338 else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
339 if (nb_args > 2)
340 {
341 size_t size = (nb_args - 2) * sizeof(DWORD);
342 memcpy( jmp->UnwindData, args, min( size, sizeof(jmp->UnwindData) ));
343 }
344 }
345 TRACE("returning 0\n");
346 context->Eax = 0;
347}
348
349/*********************************************************************
350 * longjmp (MSVCRT.@)
351 */
352#ifdef __WIN32OS2__
353DEFINE_REGS_ENTRYPOINT_2( _MSVCRT_longjmp, EXC_MSVCRT_longjmp, _JUMP_BUFFER *, int );
354void EXC_MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
355#else
356void _MSVCRT_longjmp(_JUMP_BUFFER *jmp, int retval, CONTEXT86* context)
357#endif
358{
359 unsigned long cur_frame = 0;
360
361 TRACE("(%p,%d)\n", jmp, retval);
362
363 cur_frame=(unsigned long)NtCurrentTeb()->except;
364 TRACE("cur_frame=%lx\n",cur_frame);
365
366 if (cur_frame != jmp->Registration)
367 _global_unwind2((PEXCEPTION_FRAME)jmp->Registration);
368
369 if (jmp->Registration)
370 {
371 if (!IsBadReadPtr(&jmp->Cookie, sizeof(long)) &&
372 jmp->Cookie == MSVCRT_JMP_MAGIC && jmp->UnwindFunc)
373 {
374 MSVCRT_unwind_function unwind_func;
375
376 unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
377 unwind_func(jmp);
378 }
379 else
380 _local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
381 jmp->TryLevel);
382 }
383
384 if (!retval)
385 retval = 1;
386
387 TRACE("Jump to %lx returning %d\n",jmp->Eip,retval);
388 context->Ebp = jmp->Ebp;
389 context->Ebx = jmp->Ebx;
390 context->Edi = jmp->Edi;
391 context->Esi = jmp->Esi;
392 context->Esp = jmp->Esp;
393 context->Eip = jmp->Eip;
394 context->Eax = retval;
395}
396
397/*********************************************************************
398 * _seh_longjmp_unwind (MSVCRT.@)
399 */
400void __stdcall _seh_longjmp_unwind(_JUMP_BUFFER *jmp)
401{
402 _local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel );
403}
404#endif /* i386 */
405
406/*********************************************************************
407 * signal (MSVCRT.@)
408 */
409void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func)
410{
411 FIXME("(%d %p):stub\n", sig, func);
412 return (void*)-1;
413}
Note: See TracBrowser for help on using the repository browser.