Release 970914
[wine] / win32 / except.c
1 /*
2  * Win32 exception functions
3  *
4  * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
5  *
6  * Notes:
7  *  What really happens behind the scenes of those new
8  *  __try{...}__except(..){....}  and
9  *  __try{...}__finally{...}
10  *  statements is simply not documented by Microsoft. There could be different
11  *  reasons for this: 
12  *  One reason could be that they try to hide the fact that exception 
13  *  handling in Win32 looks almost the same as in OS/2 2.x.  
14  *  Another reason could be that Microsoft does not want others to write
15  *  binary compatible implementations of the Win32 API (like us).  
16  *
17  *  Whatever the reason, THIS SUCKS!! Ensuring portabilty or future 
18  *  compatability may be valid reasons to keep some things undocumented. 
19  *  But exception handling is so basic to Win32 that it should be 
20  *  documented!
21  *
22  * Fixmes:
23  *  -Most functions need better parameter checking.
24  *  -I do not know how to handle exceptions within an exception handler.
25  *   or what is done when ExceptionNestedException is returned from an 
26  *   exception handler
27  *  -Real exceptions are not yet implemented. only the exception functions
28  *   are implemented. A real implementation needs some new code in
29  *   loader/signal.c. There would also be a need for showing debugging
30  *   information in UnhandledExceptionFilter.
31  *
32  */
33
34 #include <assert.h>
35 #include <stdio.h>
36 #include "windows.h"
37 #include "winerror.h"
38 #include "ldt.h"
39 #include "process.h"
40 #include "thread.h"
41 #include "stddebug.h"
42 #include "debug.h"
43 #include "except.h"
44
45 #define TEB_EXCEPTION_FRAME(pcontext) \
46     ((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
47
48 /*******************************************************************
49  *         _local_unwind2  (CRTDLL)
50  */
51 void WINAPI CRTDLL__local_unwind2(PEXCEPTION_FRAME endframe,DWORD nr,
52                                   PCONTEXT pcontext)
53 {
54         fprintf(stderr,"CRTDLL__local_unwind2(%p,%ld)\n",endframe,nr);
55         return;
56 }
57
58 /*******************************************************************
59  *         _global_unwind2  (CRTDLL)
60  */
61 void WINAPI CRTDLL__global_unwind2(PEXCEPTION_FRAME endframe,PCONTEXT pcontext)
62 {
63         RtlUnwind(endframe,NULL/*should point to the return;*/,NULL,0,pcontext);
64         return;
65 }
66
67 /*******************************************************************
68  *         RtlUnwind  (KERNEL32.443)
69  *
70  *  This function is undocumented. This is the general idea of 
71  *  RtlUnwind, though. Note that error handling is not yet implemented.
72  */
73 void WINAPI RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, 
74                        PEXCEPTION_RECORD pRecord, DWORD returnEax,
75                        PCONTEXT pcontext /* Wine additional parameter */ )
76 {   
77    EXCEPTION_RECORD record;
78    DWORD            dispatch;
79    int              retval;
80   
81    pcontext->Eax=returnEax;
82    
83    /* build an exception record, if we do not have one */
84    if(!pRecord)
85    {
86      record.ExceptionCode    = STATUS_INVALID_DISPOSITION;
87      record.ExceptionFlags   = 0;
88      record.ExceptionRecord  = NULL;
89      record.ExceptionAddress = (LPVOID)pcontext->Eip; 
90      record.NumberParameters = 0;
91      pRecord = &record;
92    }
93
94    if(pEndFrame)
95      pRecord->ExceptionFlags|=EH_UNWINDING;
96    else
97      pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
98   
99    /* get chain of exception frames */      
100    while ((TEB_EXCEPTION_FRAME(pcontext) != NULL) &&
101           (TEB_EXCEPTION_FRAME(pcontext) != ((void *)0xffffffff)) &&
102           (TEB_EXCEPTION_FRAME(pcontext) != pEndFrame))
103    {
104        dprintf_win32( stddeb, "calling exception handler at 0x%x\n",
105                       (int)TEB_EXCEPTION_FRAME(pcontext)->Handler );
106
107        dispatch=0;       
108        retval = TEB_EXCEPTION_FRAME(pcontext)->Handler( pRecord,
109                                                 TEB_EXCEPTION_FRAME(pcontext),
110                                                 pcontext, &dispatch);
111                                          
112        dprintf_win32(stddeb,"exception handler returns 0x%x, dispatch=0x%x\n",
113                               retval, (int) dispatch);
114   
115        if (     (retval == ExceptionCollidedUnwind) &&
116                 (TEB_EXCEPTION_FRAME(pcontext) != (LPVOID)dispatch)
117        )
118            TEB_EXCEPTION_FRAME(pcontext) = (LPVOID)dispatch;
119        else if (        (TEB_EXCEPTION_FRAME(pcontext) != pEndFrame) &&
120                         (TEB_EXCEPTION_FRAME(pcontext) != TEB_EXCEPTION_FRAME(pcontext)->Prev)
121        )
122            TEB_EXCEPTION_FRAME(pcontext) = TEB_EXCEPTION_FRAME(pcontext)->Prev;
123        else
124           break;  
125    }
126 }
127
128
129 /*******************************************************************
130  *         RaiseException  (KERNEL32.418)
131  */
132 void WINAPI RaiseException(DWORD dwExceptionCode,
133                            DWORD dwExceptionFlags,
134                            DWORD cArguments,
135                            const LPDWORD lpArguments,
136                            PCONTEXT pcontext /* Wine additional parameter */ )
137 {
138     PEXCEPTION_FRAME    pframe; 
139     EXCEPTION_RECORD    record;
140     DWORD               dispatch; /* is this used in raising exceptions ?? */
141     int                 retval;
142     int                 i;
143     
144     /* compose an exception record */ 
145     
146     record.ExceptionCode       = dwExceptionCode;   
147     record.ExceptionFlags      = dwExceptionFlags;
148     record.ExceptionRecord     = NULL;
149     record.NumberParameters    = cArguments;
150     record.ExceptionAddress    = (LPVOID) pcontext->Eip;
151     
152     if (lpArguments) for( i = 0; i < cArguments; i++)
153         record.ExceptionInformation[i] = lpArguments[i];
154     
155     /* get chain of exception frames */    
156     
157     retval = ExceptionContinueSearch;    
158     pframe = TEB_EXCEPTION_FRAME( pcontext );
159     
160     while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
161     {
162        dprintf_win32(stddeb,"calling exception handler at 0x%x\n",
163                                                 (int) pframe->Handler);
164        dispatch=0;  
165        retval=pframe->Handler(&record,pframe,pcontext,&dispatch);
166  
167        dprintf_win32(stddeb,"exception handler returns 0x%x, dispatch=0x%x\n",
168                               retval, (int) dispatch);
169                               
170        if(retval==ExceptionContinueExecution)
171           break;
172        pframe=pframe->Prev;
173    }
174
175    if (retval!=ExceptionContinueExecution)
176    {    
177        /* FIXME: what should we do here? */
178        dprintf_win32(stddeb,"no handler wanted to handle the exception, exiting\n");
179        ExitProcess(dwExceptionCode); /* what status should be used here ? */
180    }
181 }
182
183
184 /*******************************************************************
185  *         UnhandledExceptionFilter   (KERNEL32.537)
186  */
187 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
188 {
189     char message[80];
190
191     /* FIXME: Should check if the process is being debugged */
192
193     if (pCurrentProcess && pCurrentProcess->top_filter)
194     {
195         DWORD ret = pCurrentProcess->top_filter( epointers );
196         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
197     }
198
199     /* FIXME: Should check the current error mode */
200
201     sprintf( message, "Unhandled exception 0x%08lx at address 0x%08lx.",
202              epointers->ExceptionRecord->ExceptionCode,
203              (DWORD)epointers->ExceptionRecord->ExceptionAddress );
204     MessageBox32A( 0, message, "Error", MB_OK | MB_ICONHAND );
205     return EXCEPTION_EXECUTE_HANDLER;
206 }
207
208
209 /*************************************************************
210  *            SetUnhandledExceptionFilter   (KERNEL32.516)
211  */
212 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
213                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
214 {
215     LPTOP_LEVEL_EXCEPTION_FILTER old = pCurrentProcess->top_filter;
216     pCurrentProcess->top_filter = filter;
217     return old;
218 }