Made the output of --debugmsg +seh a bit more verbose.
[wine/multimedia.git] / dlls / ntdll / exception.c
blob96e7c52099b38cdca1fc75899be325de70de7515
1 /*
2 * NT exception handling routines
3 *
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
6 */
8 #include "config.h"
10 #include <assert.h>
11 #include <signal.h>
13 #include "winnt.h"
14 #include "ntddk.h"
15 #include "global.h"
16 #include "wine/exception.h"
17 #include "stackframe.h"
18 #include "miscemu.h"
19 #include "wine/server.h"
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(seh);
24 /* Exception record for handling exceptions happening inside exception handlers */
25 typedef struct
27 EXCEPTION_FRAME frame;
28 EXCEPTION_FRAME *prevFrame;
29 } EXC_NESTED_FRAME;
31 #ifdef __i386__
32 # define GET_IP(context) ((LPVOID)(context)->Eip)
33 #endif
34 #ifdef __sparc__
35 # define GET_IP(context) ((LPVOID)(context)->pc)
36 #endif
37 #ifndef GET_IP
38 # error You must define GET_IP for this CPU
39 #endif
41 extern void SIGNAL_Unblock(void);
43 void WINAPI EXC_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
44 void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME, LPVOID,
45 PEXCEPTION_RECORD, DWORD, PCONTEXT );
46 void WINAPI EXC_NtRaiseException( PEXCEPTION_RECORD, PCONTEXT,
47 BOOL, PCONTEXT );
49 /*******************************************************************
50 * EXC_RaiseHandler
52 * Handler for exceptions happening inside a handler.
54 static DWORD EXC_RaiseHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
55 CONTEXT *context, EXCEPTION_FRAME **dispatcher )
57 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
58 return ExceptionContinueSearch;
59 /* We shouldn't get here so we store faulty frame in dispatcher */
60 *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
61 return ExceptionNestedException;
65 /*******************************************************************
66 * EXC_UnwindHandler
68 * Handler for exceptions happening inside an unwind handler.
70 static DWORD EXC_UnwindHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
71 CONTEXT *context, EXCEPTION_FRAME **dispatcher )
73 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
74 return ExceptionContinueSearch;
75 /* We shouldn't get here so we store faulty frame in dispatcher */
76 *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
77 return ExceptionCollidedUnwind;
81 /*******************************************************************
82 * EXC_CallHandler
84 * Call an exception handler, setting up an exception frame to catch exceptions
85 * happening during the handler execution.
86 * Please do not change the first 4 parameters order in any way - some exceptions handlers
87 * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
89 static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
90 CONTEXT *context, EXCEPTION_FRAME **dispatcher,
91 PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler)
93 EXC_NESTED_FRAME newframe;
94 DWORD ret;
96 newframe.frame.Handler = nested_handler;
97 newframe.prevFrame = frame;
98 __wine_push_frame( &newframe.frame );
99 TRACE( "calling handler at %p code=%lx flags=%lx\n",
100 handler, record->ExceptionCode, record->ExceptionFlags );
101 ret = handler( record, frame, context, dispatcher );
102 TRACE( "handler returned %lx\n", ret );
103 __wine_pop_frame( &newframe.frame );
104 return ret;
108 /**********************************************************************
109 * send_debug_event
111 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
113 static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
115 int ret;
116 HANDLE handle = 0;
118 SERVER_START_REQ( queue_exception_event )
120 req->first = first_chance;
121 wine_server_add_data( req, context, sizeof(*context) );
122 wine_server_add_data( req, rec, sizeof(*rec) );
123 if (!wine_server_call( req )) handle = reply->handle;
125 SERVER_END_REQ;
126 if (!handle) return 0; /* no debugger present or other error */
128 /* No need to wait on the handle since the process gets suspended
129 * once the event is passed to the debugger, so when we get back
130 * here the event has been continued already.
132 SERVER_START_REQ( get_exception_status )
134 req->handle = handle;
135 wine_server_set_reply( req, context, sizeof(*context) );
136 wine_server_call( req );
137 ret = reply->status;
139 SERVER_END_REQ;
140 NtClose( handle );
141 return ret;
145 /*******************************************************************
146 * EXC_DefaultHandling
148 * Default handling for exceptions. Called when we didn't find a suitable handler.
150 static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
152 if (send_debug_event( rec, FALSE, context ) == DBG_CONTINUE) return; /* continue execution */
154 if (rec->ExceptionFlags & EH_STACK_INVALID)
155 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
156 else if (rec->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION)
157 ERR("Process attempted to continue execution after noncontinuable exception.\n");
158 else
159 ERR("Unhandled exception code %lx flags %lx addr %p\n",
160 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
161 NtTerminateProcess( NtCurrentProcess(), 1 );
165 /***********************************************************************
166 * RtlRaiseException (NTDLL.@)
168 DEFINE_REGS_ENTRYPOINT_1( RtlRaiseException, EXC_RtlRaiseException, EXCEPTION_RECORD * );
169 void WINAPI EXC_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
171 PEXCEPTION_FRAME frame, dispatch, nested_frame;
172 EXCEPTION_RECORD newrec;
173 DWORD res, c;
175 TRACE( "code=%lx flags=%lx addr=%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
176 for (c=0; c<rec->NumberParameters; c++) TRACE(" info[%ld]=%08lx\n", c, rec->ExceptionInformation[c]);
177 if (rec->ExceptionCode == EXCEPTION_WINE_STUB) TRACE(" stub=%s\n", (char*)rec->ExceptionInformation[1]);
179 if (send_debug_event( rec, TRUE, context ) == DBG_CONTINUE) return; /* continue execution */
181 SIGNAL_Unblock(); /* we may be in a signal handler, and exception handlers may jump out */
183 frame = NtCurrentTeb()->except;
184 nested_frame = NULL;
185 while (frame != (PEXCEPTION_FRAME)0xFFFFFFFF)
187 /* Check frame address */
188 if (((void*)frame < NtCurrentTeb()->stack_low) ||
189 ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
190 (int)frame & 3)
192 rec->ExceptionFlags |= EH_STACK_INVALID;
193 break;
196 /* Call handler */
197 res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, EXC_RaiseHandler );
198 if (frame == nested_frame)
200 /* no longer nested */
201 nested_frame = NULL;
202 rec->ExceptionFlags &= ~EH_NESTED_CALL;
205 switch(res)
207 case ExceptionContinueExecution:
208 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return;
209 newrec.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
210 newrec.ExceptionFlags = EH_NONCONTINUABLE;
211 newrec.ExceptionRecord = rec;
212 newrec.NumberParameters = 0;
213 RtlRaiseException( &newrec ); /* never returns */
214 break;
215 case ExceptionContinueSearch:
216 break;
217 case ExceptionNestedException:
218 if (nested_frame < dispatch) nested_frame = dispatch;
219 rec->ExceptionFlags |= EH_NESTED_CALL;
220 break;
221 default:
222 newrec.ExceptionCode = STATUS_INVALID_DISPOSITION;
223 newrec.ExceptionFlags = EH_NONCONTINUABLE;
224 newrec.ExceptionRecord = rec;
225 newrec.NumberParameters = 0;
226 RtlRaiseException( &newrec ); /* never returns */
227 break;
229 frame = frame->Prev;
231 EXC_DefaultHandling( rec, context );
235 /*******************************************************************
236 * RtlUnwind (NTDLL.@)
238 DEFINE_REGS_ENTRYPOINT_4( RtlUnwind, EXC_RtlUnwind,
239 PEXCEPTION_FRAME, LPVOID, PEXCEPTION_RECORD, DWORD );
240 void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
241 PEXCEPTION_RECORD pRecord, DWORD returnEax,
242 CONTEXT *context )
244 EXCEPTION_RECORD record, newrec;
245 PEXCEPTION_FRAME frame, dispatch;
247 #ifdef __i386__
248 context->Eax = returnEax;
249 #endif
251 /* build an exception record, if we do not have one */
252 if (!pRecord)
254 record.ExceptionCode = STATUS_UNWIND;
255 record.ExceptionFlags = 0;
256 record.ExceptionRecord = NULL;
257 record.ExceptionAddress = GET_IP(context);
258 record.NumberParameters = 0;
259 pRecord = &record;
262 pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
264 TRACE( "code=%lx flags=%lx\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );
266 /* get chain of exception frames */
267 frame = NtCurrentTeb()->except;
268 while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame))
270 /* Check frame address */
271 if (pEndFrame && (frame > pEndFrame))
273 newrec.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
274 newrec.ExceptionFlags = EH_NONCONTINUABLE;
275 newrec.ExceptionRecord = pRecord;
276 newrec.NumberParameters = 0;
277 RtlRaiseException( &newrec ); /* never returns */
279 if (((void*)frame < NtCurrentTeb()->stack_low) ||
280 ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
281 (int)frame & 3)
283 newrec.ExceptionCode = STATUS_BAD_STACK;
284 newrec.ExceptionFlags = EH_NONCONTINUABLE;
285 newrec.ExceptionRecord = pRecord;
286 newrec.NumberParameters = 0;
287 RtlRaiseException( &newrec ); /* never returns */
290 /* Call handler */
291 switch(EXC_CallHandler( pRecord, frame, context, &dispatch,
292 frame->Handler, EXC_UnwindHandler ))
294 case ExceptionContinueSearch:
295 break;
296 case ExceptionCollidedUnwind:
297 frame = dispatch;
298 break;
299 default:
300 newrec.ExceptionCode = STATUS_INVALID_DISPOSITION;
301 newrec.ExceptionFlags = EH_NONCONTINUABLE;
302 newrec.ExceptionRecord = pRecord;
303 newrec.NumberParameters = 0;
304 RtlRaiseException( &newrec ); /* never returns */
305 break;
307 frame = __wine_pop_frame( frame );
312 /*******************************************************************
313 * NtRaiseException (NTDLL.@)
315 DEFINE_REGS_ENTRYPOINT_3( NtRaiseException, EXC_NtRaiseException,
316 EXCEPTION_RECORD *, CONTEXT *, BOOL );
317 void WINAPI EXC_NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx,
318 BOOL first, CONTEXT *context )
320 EXC_RtlRaiseException( rec, ctx );
321 *context = *ctx;
325 /***********************************************************************
326 * RtlRaiseStatus (NTDLL.@)
328 * Raise an exception with ExceptionCode = status
330 void WINAPI RtlRaiseStatus( NTSTATUS status )
332 EXCEPTION_RECORD ExceptionRec;
334 ExceptionRec.ExceptionCode = status;
335 ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
336 ExceptionRec.ExceptionRecord = NULL;
337 ExceptionRec.NumberParameters = 0;
338 RtlRaiseException( &ExceptionRec );
342 /*************************************************************
343 * __wine_exception_handler (NTDLL.@)
345 * Exception handler for exception blocks declared in Wine code.
347 DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
348 CONTEXT *context, LPVOID pdispatcher )
350 __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
352 if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
353 return ExceptionContinueSearch;
354 if (wine_frame->u.filter)
356 EXCEPTION_POINTERS ptrs;
357 ptrs.ExceptionRecord = record;
358 ptrs.ContextRecord = context;
359 switch(wine_frame->u.filter( &ptrs ))
361 case EXCEPTION_CONTINUE_SEARCH:
362 return ExceptionContinueSearch;
363 case EXCEPTION_CONTINUE_EXECUTION:
364 return ExceptionContinueExecution;
365 case EXCEPTION_EXECUTE_HANDLER:
366 break;
367 default:
368 MESSAGE( "Invalid return value from exception filter\n" );
369 assert( FALSE );
372 /* hack to make GetExceptionCode() work in handler */
373 wine_frame->ExceptionCode = record->ExceptionCode;
374 wine_frame->ExceptionRecord = wine_frame;
376 RtlUnwind( frame, 0, record, 0 );
377 __wine_pop_frame( frame );
378 longjmp( wine_frame->jmp, 1 );
382 /*************************************************************
383 * __wine_finally_handler (NTDLL.@)
385 * Exception handler for try/finally blocks declared in Wine code.
387 DWORD __wine_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
388 CONTEXT *context, LPVOID pdispatcher )
390 __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
392 if (!(record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
393 return ExceptionContinueSearch;
394 wine_frame->u.finally_func( FALSE );
395 return ExceptionContinueSearch;