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

Last change on this file since 10005 was 10005, checked in by sandervl, 22 years ago

PF: MSVCRT update

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