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/except.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 for user mode */
78 if (RtlCallVectoredExceptionHandlers(ExceptionRecord
, Context
))
80 /* Exception handled, now call vectored continue handlers */
81 RtlCallVectoredContinueHandlers(ExceptionRecord
, Context
);
83 /* Continue execution */
87 /* Get the current stack limits and registration frame */
88 RtlpGetStackLimits(&StackLow
, &StackHigh
);
89 RegistrationFrame
= RtlpGetExceptionList();
91 /* Now loop every frame */
92 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
94 /* Registration chain entries are never NULL */
95 ASSERT(RegistrationFrame
!= NULL
);
97 /* Find out where it ends */
98 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
99 sizeof(EXCEPTION_REGISTRATION_RECORD
);
101 /* Make sure the registration frame is located within the stack */
102 if ((RegistrationFrameEnd
> StackHigh
) ||
103 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
104 ((ULONG_PTR
)RegistrationFrame
& 0x3))
106 /* Check if this happened in the DPC Stack */
107 if (RtlpHandleDpcStackException(RegistrationFrame
,
108 RegistrationFrameEnd
,
112 /* Use DPC Stack Limits and restart */
116 /* Set invalid stack and return false */
117 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
121 /* Check if logging is enabled */
122 RtlpCheckLogException(ExceptionRecord
,
125 sizeof(*RegistrationFrame
));
127 /* Call the handler */
128 Disposition
= RtlpExecuteHandlerForException(ExceptionRecord
,
132 RegistrationFrame
->Handler
);
134 /* Check if this is a nested frame */
135 if (RegistrationFrame
== NestedFrame
)
137 /* Mask out the flag and the nested frame */
138 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
;
142 /* Handle the dispositions */
145 /* Continue execution */
146 case ExceptionContinueExecution
:
148 /* Check if it was non-continuable */
149 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
151 /* Set up the exception record */
152 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
153 ExceptionRecord2
.ExceptionCode
=
154 STATUS_NONCONTINUABLE_EXCEPTION
;
155 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
156 ExceptionRecord2
.NumberParameters
= 0;
158 /* Raise the exception */
159 RtlRaiseException(&ExceptionRecord2
);
163 /* In user mode, call any registered vectored continue handlers */
164 RtlCallVectoredContinueHandlers(ExceptionRecord
,
167 /* Execution continues */
171 /* Continue searching */
172 case ExceptionContinueSearch
:
175 /* Nested exception */
176 case ExceptionNestedException
:
178 /* Turn the nested flag on */
179 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
181 /* Update the current nested frame */
182 if (DispatcherContext
.RegistrationPointer
> NestedFrame
)
184 /* Get the frame from the dispatcher context */
185 NestedFrame
= DispatcherContext
.RegistrationPointer
;
192 /* Set up the exception record */
193 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
194 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
195 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
196 ExceptionRecord2
.NumberParameters
= 0;
198 /* Raise the exception */
199 RtlRaiseException(&ExceptionRecord2
);
203 /* Go to the next frame */
204 RegistrationFrame
= RegistrationFrame
->Next
;
207 /* Unhandled, return false */
216 RtlUnwind(IN PVOID TargetFrame OPTIONAL
,
217 IN PVOID TargetIp OPTIONAL
,
218 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
219 IN PVOID ReturnValue
)
221 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
, OldFrame
;
222 DISPATCHER_CONTEXT DispatcherContext
;
223 EXCEPTION_RECORD ExceptionRecord2
, ExceptionRecord3
;
224 EXCEPTION_DISPOSITION Disposition
;
225 ULONG_PTR StackLow
, StackHigh
;
226 ULONG_PTR RegistrationFrameEnd
;
227 CONTEXT LocalContext
;
230 /* Get the current stack limits */
231 RtlpGetStackLimits(&StackLow
, &StackHigh
);
233 /* Check if we don't have an exception record */
234 if (!ExceptionRecord
)
236 /* Overwrite the argument */
237 ExceptionRecord
= &ExceptionRecord3
;
239 /* Setup a local one */
240 ExceptionRecord3
.ExceptionFlags
= 0;
241 ExceptionRecord3
.ExceptionCode
= STATUS_UNWIND
;
242 ExceptionRecord3
.ExceptionRecord
= NULL
;
243 ExceptionRecord3
.ExceptionAddress
= _ReturnAddress();
244 ExceptionRecord3
.NumberParameters
= 0;
247 /* Check if we have a frame */
250 /* Set it as unwinding */
251 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
255 /* Set the Exit Unwind flag as well */
256 ExceptionRecord
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|
257 EXCEPTION_EXIT_UNWIND
);
260 /* Now capture the context */
261 Context
= &LocalContext
;
262 LocalContext
.ContextFlags
= CONTEXT_INTEGER
|
265 RtlpCaptureContext(Context
);
267 /* Pop the current arguments off */
268 Context
->Esp
+= sizeof(TargetFrame
) +
270 sizeof(ExceptionRecord
) +
273 /* Set the new value for EAX */
274 Context
->Eax
= (ULONG
)ReturnValue
;
276 /* Get the current frame */
277 RegistrationFrame
= RtlpGetExceptionList();
279 /* Now loop every frame */
280 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
282 /* Registration chain entries are never NULL */
283 ASSERT(RegistrationFrame
!= NULL
);
285 /* If this is the target */
286 if (RegistrationFrame
== TargetFrame
) ZwContinue(Context
, FALSE
);
288 /* Check if the frame is too low */
290 ((ULONG_PTR
)TargetFrame
< (ULONG_PTR
)RegistrationFrame
))
292 /* Create an invalid unwind exception */
293 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
294 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
295 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
296 ExceptionRecord2
.NumberParameters
= 0;
298 /* Raise the exception */
299 RtlRaiseException(&ExceptionRecord2
);
302 /* Find out where it ends */
303 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
304 sizeof(EXCEPTION_REGISTRATION_RECORD
);
306 /* Make sure the registration frame is located within the stack */
307 if ((RegistrationFrameEnd
> StackHigh
) ||
308 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
309 ((ULONG_PTR
)RegistrationFrame
& 0x3))
311 /* Check if this happened in the DPC Stack */
312 if (RtlpHandleDpcStackException(RegistrationFrame
,
313 RegistrationFrameEnd
,
317 /* Use DPC Stack Limits and restart */
321 /* Create an invalid stack exception */
322 ExceptionRecord2
.ExceptionCode
= STATUS_BAD_STACK
;
323 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
324 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
325 ExceptionRecord2
.NumberParameters
= 0;
327 /* Raise the exception */
328 RtlRaiseException(&ExceptionRecord2
);
332 /* Call the handler */
333 Disposition
= RtlpExecuteHandlerForUnwind(ExceptionRecord
,
337 RegistrationFrame
->Handler
);
340 /* Continue searching */
341 case ExceptionContinueSearch
:
345 case ExceptionCollidedUnwind
:
347 /* Get the original frame */
348 RegistrationFrame
= DispatcherContext
.RegistrationPointer
;
354 /* Set up the exception record */
355 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
356 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
357 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
358 ExceptionRecord2
.NumberParameters
= 0;
360 /* Raise the exception */
361 RtlRaiseException(&ExceptionRecord2
);
365 /* Go to the next frame */
366 OldFrame
= RegistrationFrame
;
367 RegistrationFrame
= RegistrationFrame
->Next
;
369 /* Remove this handler */
370 RtlpSetExceptionList(OldFrame
);
374 /* Check if we reached the end */
375 if (TargetFrame
== EXCEPTION_CHAIN_END
)
377 /* Unwind completed, so we don't exit */
378 ZwContinue(Context
, FALSE
);
382 /* This is an exit_unwind or the frame wasn't present in the list */
383 ZwRaiseException(ExceptionRecord
, Context
, FALSE
);