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 *****************************************************************/
17 /* PRIVATE FUNCTIONS *********************************************************/
21 RtlpGetStackLimits(PULONG_PTR StackBase
,
22 PULONG_PTR StackLimit
);
24 PEXCEPTION_REGISTRATION_RECORD
26 RtlpGetExceptionList(VOID
);
30 RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList
);
32 /* PUBLIC FUNCTIONS **********************************************************/
39 RtlGetCallersAddress(OUT PVOID
*CallersAddress
,
40 OUT PVOID
*CallersCaller
)
50 RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
53 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
, NestedFrame
= NULL
;
54 PEXCEPTION_REGISTRATION_RECORD DispatcherContext
;
55 EXCEPTION_RECORD ExceptionRecord2
;
56 EXCEPTION_DISPOSITION ReturnValue
;
57 ULONG_PTR StackLow
, StackHigh
;
58 ULONG_PTR RegistrationFrameEnd
;
59 DPRINT("RtlDispatchException(): %p, %p \n", ExceptionRecord
, Context
);
61 /* Get the current stack limits and registration frame */
62 RtlpGetStackLimits(&StackLow
, &StackHigh
);
63 RegistrationFrame
= RtlpGetExceptionList();
64 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame
);
66 /* Now loop every frame */
67 while (RegistrationFrame
!= EXCEPTION_CHAIN_END
)
69 /* Find out where it ends */
70 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame
+
71 sizeof(*RegistrationFrame
);
73 /* Make sure the registration frame is located within the stack */
74 if ((RegistrationFrameEnd
> StackHigh
) ||
75 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
76 ((ULONG_PTR
)RegistrationFrame
& 0x3))
78 /* Check if this happened in the DPC Stack */
79 if (RtlpHandleDpcStackException(RegistrationFrame
,
84 /* Use DPC Stack Limits and restart */
88 /* Set invalid stack and return false */
89 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
90 DPRINT1("Invalid exception frame\n");
94 /* Check if logging is enabled */
95 DPRINT("Checking for logging\n");
96 RtlpCheckLogException(ExceptionRecord
,
99 sizeof(*RegistrationFrame
));
101 /* Call the handler */
102 DPRINT("Executing handler: %p\n", RegistrationFrame
->Handler
);
103 ReturnValue
= RtlpExecuteHandlerForException(ExceptionRecord
,
107 RegistrationFrame
->Handler
);
108 DPRINT("Handler returned: %lx\n", ReturnValue
);
110 /* Check if this is a nested frame */
111 if (RegistrationFrame
== NestedFrame
)
113 /* Mask out the flag and the nested frame */
114 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
;
118 /* Handle the dispositions */
119 if (ReturnValue
== ExceptionContinueExecution
)
121 /* Check if it was non-continuable */
122 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
124 /* Set up the exception record */
125 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
126 ExceptionRecord2
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
127 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
128 ExceptionRecord2
.NumberParameters
= 0;
130 /* Raise the exception */
131 DPRINT("Non-continuable\n");
132 RtlRaiseException(&ExceptionRecord2
);
136 /* Return to caller */
140 else if (ReturnValue
== ExceptionNestedException
)
142 /* Turn the nested flag on */
143 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
145 /* Update the current nested frame */
146 if (NestedFrame
< DispatcherContext
) NestedFrame
= DispatcherContext
;
148 else if (ReturnValue
== ExceptionContinueSearch
)
154 /* Set up the exception record */
155 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
156 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
157 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
158 ExceptionRecord2
.NumberParameters
= 0;
160 /* Raise the exception */
161 RtlRaiseException(&ExceptionRecord2
);
164 /* Go to the next frame */
165 RegistrationFrame
= RegistrationFrame
->Next
;
168 /* Unhandled, return false */
178 RtlUnwind(PVOID RegistrationFrame OPTIONAL
,
179 PVOID ReturnAddress OPTIONAL
,
180 PEXCEPTION_RECORD ExceptionRecord OPTIONAL
,
183 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame2
, OldFrame
;
184 PEXCEPTION_REGISTRATION_RECORD DispatcherContext
;
185 EXCEPTION_RECORD ExceptionRecord2
, ExceptionRecord3
;
186 EXCEPTION_DISPOSITION ReturnValue
;
187 ULONG_PTR StackLow
, StackHigh
;
188 ULONG_PTR RegistrationFrameEnd
;
189 CONTEXT LocalContext
;
191 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame
);
193 /* Get the current stack limits */
194 RtlpGetStackLimits(&StackLow
, &StackHigh
);
196 /* Check if we don't have an exception record */
197 if (!ExceptionRecord
)
199 /* Overwrite the argument */
200 ExceptionRecord
= &ExceptionRecord3
;
202 /* Setup a local one */
203 ExceptionRecord3
.ExceptionFlags
= 0;
204 ExceptionRecord3
.ExceptionCode
= STATUS_UNWIND
;
205 ExceptionRecord3
.ExceptionRecord
= NULL
;
206 ExceptionRecord3
.ExceptionAddress
= RtlpGetExceptionAddress();
207 ExceptionRecord3
.NumberParameters
= 0;
210 /* Check if we have a frame */
211 if (RegistrationFrame
)
213 /* Set it as unwinding */
214 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
218 /* Set the Exit Unwind flag as well */
219 ExceptionRecord
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|
220 EXCEPTION_EXIT_UNWIND
);
223 /* Now capture the context */
224 Context
= &LocalContext
;
225 LocalContext
.ContextFlags
= CONTEXT_INTEGER
|
228 RtlpCaptureContext(Context
);
230 /* Pop the current arguments off */
231 Context
->Esp
+= sizeof(RegistrationFrame
) +
232 sizeof(ReturnAddress
) +
233 sizeof(ExceptionRecord
) +
236 /* Set the new value for EAX */
237 Context
->Eax
= (ULONG
)EaxValue
;
239 /* Get the current frame */
240 RegistrationFrame2
= RtlpGetExceptionList();
242 /* Now loop every frame */
243 while (RegistrationFrame2
!= EXCEPTION_CHAIN_END
)
245 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame2
);
247 /* If this is the target */
248 if (RegistrationFrame2
== RegistrationFrame
)
250 /* Continue execution */
251 ZwContinue(Context
, FALSE
);
254 /* Check if the frame is too low */
255 if ((RegistrationFrame
) && ((ULONG_PTR
)RegistrationFrame
<
256 (ULONG_PTR
)RegistrationFrame2
))
258 /* Create an invalid unwind exception */
259 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
260 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
261 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
262 ExceptionRecord2
.NumberParameters
= 0;
264 /* Raise the exception */
265 DPRINT1("Frame is invalid\n");
266 RtlRaiseException(&ExceptionRecord2
);
269 /* Find out where it ends */
270 RegistrationFrameEnd
= (ULONG_PTR
)RegistrationFrame2
+
271 sizeof(*RegistrationFrame2
);
273 /* Make sure the registration frame is located within the stack */
274 if ((RegistrationFrameEnd
> StackHigh
) ||
275 ((ULONG_PTR
)RegistrationFrame
< StackLow
) ||
276 ((ULONG_PTR
)RegistrationFrame
& 0x3))
278 /* Check if this happened in the DPC Stack */
279 if (RtlpHandleDpcStackException(RegistrationFrame
,
280 RegistrationFrameEnd
,
284 /* Use DPC Stack Limits and restart */
288 /* Create an invalid stack exception */
289 ExceptionRecord2
.ExceptionCode
= STATUS_BAD_STACK
;
290 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
291 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
292 ExceptionRecord2
.NumberParameters
= 0;
294 /* Raise the exception */
295 DPRINT1("Frame has bad stack\n");
296 RtlRaiseException(&ExceptionRecord2
);
300 /* Call the handler */
301 DPRINT("Executing unwind handler: %p\n", RegistrationFrame2
->Handler
);
302 ReturnValue
= RtlpExecuteHandlerForUnwind(ExceptionRecord
,
306 RegistrationFrame2
->Handler
);
307 DPRINT("Handler returned: %lx\n", ReturnValue
);
309 /* Handle the dispositions */
310 if (ReturnValue
== ExceptionContinueSearch
)
314 else if (ReturnValue
== ExceptionCollidedUnwind
)
316 /* Get the previous frame */
317 RegistrationFrame2
= DispatcherContext
;
321 /* Set up the exception record */
322 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
323 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
324 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
325 ExceptionRecord2
.NumberParameters
= 0;
327 /* Raise the exception */
328 RtlRaiseException(&ExceptionRecord2
);
331 /* Go to the next frame */
332 OldFrame
= RegistrationFrame2
;
333 RegistrationFrame2
= RegistrationFrame2
->Next
;
335 /* Remove this handler */
336 RtlpSetExceptionList(OldFrame
);
340 /* Check if we reached the end */
341 if (RegistrationFrame
== EXCEPTION_CHAIN_END
)
343 /* Unwind completed, so we don't exit */
344 ZwContinue(Context
, FALSE
);
348 /* This is an exit_unwind or the frame wasn't present in the list */
349 ZwRaiseException(ExceptionRecord
, Context
, FALSE
);