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