2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Run-Time Library
4 * PURPOSE: User-mode exception support for IA-32
5 * FILE: lib/rtl/i386/exception.c
6 * PROGRAMERS: Alex Ionescu (alex@relsoft.net)
7 * Casper S. Hornstrup (chorns@users.sourceforge.net)
10 /* INCLUDES *****************************************************************/
16 /* PUBLIC FUNCTIONS **********************************************************/
23 RtlGetCallersAddress(OUT PVOID
*CallersAddress
,
24 OUT PVOID
*CallersCaller
)
28 PULONG BackTraceHash
= NULL
;
30 /* Get the tow back trace address */
31 FrameCount
= RtlCaptureStackBackTrace(2, 2, &BackTrace
[0],BackTraceHash
);
33 /* Only if user want it */
34 if (*CallersAddress
!= NULL
)
36 /* only when first frames exist */
39 *CallersAddress
= BackTrace
[0];
43 *CallersAddress
= NULL
;
47 /* Only if user want it */
48 if (*CallersCaller
!= NULL
)
50 /* only when second frames exist */
53 *CallersCaller
= BackTrace
[1];
57 *CallersCaller
= NULL
;
67 RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
70 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
, NestedFrame
= NULL
;
71 DISPATCHER_CONTEXT DispatcherContext
;
72 EXCEPTION_RECORD ExceptionRecord2
;
73 EXCEPTION_DISPOSITION Disposition
;
74 ULONG_PTR StackLow
, StackHigh
;
75 ULONG_PTR RegistrationFrameEnd
;
77 /* Perform vectored exception handling if we are in user mode */
78 if (RtlpGetMode() != KernelMode
)
80 /* Call any registered vectored handlers */
81 if (RtlCallVectoredExceptionHandlers(ExceptionRecord
, Context
))
83 /* Exception handled, continue execution */
88 /* Get the current stack limits and registration frame */
89 RtlpGetStackLimits(&StackLow
, &StackHigh
);
90 RegistrationFrame
= RtlpGetExceptionList();
92 /* Now loop every frame */
93 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
95 /* Find out where it ends */
96 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
97 sizeof(EXCEPTION_REGISTRATION_RECORD
);
99 /* Make sure the registration frame is located within the stack */
100 if ((RegistrationFrameEnd
> StackHigh
) ||
101 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
102 ((ULONG_PTR
)RegistrationFrame
& 0x3))
104 /* Check if this happened in the DPC Stack */
105 if (RtlpHandleDpcStackException(RegistrationFrame
,
106 RegistrationFrameEnd
,
110 /* Use DPC Stack Limits and restart */
114 /* Set invalid stack and return false */
115 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
119 /* Check if logging is enabled */
120 RtlpCheckLogException(ExceptionRecord
,
123 sizeof(*RegistrationFrame
));
125 /* Call the handler */
126 Disposition
= RtlpExecuteHandlerForException(ExceptionRecord
,
133 /* Check if this is a nested frame */
134 if (RegistrationFrame
== NestedFrame
)
136 /* Mask out the flag and the nested frame */
137 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
;
141 /* Handle the dispositions */
144 /* Continue searching */
145 case ExceptionContinueExecution
:
147 /* Check if it was non-continuable */
148 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
150 /* Set up the exception record */
151 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
152 ExceptionRecord2
.ExceptionCode
=
153 STATUS_NONCONTINUABLE_EXCEPTION
;
154 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
155 ExceptionRecord2
.NumberParameters
= 0;
157 /* Raise the exception */
158 RtlRaiseException(&ExceptionRecord2
);
162 /* Return to caller */
166 /* Continue searching */
167 case ExceptionContinueSearch
:
170 /* Nested exception */
171 case ExceptionNestedException
:
173 /* Turn the nested flag on */
174 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
176 /* Update the current nested frame */
177 if (DispatcherContext
.RegistrationPointer
> NestedFrame
)
179 /* Get the frame from the dispatcher context */
180 NestedFrame
= DispatcherContext
.RegistrationPointer
;
187 /* Set up the exception record */
188 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
189 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
190 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
191 ExceptionRecord2
.NumberParameters
= 0;
193 /* Raise the exception */
194 RtlRaiseException(&ExceptionRecord2
);
198 /* Go to the next frame */
199 RegistrationFrame
= RegistrationFrame
->Next
;
202 /* Unhandled, return false */
211 RtlUnwind(IN PVOID TargetFrame OPTIONAL
,
212 IN PVOID TargetIp OPTIONAL
,
213 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
214 IN PVOID ReturnValue
)
216 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
, OldFrame
;
217 DISPATCHER_CONTEXT DispatcherContext
;
218 EXCEPTION_RECORD ExceptionRecord2
, ExceptionRecord3
;
219 EXCEPTION_DISPOSITION Disposition
;
220 ULONG_PTR StackLow
, StackHigh
;
221 ULONG_PTR RegistrationFrameEnd
;
222 CONTEXT LocalContext
;
225 /* Get the current stack limits */
226 RtlpGetStackLimits(&StackLow
, &StackHigh
);
228 /* Check if we don't have an exception record */
229 if (!ExceptionRecord
)
231 /* Overwrite the argument */
232 ExceptionRecord
= &ExceptionRecord3
;
234 /* Setup a local one */
235 ExceptionRecord3
.ExceptionFlags
= 0;
236 ExceptionRecord3
.ExceptionCode
= STATUS_UNWIND
;
237 ExceptionRecord3
.ExceptionRecord
= NULL
;
238 ExceptionRecord3
.ExceptionAddress
= _ReturnAddress();
239 ExceptionRecord3
.NumberParameters
= 0;
242 /* Check if we have a frame */
245 /* Set it as unwinding */
246 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
250 /* Set the Exit Unwind flag as well */
251 ExceptionRecord
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|
252 EXCEPTION_EXIT_UNWIND
);
255 /* Now capture the context */
256 Context
= &LocalContext
;
257 LocalContext
.ContextFlags
= CONTEXT_INTEGER
|
260 RtlpCaptureContext(Context
);
262 /* Pop the current arguments off */
263 Context
->Esp
+= sizeof(TargetFrame
) +
265 sizeof(ExceptionRecord
) +
268 /* Set the new value for EAX */
269 Context
->Eax
= (ULONG
)ReturnValue
;
271 /* Get the current frame */
272 RegistrationFrame
= RtlpGetExceptionList();
274 /* Now loop every frame */
275 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
277 /* If this is the target */
278 if (RegistrationFrame
== TargetFrame
) ZwContinue(Context
, FALSE
);
280 /* Check if the frame is too low */
282 ((ULONG_PTR
)TargetFrame
< (ULONG_PTR
)RegistrationFrame
))
284 /* Create an invalid unwind exception */
285 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
286 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
287 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
288 ExceptionRecord2
.NumberParameters
= 0;
290 /* Raise the exception */
291 RtlRaiseException(&ExceptionRecord2
);
294 /* Find out where it ends */
295 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
296 sizeof(EXCEPTION_REGISTRATION_RECORD
);
298 /* Make sure the registration frame is located within the stack */
299 if ((RegistrationFrameEnd
> StackHigh
) ||
300 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
301 ((ULONG_PTR
)RegistrationFrame
& 0x3))
303 /* Check if this happened in the DPC Stack */
304 if (RtlpHandleDpcStackException(RegistrationFrame
,
305 RegistrationFrameEnd
,
309 /* Use DPC Stack Limits and restart */
313 /* Create an invalid stack exception */
314 ExceptionRecord2
.ExceptionCode
= STATUS_BAD_STACK
;
315 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
316 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
317 ExceptionRecord2
.NumberParameters
= 0;
319 /* Raise the exception */
320 RtlRaiseException(&ExceptionRecord2
);
324 /* Call the handler */
325 Disposition
= RtlpExecuteHandlerForUnwind(ExceptionRecord
,
333 /* Continue searching */
334 case ExceptionContinueSearch
:
338 case ExceptionCollidedUnwind
:
340 /* Get the original frame */
341 RegistrationFrame
= DispatcherContext
.RegistrationPointer
;
347 /* Set up the exception record */
348 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
349 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
350 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
351 ExceptionRecord2
.NumberParameters
= 0;
353 /* Raise the exception */
354 RtlRaiseException(&ExceptionRecord2
);
358 /* Go to the next frame */
359 OldFrame
= RegistrationFrame
;
360 RegistrationFrame
= RegistrationFrame
->Next
;
362 /* Remove this handler */
363 RtlpSetExceptionList(OldFrame
);
367 /* Check if we reached the end */
368 if (TargetFrame
== EXCEPTION_CHAIN_END
)
370 /* Unwind completed, so we don't exit */
371 ZwContinue(Context
, FALSE
);
375 /* This is an exit_unwind or the frame wasn't present in the list */
376 ZwRaiseException(ExceptionRecord
, Context
, FALSE
);