894065d081583609c42e620ae5bfd637bbd8312a
[reactos.git] / reactos / lib / rtl / i386 / exception.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
14 #define NDEBUG
15 #include <debug.h>
16
17 /* PRIVATE FUNCTIONS *********************************************************/
18
19 VOID
20 STDCALL
21 RtlpGetStackLimits(PULONG_PTR StackBase,
22 PULONG_PTR StackLimit);
23
24 PEXCEPTION_REGISTRATION_RECORD
25 STDCALL
26 RtlpGetExceptionList(VOID);
27
28 VOID
29 STDCALL
30 RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList);
31
32 /* PUBLIC FUNCTIONS **********************************************************/
33
34 /*
35 * @unimplemented
36 */
37 VOID
38 STDCALL
39 RtlGetCallersAddress(OUT PVOID *CallersAddress,
40 OUT PVOID *CallersCaller)
41 {
42 UNIMPLEMENTED;
43 }
44
45 /*
46 * @implemented
47 */
48 BOOLEAN
49 STDCALL
50 RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
51 IN PCONTEXT Context)
52 {
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);
60
61 /* Get the current stack limits and registration frame */
62 RtlpGetStackLimits(&StackLow, &StackHigh);
63 RegistrationFrame = RtlpGetExceptionList();
64 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
65
66 /* Now loop every frame */
67 while (RegistrationFrame != EXCEPTION_CHAIN_END)
68 {
69 /* Find out where it ends */
70 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
71 sizeof(*RegistrationFrame);
72
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))
77 {
78 /* Check if this happened in the DPC Stack */
79 if (RtlpHandleDpcStackException(RegistrationFrame,
80 RegistrationFrameEnd,
81 &StackLow,
82 &StackHigh))
83 {
84 /* Use DPC Stack Limits and restart */
85 continue;
86 }
87
88 /* Set invalid stack and return false */
89 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
90 DPRINT1("Invalid exception frame\n");
91 return FALSE;
92 }
93
94 /* Check if logging is enabled */
95 DPRINT("Checking for logging\n");
96 RtlpCheckLogException(ExceptionRecord,
97 Context,
98 RegistrationFrame,
99 sizeof(*RegistrationFrame));
100
101 /* Call the handler */
102 DPRINT("Executing handler: %p\n", RegistrationFrame->Handler);
103 ReturnValue = RtlpExecuteHandlerForException(ExceptionRecord,
104 RegistrationFrame,
105 Context,
106 &DispatcherContext,
107 RegistrationFrame->Handler);
108 DPRINT("Handler returned: %lx\n", ReturnValue);
109
110 /* Check if this is a nested frame */
111 if (RegistrationFrame == NestedFrame)
112 {
113 /* Mask out the flag and the nested frame */
114 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL;
115 NestedFrame = NULL;
116 }
117
118 /* Handle the dispositions */
119 if (ReturnValue == ExceptionContinueExecution)
120 {
121 /* Check if it was non-continuable */
122 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
123 {
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;
129
130 /* Raise the exception */
131 DPRINT("Non-continuable\n");
132 RtlRaiseException(&ExceptionRecord2);
133 }
134 else
135 {
136 /* Return to caller */
137 return TRUE;
138 }
139 }
140 else if (ReturnValue == ExceptionNestedException)
141 {
142 /* Turn the nested flag on */
143 ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
144
145 /* Update the current nested frame */
146 if (NestedFrame < DispatcherContext) NestedFrame = DispatcherContext;
147 }
148 else if (ReturnValue == ExceptionContinueSearch)
149 {
150 /* Do nothing */
151 }
152 else
153 {
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;
159
160 /* Raise the exception */
161 RtlRaiseException(&ExceptionRecord2);
162 }
163
164 /* Go to the next frame */
165 RegistrationFrame = RegistrationFrame->Next;
166 }
167
168 /* Unhandled, return false */
169 DPRINT("FALSE\n");
170 return FALSE;
171 }
172
173 /*
174 * @implemented
175 */
176 VOID
177 STDCALL
178 RtlUnwind(PVOID RegistrationFrame OPTIONAL,
179 PVOID ReturnAddress OPTIONAL,
180 PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
181 PVOID EaxValue)
182 {
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;
190 PCONTEXT Context;
191 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
192
193 /* Get the current stack limits */
194 RtlpGetStackLimits(&StackLow, &StackHigh);
195
196 /* Check if we don't have an exception record */
197 if (!ExceptionRecord)
198 {
199 /* Overwrite the argument */
200 ExceptionRecord = &ExceptionRecord3;
201
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;
208 }
209
210 /* Check if we have a frame */
211 if (RegistrationFrame)
212 {
213 /* Set it as unwinding */
214 ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
215 }
216 else
217 {
218 /* Set the Exit Unwind flag as well */
219 ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING |
220 EXCEPTION_EXIT_UNWIND);
221 }
222
223 /* Now capture the context */
224 Context = &LocalContext;
225 LocalContext.ContextFlags = CONTEXT_INTEGER |
226 CONTEXT_CONTROL |
227 CONTEXT_SEGMENTS;
228 RtlpCaptureContext(Context);
229
230 /* Pop the current arguments off */
231 Context->Esp += sizeof(RegistrationFrame) +
232 sizeof(ReturnAddress) +
233 sizeof(ExceptionRecord) +
234 sizeof(ReturnValue);
235
236 /* Set the new value for EAX */
237 Context->Eax = (ULONG)EaxValue;
238
239 /* Get the current frame */
240 RegistrationFrame2 = RtlpGetExceptionList();
241
242 /* Now loop every frame */
243 while (RegistrationFrame2 != EXCEPTION_CHAIN_END)
244 {
245 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame2);
246
247 /* If this is the target */
248 if (RegistrationFrame2 == RegistrationFrame)
249 {
250 /* Continue execution */
251 ZwContinue(Context, FALSE);
252 }
253
254 /* Check if the frame is too low */
255 if ((RegistrationFrame) && ((ULONG_PTR)RegistrationFrame <
256 (ULONG_PTR)RegistrationFrame2))
257 {
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;
263
264 /* Raise the exception */
265 DPRINT1("Frame is invalid\n");
266 RtlRaiseException(&ExceptionRecord2);
267 }
268
269 /* Find out where it ends */
270 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame2 +
271 sizeof(*RegistrationFrame2);
272
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))
277 {
278 /* Check if this happened in the DPC Stack */
279 if (RtlpHandleDpcStackException(RegistrationFrame,
280 RegistrationFrameEnd,
281 &StackLow,
282 &StackHigh))
283 {
284 /* Use DPC Stack Limits and restart */
285 continue;
286 }
287
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;
293
294 /* Raise the exception */
295 DPRINT1("Frame has bad stack\n");
296 RtlRaiseException(&ExceptionRecord2);
297 }
298 else
299 {
300 /* Call the handler */
301 DPRINT("Executing unwind handler: %p\n", RegistrationFrame2->Handler);
302 ReturnValue = RtlpExecuteHandlerForUnwind(ExceptionRecord,
303 RegistrationFrame2,
304 Context,
305 &DispatcherContext,
306 RegistrationFrame2->Handler);
307 DPRINT("Handler returned: %lx\n", ReturnValue);
308
309 /* Handle the dispositions */
310 if (ReturnValue == ExceptionContinueSearch)
311 {
312 /* Do nothing */
313 }
314 else if (ReturnValue == ExceptionCollidedUnwind)
315 {
316 /* Get the previous frame */
317 RegistrationFrame2 = DispatcherContext;
318 }
319 else
320 {
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;
326
327 /* Raise the exception */
328 RtlRaiseException(&ExceptionRecord2);
329 }
330
331 /* Go to the next frame */
332 OldFrame = RegistrationFrame2;
333 RegistrationFrame2 = RegistrationFrame2->Next;
334
335 /* Remove this handler */
336 RtlpSetExceptionList(OldFrame);
337 }
338 }
339
340 /* Check if we reached the end */
341 if (RegistrationFrame == EXCEPTION_CHAIN_END)
342 {
343 /* Unwind completed, so we don't exit */
344 ZwContinue(Context, FALSE);
345 }
346 else
347 {
348 /* This is an exit_unwind or the frame wasn't present in the list */
349 ZwRaiseException(ExceptionRecord, Context, FALSE);
350 }
351 }
352
353 /* EOF */