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 (a dummy in kernel mode) */
78 if (RtlCallVectoredExceptionHandlers(ExceptionRecord
, Context
))
80 /* Exception handled, continue execution */
84 /* Get the current stack limits and registration frame */
85 RtlpGetStackLimits(&StackLow
, &StackHigh
);
86 RegistrationFrame
= RtlpGetExceptionList();
88 /* Now loop every frame */
89 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
91 /* Registration chain entries are never NULL */
92 ASSERT(RegistrationFrame
!= NULL
);
94 /* Find out where it ends */
95 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
96 sizeof(EXCEPTION_REGISTRATION_RECORD
);
98 /* Make sure the registration frame is located within the stack */
99 if ((RegistrationFrameEnd
> StackHigh
) ||
100 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
101 ((ULONG_PTR
)RegistrationFrame
& 0x3))
103 /* Check if this happened in the DPC Stack */
104 if (RtlpHandleDpcStackException(RegistrationFrame
,
105 RegistrationFrameEnd
,
109 /* Use DPC Stack Limits and restart */
113 /* Set invalid stack and return false */
114 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
118 /* Check if logging is enabled */
119 RtlpCheckLogException(ExceptionRecord
,
122 sizeof(*RegistrationFrame
));
124 /* Call the handler */
125 Disposition
= RtlpExecuteHandlerForException(ExceptionRecord
,
129 RegistrationFrame
->Handler
);
131 /* Check if this is a nested frame */
132 if (RegistrationFrame
== NestedFrame
)
134 /* Mask out the flag and the nested frame */
135 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
;
139 /* Handle the dispositions */
142 /* Continue searching */
143 case ExceptionContinueExecution
:
145 /* Check if it was non-continuable */
146 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
148 /* Set up the exception record */
149 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
150 ExceptionRecord2
.ExceptionCode
=
151 STATUS_NONCONTINUABLE_EXCEPTION
;
152 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
153 ExceptionRecord2
.NumberParameters
= 0;
155 /* Raise the exception */
156 RtlRaiseException(&ExceptionRecord2
);
160 /* Return to caller */
164 /* Continue searching */
165 case ExceptionContinueSearch
:
168 /* Nested exception */
169 case ExceptionNestedException
:
171 /* Turn the nested flag on */
172 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
174 /* Update the current nested frame */
175 if (DispatcherContext
.RegistrationPointer
> NestedFrame
)
177 /* Get the frame from the dispatcher context */
178 NestedFrame
= DispatcherContext
.RegistrationPointer
;
185 /* Set up the exception record */
186 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
187 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
188 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
189 ExceptionRecord2
.NumberParameters
= 0;
191 /* Raise the exception */
192 RtlRaiseException(&ExceptionRecord2
);
196 /* Go to the next frame */
197 RegistrationFrame
= RegistrationFrame
->Next
;
200 /* Unhandled, return false */
209 RtlUnwind(IN PVOID TargetFrame OPTIONAL
,
210 IN PVOID TargetIp OPTIONAL
,
211 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
212 IN PVOID ReturnValue
)
214 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
, OldFrame
;
215 DISPATCHER_CONTEXT DispatcherContext
;
216 EXCEPTION_RECORD ExceptionRecord2
, ExceptionRecord3
;
217 EXCEPTION_DISPOSITION Disposition
;
218 ULONG_PTR StackLow
, StackHigh
;
219 ULONG_PTR RegistrationFrameEnd
;
220 CONTEXT LocalContext
;
223 /* Get the current stack limits */
224 RtlpGetStackLimits(&StackLow
, &StackHigh
);
226 /* Check if we don't have an exception record */
227 if (!ExceptionRecord
)
229 /* Overwrite the argument */
230 ExceptionRecord
= &ExceptionRecord3
;
232 /* Setup a local one */
233 ExceptionRecord3
.ExceptionFlags
= 0;
234 ExceptionRecord3
.ExceptionCode
= STATUS_UNWIND
;
235 ExceptionRecord3
.ExceptionRecord
= NULL
;
236 ExceptionRecord3
.ExceptionAddress
= _ReturnAddress();
237 ExceptionRecord3
.NumberParameters
= 0;
240 /* Check if we have a frame */
243 /* Set it as unwinding */
244 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
248 /* Set the Exit Unwind flag as well */
249 ExceptionRecord
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|
250 EXCEPTION_EXIT_UNWIND
);
253 /* Now capture the context */
254 Context
= &LocalContext
;
255 LocalContext
.ContextFlags
= CONTEXT_INTEGER
|
258 RtlpCaptureContext(Context
);
260 /* Pop the current arguments off */
261 Context
->Esp
+= sizeof(TargetFrame
) +
263 sizeof(ExceptionRecord
) +
266 /* Set the new value for EAX */
267 Context
->Eax
= (ULONG
)ReturnValue
;
269 /* Get the current frame */
270 RegistrationFrame
= RtlpGetExceptionList();
272 /* Now loop every frame */
273 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
275 /* Registration chain entries are never NULL */
276 ASSERT(RegistrationFrame
!= NULL
);
278 /* If this is the target */
279 if (RegistrationFrame
== TargetFrame
) ZwContinue(Context
, FALSE
);
281 /* Check if the frame is too low */
283 ((ULONG_PTR
)TargetFrame
< (ULONG_PTR
)RegistrationFrame
))
285 /* Create an invalid unwind exception */
286 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
287 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
288 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
289 ExceptionRecord2
.NumberParameters
= 0;
291 /* Raise the exception */
292 RtlRaiseException(&ExceptionRecord2
);
295 /* Find out where it ends */
296 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
297 sizeof(EXCEPTION_REGISTRATION_RECORD
);
299 /* Make sure the registration frame is located within the stack */
300 if ((RegistrationFrameEnd
> StackHigh
) ||
301 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
302 ((ULONG_PTR
)RegistrationFrame
& 0x3))
304 /* Check if this happened in the DPC Stack */
305 if (RtlpHandleDpcStackException(RegistrationFrame
,
306 RegistrationFrameEnd
,
310 /* Use DPC Stack Limits and restart */
314 /* Create an invalid stack exception */
315 ExceptionRecord2
.ExceptionCode
= STATUS_BAD_STACK
;
316 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
317 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
318 ExceptionRecord2
.NumberParameters
= 0;
320 /* Raise the exception */
321 RtlRaiseException(&ExceptionRecord2
);
325 /* Call the handler */
326 Disposition
= RtlpExecuteHandlerForUnwind(ExceptionRecord
,
330 RegistrationFrame
->Handler
);
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
);