66a9d810e80dd0e0dcf6b1e99b2c3e010166ca0c
[reactos.git] / reactos / lib / rtl / i386 / except.c
1 /*
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <rtl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* PUBLIC FUNCTIONS **********************************************************/
17
18 /*
19 * @implemented
20 */
21 VOID
22 NTAPI
23 RtlGetCallersAddress(OUT PVOID *CallersAddress,
24 OUT PVOID *CallersCaller)
25 {
26 USHORT FrameCount;
27 PVOID BackTrace[2];
28 PULONG BackTraceHash = NULL;
29
30 /* Get the tow back trace address */
31 FrameCount = RtlCaptureStackBackTrace(2, 2, &BackTrace[0],BackTraceHash);
32
33 /* Only if user want it */
34 if (*CallersAddress != NULL)
35 {
36 /* only when first frames exist */
37 if (FrameCount >= 1)
38 {
39 *CallersAddress = BackTrace[0];
40 }
41 else
42 {
43 *CallersAddress = NULL;
44 }
45 }
46
47 /* Only if user want it */
48 if (*CallersCaller != NULL)
49 {
50 /* only when second frames exist */
51 if (FrameCount >= 2)
52 {
53 *CallersCaller = BackTrace[1];
54 }
55 else
56 {
57 *CallersCaller = NULL;
58 }
59 }
60 }
61
62 /*
63 * @implemented
64 */
65 BOOLEAN
66 NTAPI
67 RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
68 IN PCONTEXT Context)
69 {
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;
76
77 /* Perform vectored exception handling if we are in user mode */
78 if (RtlpGetMode() != KernelMode)
79 {
80 /* Call any registered vectored handlers */
81 if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context))
82 {
83 /* Exception handled, continue execution */
84 return TRUE;
85 }
86 }
87
88 /* Get the current stack limits and registration frame */
89 RtlpGetStackLimits(&StackLow, &StackHigh);
90 RegistrationFrame = RtlpGetExceptionList();
91
92 /* Now loop every frame */
93 while (RegistrationFrame != EXCEPTION_CHAIN_END)
94 {
95 /* Find out where it ends */
96 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
97 sizeof(EXCEPTION_REGISTRATION_RECORD);
98
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))
103 {
104 /* Check if this happened in the DPC Stack */
105 if (RtlpHandleDpcStackException(RegistrationFrame,
106 RegistrationFrameEnd,
107 &StackLow,
108 &StackHigh))
109 {
110 /* Use DPC Stack Limits and restart */
111 continue;
112 }
113
114 /* Set invalid stack and return false */
115 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
116 return FALSE;
117 }
118
119 /* Check if logging is enabled */
120 RtlpCheckLogException(ExceptionRecord,
121 Context,
122 RegistrationFrame,
123 sizeof(*RegistrationFrame));
124
125 /* Call the handler */
126 Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
127 RegistrationFrame,
128 Context,
129 &DispatcherContext,
130 RegistrationFrame->
131 Handler);
132
133 /* Check if this is a nested frame */
134 if (RegistrationFrame == NestedFrame)
135 {
136 /* Mask out the flag and the nested frame */
137 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL;
138 NestedFrame = NULL;
139 }
140
141 /* Handle the dispositions */
142 switch (Disposition)
143 {
144 /* Continue searching */
145 case ExceptionContinueExecution:
146
147 /* Check if it was non-continuable */
148 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
149 {
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;
156
157 /* Raise the exception */
158 RtlRaiseException(&ExceptionRecord2);
159 }
160 else
161 {
162 /* Return to caller */
163 return TRUE;
164 }
165
166 /* Continue searching */
167 case ExceptionContinueSearch:
168 break;
169
170 /* Nested exception */
171 case ExceptionNestedException:
172
173 /* Turn the nested flag on */
174 ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
175
176 /* Update the current nested frame */
177 if (DispatcherContext.RegistrationPointer > NestedFrame)
178 {
179 /* Get the frame from the dispatcher context */
180 NestedFrame = DispatcherContext.RegistrationPointer;
181 }
182 break;
183
184 /* Anything else */
185 default:
186
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;
192
193 /* Raise the exception */
194 RtlRaiseException(&ExceptionRecord2);
195 break;
196 }
197
198 /* Go to the next frame */
199 RegistrationFrame = RegistrationFrame->Next;
200 }
201
202 /* Unhandled, return false */
203 return FALSE;
204 }
205
206 /*
207 * @implemented
208 */
209 VOID
210 NTAPI
211 RtlUnwind(IN PVOID TargetFrame OPTIONAL,
212 IN PVOID TargetIp OPTIONAL,
213 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
214 IN PVOID ReturnValue)
215 {
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;
223 PCONTEXT Context;
224
225 /* Get the current stack limits */
226 RtlpGetStackLimits(&StackLow, &StackHigh);
227
228 /* Check if we don't have an exception record */
229 if (!ExceptionRecord)
230 {
231 /* Overwrite the argument */
232 ExceptionRecord = &ExceptionRecord3;
233
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;
240 }
241
242 /* Check if we have a frame */
243 if (TargetFrame)
244 {
245 /* Set it as unwinding */
246 ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
247 }
248 else
249 {
250 /* Set the Exit Unwind flag as well */
251 ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING |
252 EXCEPTION_EXIT_UNWIND);
253 }
254
255 /* Now capture the context */
256 Context = &LocalContext;
257 LocalContext.ContextFlags = CONTEXT_INTEGER |
258 CONTEXT_CONTROL |
259 CONTEXT_SEGMENTS;
260 RtlpCaptureContext(Context);
261
262 /* Pop the current arguments off */
263 Context->Esp += sizeof(TargetFrame) +
264 sizeof(TargetIp) +
265 sizeof(ExceptionRecord) +
266 sizeof(ReturnValue);
267
268 /* Set the new value for EAX */
269 Context->Eax = (ULONG)ReturnValue;
270
271 /* Get the current frame */
272 RegistrationFrame = RtlpGetExceptionList();
273
274 /* Now loop every frame */
275 while (RegistrationFrame != EXCEPTION_CHAIN_END)
276 {
277 /* If this is the target */
278 if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE);
279
280 /* Check if the frame is too low */
281 if ((TargetFrame) &&
282 ((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame))
283 {
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;
289
290 /* Raise the exception */
291 RtlRaiseException(&ExceptionRecord2);
292 }
293
294 /* Find out where it ends */
295 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
296 sizeof(EXCEPTION_REGISTRATION_RECORD);
297
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))
302 {
303 /* Check if this happened in the DPC Stack */
304 if (RtlpHandleDpcStackException(RegistrationFrame,
305 RegistrationFrameEnd,
306 &StackLow,
307 &StackHigh))
308 {
309 /* Use DPC Stack Limits and restart */
310 continue;
311 }
312
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;
318
319 /* Raise the exception */
320 RtlRaiseException(&ExceptionRecord2);
321 }
322 else
323 {
324 /* Call the handler */
325 Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
326 RegistrationFrame,
327 Context,
328 &DispatcherContext,
329 RegistrationFrame->
330 Handler);
331 switch(Disposition)
332 {
333 /* Continue searching */
334 case ExceptionContinueSearch:
335 break;
336
337 /* Collission */
338 case ExceptionCollidedUnwind :
339
340 /* Get the original frame */
341 RegistrationFrame = DispatcherContext.RegistrationPointer;
342 break;
343
344 /* Anything else */
345 default:
346
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;
352
353 /* Raise the exception */
354 RtlRaiseException(&ExceptionRecord2);
355 break;
356 }
357
358 /* Go to the next frame */
359 OldFrame = RegistrationFrame;
360 RegistrationFrame = RegistrationFrame->Next;
361
362 /* Remove this handler */
363 RtlpSetExceptionList(OldFrame);
364 }
365 }
366
367 /* Check if we reached the end */
368 if (TargetFrame == EXCEPTION_CHAIN_END)
369 {
370 /* Unwind completed, so we don't exit */
371 ZwContinue(Context, FALSE);
372 }
373 else
374 {
375 /* This is an exit_unwind or the frame wasn't present in the list */
376 ZwRaiseException(ExceptionRecord, Context, FALSE);
377 }
378 }
379
380 /* EOF */