2 * Win32 exception functions
4 * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
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
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).
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
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
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.
40 #include "debugtools.h"
42 #include "stackframe.h"
44 DECLARE_DEBUG_CHANNEL(relay)
45 DECLARE_DEBUG_CHANNEL(win32)
47 #define TEB_EXCEPTION_FRAME(pcontext) \
48 ((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
50 /*******************************************************************
51 * RtlUnwind (KERNEL32.443)
53 * This function is undocumented. This is the general idea of
54 * RtlUnwind, though. Note that error handling is not yet implemented.
56 * The real prototype is:
57 * void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
58 * PEXCEPTION_RECORD pRecord, DWORD returnEax );
60 REGS_ENTRYPOINT(RtlUnwind)
62 EXCEPTION_RECORD record;
65 PEXCEPTION_FRAME pEndFrame;
66 PEXCEPTION_RECORD pRecord;
68 /* get the arguments from the stack */
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 */
77 /* build an exception record, if we do not have one */
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;
89 pRecord->ExceptionFlags|=EH_UNWINDING;
91 pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
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))
98 TRACE_(win32)("calling exception handler at 0x%x\n",
99 (int)TEB_EXCEPTION_FRAME(context)->Handler );
102 retval = TEB_EXCEPTION_FRAME(context)->Handler( pRecord,
103 TEB_EXCEPTION_FRAME(context),
106 TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
107 retval, (int) dispatch);
109 if ( (retval == ExceptionCollidedUnwind) &&
110 (TEB_EXCEPTION_FRAME(context) != (LPVOID)dispatch)
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)
116 TEB_EXCEPTION_FRAME(context) = TEB_EXCEPTION_FRAME(context)->Prev;
123 /*******************************************************************
124 * RaiseException (KERNEL32.418)
126 * The real prototype is:
127 * void WINAPI EXC_RaiseException(DWORD dwExceptionCode,
128 * DWORD dwExceptionFlags,
130 * const LPDWORD lpArguments );
132 REGS_ENTRYPOINT(RaiseException)
134 PEXCEPTION_FRAME pframe;
135 EXCEPTION_RECORD record;
136 DWORD dispatch; /* is this used in raising exceptions ?? */
140 /* Get the arguments from the stack */
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 */
149 /* compose an exception record */
151 record.ExceptionCode = dwExceptionCode;
152 record.ExceptionFlags = dwExceptionFlags;
153 record.ExceptionRecord = NULL;
154 record.NumberParameters = cArguments;
155 record.ExceptionAddress = (LPVOID)EIP_reg(context);
157 if (lpArguments) for( i = 0; i < cArguments; i++)
158 record.ExceptionInformation[i] = lpArguments[i];
160 /* get chain of exception frames */
162 retval = ExceptionContinueSearch;
163 pframe = TEB_EXCEPTION_FRAME( context );
165 while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
167 PEXCEPTION_FRAME prevframe;
168 TRACE_(win32)("calling exception handler at 0x%x\n",
169 (int) pframe->Handler);
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);
176 TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
177 retval, (int) dispatch);
179 if(retval==ExceptionContinueExecution)
184 if (retval!=ExceptionContinueExecution)
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 ? */
193 /*******************************************************************
194 * UnhandledExceptionFilter (KERNEL32.537)
196 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
199 PDB *pdb = PROCESS_Current();
201 /* FIXME: Should check if the process is being debugged */
205 DWORD ret = pdb->top_filter( epointers );
206 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
209 /* FIXME: Should check the current error mode */
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;
219 /*************************************************************
220 * SetUnhandledExceptionFilter (KERNEL32.516)
222 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
223 LPTOP_LEVEL_EXCEPTION_FILTER filter )
225 PDB *pdb = PROCESS_Current();
226 LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
227 pdb->top_filter = filter;