Extended the winmm joystick API calls to support the new Linux
[wine] / dlls / ntdll / exception.c
1 /*
2  * NT exception handling routines
3  * 
4  * Copyright 1999 Turchanov Sergey
5  * Copyright 1999 Alexandre Julliard
6  */
7
8 #include <signal.h>
9 #include "winnt.h"
10 #include "ntddk.h"
11 #include "process.h"
12 #include "global.h"
13 #include "wine/exception.h"
14 #include "stackframe.h"
15 #include "miscemu.h"
16 #include "debugger.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(seh)
20
21 /* Exception record for handling exceptions happening inside exception handlers */
22 typedef struct
23 {
24     EXCEPTION_FRAME frame;
25     EXCEPTION_FRAME *prevFrame;
26 } EXC_NESTED_FRAME;
27
28  
29 /*******************************************************************
30  *         EXC_RaiseHandler
31  *
32  * Handler for exceptions happening inside a handler.
33  */
34 static DWORD EXC_RaiseHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
35                                CONTEXT *context, EXCEPTION_FRAME **dispatcher )
36 {
37     if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
38         return ExceptionContinueSearch;
39     /* We shouldn't get here so we store faulty frame in dispatcher */
40     *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
41     return ExceptionNestedException;
42 }
43
44
45 /*******************************************************************
46  *         EXC_UnwindHandler
47  *
48  * Handler for exceptions happening inside an unwind handler.
49  */
50 static DWORD EXC_UnwindHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
51                                 CONTEXT *context, EXCEPTION_FRAME **dispatcher )
52 {
53     if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
54         return ExceptionContinueSearch;
55     /* We shouldn't get here so we store faulty frame in dispatcher */
56     *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
57     return ExceptionCollidedUnwind;
58 }
59
60
61 /*******************************************************************
62  *         EXC_CallHandler
63  *
64  * Call an exception handler, setting up an exception frame to catch exceptions
65  * happening during the handler execution.
66  * Please do not change the first 4 parameters order in any way - some exceptions handlers
67  * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
68  */
69 static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
70                               CONTEXT *context, EXCEPTION_FRAME **dispatcher, 
71                               PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler)
72 {
73     EXC_NESTED_FRAME newframe;
74     DWORD ret;
75
76     newframe.frame.Handler = nested_handler;
77     newframe.prevFrame     = frame;
78     EXC_push_frame( &newframe.frame );
79     TRACE( "calling handler at %p code=%lx flags=%lx\n",
80            handler, record->ExceptionCode, record->ExceptionFlags );
81     ret = handler( record, frame, context, dispatcher );
82     TRACE( "handler returned %lx\n", ret );
83     EXC_pop_frame( &newframe.frame );
84     return ret;
85 }
86
87
88 /*******************************************************************
89  *         EXC_DefaultHandling
90  *
91  * Default handling for exceptions. Called when we didn't find a suitable handler.
92  */
93 static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
94 {
95     if ((PROCESS_Current()->flags & PDB32_DEBUGGED) &&
96         (DEBUG_SendExceptionEvent( rec, FALSE, context ) == DBG_CONTINUE))
97         return;  /* continue execution */
98
99     if (wine_debugger( rec, context, FALSE ) == DBG_CONTINUE)
100         return;  /* continue execution */
101
102     if (rec->ExceptionFlags & EH_STACK_INVALID)
103         ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
104     else if (rec->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION)
105         ERR("Process attempted to continue execution after noncontinuable exception.\n");
106     else
107         ERR("Unhandled exception code %lx flags %lx addr %p\n",
108             rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
109     TerminateProcess( GetCurrentProcess(), 1 );
110 }
111
112
113 /***********************************************************************
114  *            EXC_RtlRaiseException / RtlRaiseException (NTDLL.464)
115  */
116 DEFINE_REGS_ENTRYPOINT_1( RtlRaiseException, EXC_RtlRaiseException, EXCEPTION_RECORD * )
117 void WINAPI EXC_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
118 {
119     PEXCEPTION_FRAME frame, dispatch, nested_frame;
120     EXCEPTION_RECORD newrec;
121     DWORD res;
122
123     TRACE( "code=%lx flags=%lx\n", rec->ExceptionCode, rec->ExceptionFlags );
124
125     if ((PROCESS_Current()->flags & PDB32_DEBUGGED) &&
126         (DEBUG_SendExceptionEvent( rec, TRUE, context ) == DBG_CONTINUE))
127         return;  /* continue execution */
128
129     if (wine_debugger( rec, context, TRUE ) == DBG_CONTINUE)
130         return;  /* continue execution */
131
132     frame = NtCurrentTeb()->except;
133     nested_frame = NULL;
134     while (frame != (PEXCEPTION_FRAME)0xFFFFFFFF)
135     {
136         /* Check frame address */
137         if (((void*)frame < NtCurrentTeb()->stack_low) ||
138             ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
139             (int)frame & 3)
140         {
141             rec->ExceptionFlags |= EH_STACK_INVALID;
142             break;
143         }
144
145         /* Call handler */
146         res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, EXC_RaiseHandler );
147         if (frame == nested_frame)
148         {
149             /* no longer nested */
150             nested_frame = NULL;
151             rec->ExceptionFlags &= ~EH_NESTED_CALL;
152         }
153
154         switch(res)
155         {
156         case ExceptionContinueExecution:
157             if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return;
158             newrec.ExceptionCode    = STATUS_NONCONTINUABLE_EXCEPTION;
159             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
160             newrec.ExceptionRecord  = rec;
161             newrec.NumberParameters = 0;
162             RtlRaiseException( &newrec );  /* never returns */
163             break;
164         case ExceptionContinueSearch:
165             break;
166         case ExceptionNestedException:
167             if (nested_frame < dispatch) nested_frame = dispatch;
168             rec->ExceptionFlags |= EH_NESTED_CALL;
169             break;
170         default:
171             newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
172             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
173             newrec.ExceptionRecord  = rec;
174             newrec.NumberParameters = 0;
175             RtlRaiseException( &newrec );  /* never returns */
176             break;
177         }
178         frame = frame->Prev;
179     }
180     EXC_DefaultHandling( rec, context );
181 }
182
183
184 /*******************************************************************
185  *         EXC_RtlUnwind / RtlUnwind  (KERNEL32.590) (NTDLL.518)
186  */
187 DEFINE_REGS_ENTRYPOINT_4( RtlUnwind, EXC_RtlUnwind, 
188                           PEXCEPTION_FRAME, LPVOID, PEXCEPTION_RECORD, DWORD )
189 void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, 
190                            PEXCEPTION_RECORD pRecord, DWORD returnEax,
191                            CONTEXT *context )
192 {
193     EXCEPTION_RECORD record, newrec;
194     PEXCEPTION_FRAME frame, dispatch;
195
196 #ifdef __i386__
197     context->Eax = returnEax;
198 #endif
199
200     /* build an exception record, if we do not have one */
201     if (!pRecord)
202     {
203         record.ExceptionCode    = STATUS_UNWIND;
204         record.ExceptionFlags   = 0;
205         record.ExceptionRecord  = NULL;
206         record.ExceptionAddress = GET_IP(context); 
207         record.NumberParameters = 0;
208         pRecord = &record;
209     }
210
211     pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
212
213     TRACE( "code=%lx flags=%lx\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );
214
215     /* get chain of exception frames */
216     frame = NtCurrentTeb()->except;
217     while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame))
218     {
219         /* Check frame address */
220         if (pEndFrame && (frame > pEndFrame))
221         {
222             newrec.ExceptionCode    = STATUS_INVALID_UNWIND_TARGET;
223             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
224             newrec.ExceptionRecord  = pRecord;
225             newrec.NumberParameters = 0;
226             RtlRaiseException( &newrec );  /* never returns */
227         }
228         if (((void*)frame < NtCurrentTeb()->stack_low) ||
229             ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
230             (int)frame & 3)
231         {
232             newrec.ExceptionCode    = STATUS_BAD_STACK;
233             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
234             newrec.ExceptionRecord  = pRecord;
235             newrec.NumberParameters = 0;
236             RtlRaiseException( &newrec );  /* never returns */
237         }
238
239         /* Call handler */
240         switch(EXC_CallHandler( pRecord, frame, context, &dispatch,
241                                 frame->Handler, EXC_UnwindHandler ))
242         {
243         case ExceptionContinueSearch:
244             break;
245         case ExceptionCollidedUnwind:
246             frame = dispatch;
247             break;
248         default:
249             newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
250             newrec.ExceptionFlags   = EH_NONCONTINUABLE;
251             newrec.ExceptionRecord  = pRecord;
252             newrec.NumberParameters = 0;
253             RtlRaiseException( &newrec );  /* never returns */
254             break;
255         }
256         frame = EXC_pop_frame( frame );
257     }
258 }
259
260
261 /*******************************************************************
262  *            EXC_NtRaiseException / NtRaiseException  (NTDLL.175)
263  */
264 DEFINE_REGS_ENTRYPOINT_3( NtRaiseException, EXC_NtRaiseException,
265                           EXCEPTION_RECORD *, CONTEXT *, BOOL )
266 void WINAPI EXC_NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx,
267                                   BOOL first, CONTEXT *context )
268 {
269     EXC_RtlRaiseException( rec, ctx );
270     *context = *ctx;
271 }
272
273
274 /***********************************************************************
275  *            RtlRaiseStatus  (NTDLL.465)
276  *
277  * Raise an exception with ExceptionCode = status
278  */
279 void WINAPI RtlRaiseStatus( NTSTATUS status )
280 {
281     EXCEPTION_RECORD ExceptionRec;
282
283     ExceptionRec.ExceptionCode    = status;
284     ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
285     ExceptionRec.ExceptionRecord  = NULL;
286     ExceptionRec.NumberParameters = 0;
287     RtlRaiseException( &ExceptionRec );
288 }
289
290
291 /***********************************************************************
292  *           EXC_DebugBreak / DebugBreak (KERNEL32.181)
293  */
294 DEFINE_REGS_ENTRYPOINT_0( DebugBreak, EXC_DebugBreak )
295 void WINAPI EXC_DebugBreak( CONTEXT *context )
296 {
297     EXCEPTION_RECORD rec;
298
299     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
300     rec.ExceptionFlags   = 0;
301     rec.ExceptionRecord  = NULL;
302     rec.NumberParameters = 0;
303     EXC_RtlRaiseException( &rec, context );
304 }
305
306
307 /***********************************************************************
308  *           DebugBreak16   (KERNEL.203)
309  */
310 void WINAPI DebugBreak16( CONTEXT86 *context )
311 {
312 #ifdef __i386__
313     EXC_DebugBreak( context );
314 #endif  /* defined(__i386__) */
315 }