Don't send an extra signal when waiting for a debug event, just do a
[wine] / dlls / ntdll / exception.c
1 /*
2  * NT exception handling routines
3  *
4  * Copyright 1999 Turchanov Sergey
5  * Copyright 1999 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <signal.h>
27 #include <stdarg.h>
28
29 #include "ntstatus.h"
30 #include "windef.h"
31 #include "winternl.h"
32 #include "wine/exception.h"
33 #include "wine/server.h"
34 #include "wine/list.h"
35 #include "wine/debug.h"
36 #include "excpt.h"
37 #include "ntdll_misc.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(seh);
40
41 /* Exception record for handling exceptions happening inside exception handlers */
42 typedef struct
43 {
44     EXCEPTION_REGISTRATION_RECORD frame;
45     EXCEPTION_REGISTRATION_RECORD *prevFrame;
46 } EXC_NESTED_FRAME;
47
48 typedef struct
49 {
50     struct list                 entry;
51     PVECTORED_EXCEPTION_HANDLER func;
52 } VECTORED_HANDLER;
53
54 static struct list vectored_handlers = LIST_INIT(vectored_handlers);
55
56 static RTL_CRITICAL_SECTION vectored_handlers_section;
57 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
58 {
59     0, 0, &vectored_handlers_section,
60     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
61       0, 0, { (DWORD_PTR)(__FILE__ ": vectored_handlers_section") }
62 };
63 static RTL_CRITICAL_SECTION vectored_handlers_section = { &critsect_debug, -1, 0, 0, 0, 0 };
64
65 #ifdef __i386__
66 # define GET_IP(context) ((LPVOID)(context)->Eip)
67 #elif defined(__sparc__)
68 # define GET_IP(context) ((LPVOID)(context)->pc)
69 #elif defined(__powerpc__)
70 # define GET_IP(context) ((LPVOID)(context)->Iar)
71 #elif defined(__ALPHA__)
72 # define GET_IP(context) ((LPVOID)(context)->Fir)
73 #elif defined(__x86_64__)
74 # define GET_IP(context) ((LPVOID)(context)->Rip)
75 #else
76 # error You must define GET_IP for this CPU
77 #endif
78
79
80 /*******************************************************************
81  *         EXC_RaiseHandler
82  *
83  * Handler for exceptions happening inside a handler.
84  */
85 static DWORD EXC_RaiseHandler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
86                                CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
87 {
88     if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
89         return ExceptionContinueSearch;
90     /* We shouldn't get here so we store faulty frame in dispatcher */
91     *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
92     return ExceptionNestedException;
93 }
94
95
96 /*******************************************************************
97  *         EXC_UnwindHandler
98  *
99  * Handler for exceptions happening inside an unwind handler.
100  */
101 static DWORD EXC_UnwindHandler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
102                                 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
103 {
104     if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
105         return ExceptionContinueSearch;
106     /* We shouldn't get here so we store faulty frame in dispatcher */
107     *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
108     return ExceptionCollidedUnwind;
109 }
110
111
112 /*******************************************************************
113  *         EXC_CallHandler
114  *
115  * Call an exception handler, setting up an exception frame to catch exceptions
116  * happening during the handler execution.
117  *
118  * For i386 this function is implemented in assembler in signal_i386.c.
119  */
120 #ifndef __i386__
121 static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
122                               CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher,
123                               PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler)
124 {
125     EXC_NESTED_FRAME newframe;
126     DWORD ret;
127
128     newframe.frame.Handler = nested_handler;
129     newframe.prevFrame     = frame;
130     __wine_push_frame( &newframe.frame );
131     TRACE( "calling handler at %p code=%lx flags=%lx\n",
132            handler, record->ExceptionCode, record->ExceptionFlags );
133     ret = handler( record, frame, context, dispatcher );
134     TRACE( "handler returned %lx\n", ret );
135     __wine_pop_frame( &newframe.frame );
136     return ret;
137 }
138 #else
139 /* in signal_i386.c */
140 extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
141                               CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher,
142                               PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler);
143 #endif
144
145 /**********************************************************************
146  *           send_debug_event
147  *
148  * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
149  */
150 static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
151 {
152     int ret;
153     HANDLE handle = 0;
154
155     if (!NtCurrentTeb()->Peb->BeingDebugged) return 0;  /* no debugger present */
156
157     SERVER_START_REQ( queue_exception_event )
158     {
159         req->first   = first_chance;
160         wine_server_add_data( req, context, sizeof(*context) );
161         wine_server_add_data( req, rec, sizeof(*rec) );
162         if (!wine_server_call( req )) handle = reply->handle;
163     }
164     SERVER_END_REQ;
165     if (!handle) return 0;
166
167     NTDLL_wait_for_multiple_objects( 1, &handle, 0, NULL, 0 );
168
169     SERVER_START_REQ( get_exception_status )
170     {
171         req->handle = handle;
172         wine_server_set_reply( req, context, sizeof(*context) );
173         ret = wine_server_call( req );
174     }
175     SERVER_END_REQ;
176     return ret;
177 }
178
179
180 /**********************************************************************
181  *           call_vectored_handlers
182  *
183  * Call the vectored handlers chain.
184  */
185 static LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
186 {
187     struct list *ptr;
188     LONG ret = EXCEPTION_CONTINUE_SEARCH;
189     EXCEPTION_POINTERS except_ptrs;
190
191     except_ptrs.ExceptionRecord = rec;
192     except_ptrs.ContextRecord = context;
193
194     RtlEnterCriticalSection( &vectored_handlers_section );
195     LIST_FOR_EACH( ptr, &vectored_handlers )
196     {
197         VECTORED_HANDLER *handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
198         ret = handler->func( &except_ptrs );
199         if (ret == EXCEPTION_CONTINUE_EXECUTION) break;
200     }
201     RtlLeaveCriticalSection( &vectored_handlers_section );
202     return ret;
203 }
204
205
206 /*******************************************************************
207  *         EXC_DefaultHandling
208  *
209  * Default handling for exceptions. Called when we didn't find a suitable handler.
210  */
211 static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
212 {
213     if (send_debug_event( rec, FALSE, context ) == DBG_CONTINUE) return;  /* continue execution */
214
215     if (rec->ExceptionFlags & EH_STACK_INVALID)
216         ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
217     else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
218         ERR("Process attempted to continue execution after noncontinuable exception.\n");
219     else
220         ERR("Unhandled exception code %lx flags %lx addr %p\n",
221             rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
222     NtTerminateProcess( NtCurrentProcess(), 1 );
223 }
224
225
226 /***********************************************************************
227  *              RtlRaiseException (NTDLL.@)
228  */
229 void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
230 {
231     EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
232     EXCEPTION_RECORD newrec;
233     DWORD res, c;
234
235     TRACE( "code=%lx flags=%lx addr=%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
236     for (c=0; c<rec->NumberParameters; c++) TRACE(" info[%ld]=%08lx\n", c, rec->ExceptionInformation[c]);
237     if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
238     {
239         if (HIWORD(rec->ExceptionInformation[1]))
240             MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
241                    rec->ExceptionAddress,
242                    (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
243         else
244             MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
245                    rec->ExceptionAddress,
246                    (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
247     }
248 #ifdef __i386__
249     else
250     {
251         TRACE(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
252               context->Eax, context->Ebx, context->Ecx,
253               context->Edx, context->Esi, context->Edi );
254         TRACE(" ebp=%08lx esp=%08lx cs=%04lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
255               context->Ebp, context->Esp, context->SegCs, context->SegDs,
256               context->SegEs, context->SegFs, context->SegGs, context->EFlags );
257     }
258 #endif
259
260     if (send_debug_event( rec, TRUE, context ) == DBG_CONTINUE) return;  /* continue execution */
261
262     if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION) return;
263
264     frame = NtCurrentTeb()->Tib.ExceptionList;
265     nested_frame = NULL;
266     while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
267     {
268         /* Check frame address */
269         if (((void*)frame < NtCurrentTeb()->Tib.StackLimit) ||
270             ((void*)(frame+1) > NtCurrentTeb()->Tib.StackBase) ||
271             (ULONG_PTR)frame & 3)
272         {
273             rec->ExceptionFlags |= EH_STACK_INVALID;
274             break;
275         }
276
277         /* Call handler */
278         res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, EXC_RaiseHandler );
279         if (frame == nested_frame)
280         {
281             /* no longer nested */
282             nested_frame = NULL;
283             rec->ExceptionFlags &= ~EH_NESTED_CALL;
284         }
285
286         switch(res)
287         {
288         case ExceptionContinueExecution:
289             if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return;
290             newrec.ExceptionCode    = STATUS_NONCONTINUABLE_EXCEPTION;
291             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
292             newrec.ExceptionRecord  = rec;
293             newrec.NumberParameters = 0;
294             RtlRaiseException( &newrec );  /* never returns */
295             break;
296         case ExceptionContinueSearch:
297             break;
298         case ExceptionNestedException:
299             if (nested_frame < dispatch) nested_frame = dispatch;
300             rec->ExceptionFlags |= EH_NESTED_CALL;
301             break;
302         default:
303             newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
304             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
305             newrec.ExceptionRecord  = rec;
306             newrec.NumberParameters = 0;
307             RtlRaiseException( &newrec );  /* never returns */
308             break;
309         }
310         frame = frame->Prev;
311     }
312     EXC_DefaultHandling( rec, context );
313 }
314
315 /**********************************************************************/
316
317 #ifdef DEFINE_REGS_ENTRYPOINT
318 DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 4, 4 );
319 #else
320 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
321 {
322     CONTEXT context;
323     memset( &context, 0, sizeof(context) );
324     __regs_RtlRaiseException( rec, &context );
325 }
326 #endif
327
328
329 /*******************************************************************
330  *              RtlUnwind (NTDLL.@)
331  */
332 void WINAPI __regs_RtlUnwind( EXCEPTION_REGISTRATION_RECORD* pEndFrame, PVOID unusedEip,
333                               PEXCEPTION_RECORD pRecord, PVOID returnEax, CONTEXT *context )
334 {
335     EXCEPTION_RECORD record, newrec;
336     EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
337
338 #ifdef __i386__
339     context->Eax = (DWORD)returnEax;
340 #endif
341
342     /* build an exception record, if we do not have one */
343     if (!pRecord)
344     {
345         record.ExceptionCode    = STATUS_UNWIND;
346         record.ExceptionFlags   = 0;
347         record.ExceptionRecord  = NULL;
348         record.ExceptionAddress = GET_IP(context);
349         record.NumberParameters = 0;
350         pRecord = &record;
351     }
352
353     pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
354
355     TRACE( "code=%lx flags=%lx\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );
356
357     /* get chain of exception frames */
358     frame = NtCurrentTeb()->Tib.ExceptionList;
359     while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != pEndFrame))
360     {
361         /* Check frame address */
362         if (pEndFrame && (frame > pEndFrame))
363         {
364             newrec.ExceptionCode    = STATUS_INVALID_UNWIND_TARGET;
365             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
366             newrec.ExceptionRecord  = pRecord;
367             newrec.NumberParameters = 0;
368             RtlRaiseException( &newrec );  /* never returns */
369         }
370         if (((void*)frame < NtCurrentTeb()->Tib.StackLimit) ||
371             ((void*)(frame+1) > NtCurrentTeb()->Tib.StackBase) ||
372             (UINT_PTR)frame & 3)
373         {
374             newrec.ExceptionCode    = STATUS_BAD_STACK;
375             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
376             newrec.ExceptionRecord  = pRecord;
377             newrec.NumberParameters = 0;
378             RtlRaiseException( &newrec );  /* never returns */
379         }
380
381         /* Call handler */
382         switch(EXC_CallHandler( pRecord, frame, context, &dispatch,
383                                 frame->Handler, EXC_UnwindHandler ))
384         {
385         case ExceptionContinueSearch:
386             break;
387         case ExceptionCollidedUnwind:
388             frame = dispatch;
389             break;
390         default:
391             newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
392             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
393             newrec.ExceptionRecord  = pRecord;
394             newrec.NumberParameters = 0;
395             RtlRaiseException( &newrec );  /* never returns */
396             break;
397         }
398         frame = __wine_pop_frame( frame );
399     }
400 }
401
402 /**********************************************************************/
403
404 #ifdef DEFINE_REGS_ENTRYPOINT
405 DEFINE_REGS_ENTRYPOINT( RtlUnwind, 16, 16 );
406 #else
407 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID unusedEip,
408                        PEXCEPTION_RECORD pRecord, PVOID returnEax )
409 {
410     CONTEXT context;
411     memset( &context, 0, sizeof(context) );
412     __regs_RtlUnwind( pEndFrame, unusedEip, pRecord, returnEax, &context );
413 }
414 #endif
415
416
417 /*******************************************************************
418  *              NtRaiseException (NTDLL.@)
419  */
420 void WINAPI __regs_NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx,
421                                   BOOL first, CONTEXT *context )
422 {
423     __regs_RtlRaiseException( rec, ctx );
424     *context = *ctx;
425 }
426
427 #ifdef DEFINE_REGS_ENTRYPOINT
428 DEFINE_REGS_ENTRYPOINT( NtRaiseException, 12, 12 );
429 #else
430 void WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx, BOOL first )
431 {
432     CONTEXT context;
433     memset( &context, 0, sizeof(context) );
434     __regs_NtRaiseException( rec, ctx, first, &context );
435 }
436 #endif
437
438
439 /***********************************************************************
440  *            RtlRaiseStatus  (NTDLL.@)
441  *
442  * Raise an exception with ExceptionCode = status
443  */
444 void WINAPI RtlRaiseStatus( NTSTATUS status )
445 {
446     EXCEPTION_RECORD ExceptionRec;
447
448     ExceptionRec.ExceptionCode    = status;
449     ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
450     ExceptionRec.ExceptionRecord  = NULL;
451     ExceptionRec.NumberParameters = 0;
452     RtlRaiseException( &ExceptionRec );
453 }
454
455
456 /*******************************************************************
457  *         RtlAddVectoredExceptionHandler   (NTDLL.@)
458  */
459 PVOID WINAPI RtlAddVectoredExceptionHandler( ULONG first, PVECTORED_EXCEPTION_HANDLER func )
460 {
461     VECTORED_HANDLER *handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) );
462     if (handler)
463     {
464         handler->func = func;
465         RtlEnterCriticalSection( &vectored_handlers_section );
466         if (first) list_add_head( &vectored_handlers, &handler->entry );
467         else list_add_tail( &vectored_handlers, &handler->entry );
468         RtlLeaveCriticalSection( &vectored_handlers_section );
469     }
470     return handler;
471 }
472
473
474 /*******************************************************************
475  *         RtlRemoveVectoredExceptionHandler   (NTDLL.@)
476  */
477 ULONG WINAPI RtlRemoveVectoredExceptionHandler( PVOID handler )
478 {
479     struct list *ptr;
480     ULONG ret = FALSE;
481
482     RtlEnterCriticalSection( &vectored_handlers_section );
483     LIST_FOR_EACH( ptr, &vectored_handlers )
484     {
485         VECTORED_HANDLER *curr_handler = LIST_ENTRY( ptr, VECTORED_HANDLER, entry );
486         if (curr_handler == handler)
487         {
488             list_remove( ptr );
489             ret = TRUE;
490             break;
491         }
492     }
493     RtlLeaveCriticalSection( &vectored_handlers_section );
494     if (ret) RtlFreeHeap( GetProcessHeap(), 0, handler );
495     return ret;
496 }
497
498
499 /*************************************************************
500  *            __wine_exception_handler (NTDLL.@)
501  *
502  * Exception handler for exception blocks declared in Wine code.
503  */
504 DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
505                                 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher )
506 {
507     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
508
509     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
510         return ExceptionContinueSearch;
511     if (wine_frame->u.filter)
512     {
513         EXCEPTION_POINTERS ptrs;
514         ptrs.ExceptionRecord = record;
515         ptrs.ContextRecord = context;
516         switch(wine_frame->u.filter( &ptrs ))
517         {
518         case EXCEPTION_CONTINUE_SEARCH:
519             return ExceptionContinueSearch;
520         case EXCEPTION_CONTINUE_EXECUTION:
521             return ExceptionContinueExecution;
522         case EXCEPTION_EXECUTE_HANDLER:
523             break;
524         default:
525             MESSAGE( "Invalid return value from exception filter\n" );
526             assert( FALSE );
527         }
528     }
529     /* hack to make GetExceptionCode() work in handler */
530     wine_frame->ExceptionCode   = record->ExceptionCode;
531     wine_frame->ExceptionRecord = wine_frame;
532
533     RtlUnwind( frame, 0, record, 0 );
534     __wine_pop_frame( frame );
535     siglongjmp( wine_frame->jmp, 1 );
536 }
537
538
539 /*************************************************************
540  *            __wine_finally_handler (NTDLL.@)
541  *
542  * Exception handler for try/finally blocks declared in Wine code.
543  */
544 DWORD __wine_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
545                               CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher )
546 {
547     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
548     {
549         __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
550         wine_frame->u.finally_func( FALSE );
551     }
552     return ExceptionContinueSearch;
553 }
554
555
556 /*************************************************************
557  *            __wine_spec_unimplemented_stub
558  *
559  * ntdll-specific implementation to avoid depending on kernel functions.
560  * Can be removed once ntdll.spec no longer contains stubs.
561  */
562 void __wine_spec_unimplemented_stub( const char *module, const char *function )
563 {
564     EXCEPTION_RECORD record;
565
566     record.ExceptionCode    = EXCEPTION_WINE_STUB;
567     record.ExceptionFlags   = EH_NONCONTINUABLE;
568     record.ExceptionRecord  = NULL;
569     record.ExceptionAddress = __wine_spec_unimplemented_stub;
570     record.NumberParameters = 2;
571     record.ExceptionInformation[0] = (ULONG_PTR)module;
572     record.ExceptionInformation[1] = (ULONG_PTR)function;
573     RtlRaiseException( &record );
574 }