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