Converted to the new debugging interface (done with the help of the
[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 "winuser.h"
36 #include "winerror.h"
37 #include "ldt.h"
38 #include "process.h"
39 #include "thread.h"
40 #include "debugtools.h"
41 #include "except.h"
42 #include "stackframe.h"
43
44 DECLARE_DEBUG_CHANNEL(relay)
45 DECLARE_DEBUG_CHANNEL(win32)
46
47 #define TEB_EXCEPTION_FRAME(pcontext) \
48     ((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
49
50 /*******************************************************************
51  *         RtlUnwind  (KERNEL32.443)
52  *
53  *  This function is undocumented. This is the general idea of 
54  *  RtlUnwind, though. Note that error handling is not yet implemented.
55  *
56  * The real prototype is:
57  * void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, 
58  *                            PEXCEPTION_RECORD pRecord, DWORD returnEax );
59  */
60 REGS_ENTRYPOINT(RtlUnwind)
61 {
62     EXCEPTION_RECORD record;
63     DWORD            dispatch;
64     int              retval;
65     PEXCEPTION_FRAME pEndFrame;
66     PEXCEPTION_RECORD pRecord;
67
68     /* get the arguments from the stack */
69
70     DWORD ret        = STACK32_POP(context);  /* return addr */
71     pEndFrame        = (PEXCEPTION_FRAME)STACK32_POP(context);
72     (void)STACK32_POP(context);  /* unused arg */
73     pRecord          = (PEXCEPTION_RECORD)STACK32_POP(context);
74     EAX_reg(context) = STACK32_POP(context);
75     STACK32_PUSH(context,ret);  /* restore return addr */
76    
77    /* build an exception record, if we do not have one */
78    if(!pRecord)
79    {
80      record.ExceptionCode    = STATUS_INVALID_DISPOSITION;
81      record.ExceptionFlags   = 0;
82      record.ExceptionRecord  = NULL;
83      record.ExceptionAddress = (LPVOID)EIP_reg(context); 
84      record.NumberParameters = 0;
85      pRecord = &record;
86    }
87
88    if(pEndFrame)
89      pRecord->ExceptionFlags|=EH_UNWINDING;
90    else
91      pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
92   
93    /* get chain of exception frames */      
94    while ((TEB_EXCEPTION_FRAME(context) != NULL) &&
95           (TEB_EXCEPTION_FRAME(context) != ((void *)0xffffffff)) &&
96           (TEB_EXCEPTION_FRAME(context) != pEndFrame))
97    {
98        TRACE_(win32)("calling exception handler at 0x%x\n",
99                       (int)TEB_EXCEPTION_FRAME(context)->Handler );
100
101        dispatch=0;       
102        retval = TEB_EXCEPTION_FRAME(context)->Handler( pRecord,
103                                                 TEB_EXCEPTION_FRAME(context),
104                                                 context, &dispatch);
105                                          
106        TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
107                               retval, (int) dispatch);
108   
109        if (     (retval == ExceptionCollidedUnwind) &&
110                 (TEB_EXCEPTION_FRAME(context) != (LPVOID)dispatch)
111        )
112            TEB_EXCEPTION_FRAME(context) = (LPVOID)dispatch;
113        else if (        (TEB_EXCEPTION_FRAME(context) != pEndFrame) &&
114                         (TEB_EXCEPTION_FRAME(context) != TEB_EXCEPTION_FRAME(context)->Prev)
115        )
116            TEB_EXCEPTION_FRAME(context) = TEB_EXCEPTION_FRAME(context)->Prev;
117        else
118           break;  
119    }
120 }
121
122
123 /*******************************************************************
124  *         RaiseException  (KERNEL32.418)
125  *
126  * The real prototype is:
127  * void WINAPI EXC_RaiseException(DWORD dwExceptionCode,
128  *                                DWORD dwExceptionFlags,
129  *                                DWORD cArguments,
130  *                                const LPDWORD lpArguments );
131  */
132 REGS_ENTRYPOINT(RaiseException)
133 {
134     PEXCEPTION_FRAME    pframe; 
135     EXCEPTION_RECORD    record;
136     DWORD               dispatch; /* is this used in raising exceptions ?? */
137     int                 retval;
138     int                 i;
139
140     /* Get the arguments from the stack */
141
142     DWORD ret                 = STACK32_POP(context);  /* return addr */
143     DWORD dwExceptionCode     = STACK32_POP(context);
144     DWORD dwExceptionFlags    = STACK32_POP(context);
145     DWORD cArguments          = STACK32_POP(context);
146     const LPDWORD lpArguments = (LPDWORD)STACK32_POP(context);
147     STACK32_PUSH(context,ret);  /* Restore the return address */
148
149     /* compose an exception record */ 
150     
151     record.ExceptionCode       = dwExceptionCode;   
152     record.ExceptionFlags      = dwExceptionFlags;
153     record.ExceptionRecord     = NULL;
154     record.NumberParameters    = cArguments;
155     record.ExceptionAddress    = (LPVOID)EIP_reg(context);
156     
157     if (lpArguments) for( i = 0; i < cArguments; i++)
158         record.ExceptionInformation[i] = lpArguments[i];
159     
160     /* get chain of exception frames */    
161     
162     retval = ExceptionContinueSearch;    
163     pframe = TEB_EXCEPTION_FRAME( context );
164     
165     while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
166     {
167        PEXCEPTION_FRAME    prevframe; 
168        TRACE_(win32)("calling exception handler at 0x%x\n",
169                                                 (int) pframe->Handler);
170        dispatch=0;  
171        TRACE_(relay)("(except=%p,record=%p,frame=%p,context=%p,dispatch=%p)\n",
172                      pframe->Handler, &record, pframe, context, &dispatch );
173        prevframe = pframe->Prev;
174        retval=pframe->Handler(&record,pframe,context,&dispatch);
175  
176        TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
177                               retval, (int) dispatch);
178                               
179        if(retval==ExceptionContinueExecution)
180           break;
181        pframe=prevframe;
182    }
183
184    if (retval!=ExceptionContinueExecution)
185    {    
186        /* FIXME: what should we do here? */
187        TRACE_(win32)("no handler wanted to handle the exception, exiting\n");
188        ExitProcess(dwExceptionCode); /* what status should be used here ? */
189    }
190 }
191
192
193 /*******************************************************************
194  *         UnhandledExceptionFilter   (KERNEL32.537)
195  */
196 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
197 {
198     char message[80];
199     PDB *pdb = PROCESS_Current();
200
201     /* FIXME: Should check if the process is being debugged */
202
203     if (pdb->top_filter)
204     {
205         DWORD ret = pdb->top_filter( epointers );
206         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
207     }
208
209     /* FIXME: Should check the current error mode */
210
211     sprintf( message, "Unhandled exception 0x%08lx at address 0x%08lx.",
212              epointers->ExceptionRecord->ExceptionCode,
213              (DWORD)epointers->ExceptionRecord->ExceptionAddress );
214     MessageBoxA( 0, message, "Error", MB_OK | MB_ICONHAND );
215     return EXCEPTION_EXECUTE_HANDLER;
216 }
217
218
219 /*************************************************************
220  *            SetUnhandledExceptionFilter   (KERNEL32.516)
221  */
222 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
223                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
224 {
225     PDB *pdb = PROCESS_Current();
226     LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
227     pdb->top_filter = filter;
228     return old;
229 }