xref: /reactos/sdk/lib/rtl/i386/except.c (revision a4b6e0d9)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:         See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:           ReactOS Run-Time Library
4c2c66affSColin Finck  * PURPOSE:           User-mode exception support for IA-32
5c2c66affSColin Finck  * FILE:              lib/rtl/i386/except.c
6c2c66affSColin Finck  * PROGRAMERS:        Alex Ionescu (alex@relsoft.net)
7c2c66affSColin Finck  *                    Casper S. Hornstrup (chorns@users.sourceforge.net)
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck /* INCLUDES *****************************************************************/
11c2c66affSColin Finck 
12c2c66affSColin Finck #include <rtl.h>
13c2c66affSColin Finck #define NDEBUG
14c2c66affSColin Finck #include <debug.h>
15c2c66affSColin Finck 
16c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
17c2c66affSColin Finck 
18c2c66affSColin Finck /*
19c2c66affSColin Finck  * @implemented
20c2c66affSColin Finck  */
21c2c66affSColin Finck VOID
22c2c66affSColin Finck NTAPI
RtlGetCallersAddress(OUT PVOID * CallersAddress,OUT PVOID * CallersCaller)23c2c66affSColin Finck RtlGetCallersAddress(OUT PVOID *CallersAddress,
24c2c66affSColin Finck                      OUT PVOID *CallersCaller)
25c2c66affSColin Finck {
26c2c66affSColin Finck     USHORT FrameCount;
27c2c66affSColin Finck     PVOID  BackTrace[2];
28c2c66affSColin Finck     PULONG BackTraceHash = NULL;
29c2c66affSColin Finck 
30c2c66affSColin Finck     /* Get the tow back trace address */
31c2c66affSColin Finck     FrameCount = RtlCaptureStackBackTrace(2, 2, &BackTrace[0],BackTraceHash);
32c2c66affSColin Finck 
33c2c66affSColin Finck     /* Only if user want it */
34c2c66affSColin Finck     if (CallersAddress != NULL)
35c2c66affSColin Finck     {
36c2c66affSColin Finck         /* only when first frames exist */
37c2c66affSColin Finck         if (FrameCount >= 1)
38c2c66affSColin Finck         {
39c2c66affSColin Finck             *CallersAddress = BackTrace[0];
40c2c66affSColin Finck         }
41c2c66affSColin Finck         else
42c2c66affSColin Finck         {
43c2c66affSColin Finck             *CallersAddress = NULL;
44c2c66affSColin Finck         }
45c2c66affSColin Finck     }
46c2c66affSColin Finck 
47c2c66affSColin Finck     /* Only if user want it */
48c2c66affSColin Finck     if (CallersCaller != NULL)
49c2c66affSColin Finck     {
50c2c66affSColin Finck         /* only when second frames exist */
51c2c66affSColin Finck         if (FrameCount >= 2)
52c2c66affSColin Finck         {
53c2c66affSColin Finck             *CallersCaller = BackTrace[1];
54c2c66affSColin Finck         }
55c2c66affSColin Finck         else
56c2c66affSColin Finck         {
57c2c66affSColin Finck             *CallersCaller = NULL;
58c2c66affSColin Finck         }
59c2c66affSColin Finck     }
60c2c66affSColin Finck }
61c2c66affSColin Finck 
62c2c66affSColin Finck /*
63c2c66affSColin Finck  * @implemented
64c2c66affSColin Finck  */
65c2c66affSColin Finck BOOLEAN
66c2c66affSColin Finck NTAPI
RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,IN PCONTEXT Context)67c2c66affSColin Finck RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
68c2c66affSColin Finck                      IN PCONTEXT Context)
69c2c66affSColin Finck {
70c2c66affSColin Finck     PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL;
71c2c66affSColin Finck     DISPATCHER_CONTEXT DispatcherContext;
72c2c66affSColin Finck     EXCEPTION_RECORD ExceptionRecord2;
73c2c66affSColin Finck     EXCEPTION_DISPOSITION Disposition;
74c2c66affSColin Finck     ULONG_PTR StackLow, StackHigh;
75c2c66affSColin Finck     ULONG_PTR RegistrationFrameEnd;
76c2c66affSColin Finck 
77c2c66affSColin Finck     /* Perform vectored exception handling for user mode */
78c2c66affSColin Finck     if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context))
79c2c66affSColin Finck     {
80c2c66affSColin Finck         /* Exception handled, now call vectored continue handlers */
81c2c66affSColin Finck         RtlCallVectoredContinueHandlers(ExceptionRecord, Context);
82c2c66affSColin Finck 
83c2c66affSColin Finck         /* Continue execution */
84c2c66affSColin Finck         return TRUE;
85c2c66affSColin Finck     }
86c2c66affSColin Finck 
87c2c66affSColin Finck     /* Get the current stack limits and registration frame */
88c2c66affSColin Finck     RtlpGetStackLimits(&StackLow, &StackHigh);
89c2c66affSColin Finck     RegistrationFrame = RtlpGetExceptionList();
90c2c66affSColin Finck 
91c2c66affSColin Finck     /* Now loop every frame */
92c2c66affSColin Finck     while (RegistrationFrame != EXCEPTION_CHAIN_END)
93c2c66affSColin Finck     {
94c2c66affSColin Finck         /* Registration chain entries are never NULL */
95c2c66affSColin Finck         ASSERT(RegistrationFrame != NULL);
96c2c66affSColin Finck 
97c2c66affSColin Finck         /* Find out where it ends */
98c2c66affSColin Finck         RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
99c2c66affSColin Finck                                 sizeof(EXCEPTION_REGISTRATION_RECORD);
100c2c66affSColin Finck 
101c2c66affSColin Finck         /* Make sure the registration frame is located within the stack */
102c2c66affSColin Finck         if ((RegistrationFrameEnd > StackHigh) ||
103c2c66affSColin Finck             ((ULONG_PTR)RegistrationFrame < StackLow) ||
104c2c66affSColin Finck             ((ULONG_PTR)RegistrationFrame & 0x3))
105c2c66affSColin Finck         {
106c2c66affSColin Finck             /* Check if this happened in the DPC Stack */
107c2c66affSColin Finck             if (RtlpHandleDpcStackException(RegistrationFrame,
108c2c66affSColin Finck                                             RegistrationFrameEnd,
109c2c66affSColin Finck                                             &StackLow,
110c2c66affSColin Finck                                             &StackHigh))
111c2c66affSColin Finck             {
112c2c66affSColin Finck                 /* Use DPC Stack Limits and restart */
113c2c66affSColin Finck                 continue;
114c2c66affSColin Finck             }
115c2c66affSColin Finck 
116*a4b6e0d9SHermès Bélusca-Maïto             /* Set invalid stack and bail out */
117c2c66affSColin Finck             ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
118c2c66affSColin Finck             return FALSE;
119c2c66affSColin Finck         }
120c2c66affSColin Finck 
121*a4b6e0d9SHermès Bélusca-Maïto         //
122*a4b6e0d9SHermès Bélusca-Maïto         // TODO: Implement and call here RtlIsValidHandler(RegistrationFrame->Handler)
123*a4b6e0d9SHermès Bélusca-Maïto         // for supporting SafeSEH functionality, see the following articles:
124*a4b6e0d9SHermès Bélusca-Maïto         // https://www.optiv.com/blog/old-meets-new-microsoft-windows-safeseh-incompatibility
125*a4b6e0d9SHermès Bélusca-Maïto         // https://msrc-blog.microsoft.com/2012/01/10/more-information-on-the-impact-of-ms12-001/
126*a4b6e0d9SHermès Bélusca-Maïto         //
127*a4b6e0d9SHermès Bélusca-Maïto 
128c2c66affSColin Finck         /* Check if logging is enabled */
129c2c66affSColin Finck         RtlpCheckLogException(ExceptionRecord,
130c2c66affSColin Finck                               Context,
131c2c66affSColin Finck                               RegistrationFrame,
132c2c66affSColin Finck                               sizeof(*RegistrationFrame));
133c2c66affSColin Finck 
134c2c66affSColin Finck         /* Call the handler */
135c2c66affSColin Finck         Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
136c2c66affSColin Finck                                                      RegistrationFrame,
137c2c66affSColin Finck                                                      Context,
138c2c66affSColin Finck                                                      &DispatcherContext,
139c2c66affSColin Finck                                                      RegistrationFrame->Handler);
140c2c66affSColin Finck 
141c2c66affSColin Finck         /* Check if this is a nested frame */
142c2c66affSColin Finck         if (RegistrationFrame == NestedFrame)
143c2c66affSColin Finck         {
144c2c66affSColin Finck             /* Mask out the flag and the nested frame */
145c2c66affSColin Finck             ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL;
146c2c66affSColin Finck             NestedFrame = NULL;
147c2c66affSColin Finck         }
148c2c66affSColin Finck 
149c2c66affSColin Finck         /* Handle the dispositions */
150c2c66affSColin Finck         switch (Disposition)
151c2c66affSColin Finck         {
152c2c66affSColin Finck             /* Continue execution */
153c2c66affSColin Finck             case ExceptionContinueExecution:
154*a4b6e0d9SHermès Bélusca-Maïto             {
155c2c66affSColin Finck                 /* Check if it was non-continuable */
156c2c66affSColin Finck                 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
157c2c66affSColin Finck                 {
158c2c66affSColin Finck                     /* Set up the exception record */
159c2c66affSColin Finck                     ExceptionRecord2.ExceptionRecord = ExceptionRecord;
160c2c66affSColin Finck                     ExceptionRecord2.ExceptionCode =
161c2c66affSColin Finck                         STATUS_NONCONTINUABLE_EXCEPTION;
162c2c66affSColin Finck                     ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
163c2c66affSColin Finck                     ExceptionRecord2.NumberParameters = 0;
164c2c66affSColin Finck 
165c2c66affSColin Finck                     /* Raise the exception */
166c2c66affSColin Finck                     RtlRaiseException(&ExceptionRecord2);
167c2c66affSColin Finck                 }
168c2c66affSColin Finck                 else
169c2c66affSColin Finck                 {
170c2c66affSColin Finck                     /* In user mode, call any registered vectored continue handlers */
171*a4b6e0d9SHermès Bélusca-Maïto                     RtlCallVectoredContinueHandlers(ExceptionRecord, Context);
172c2c66affSColin Finck 
173c2c66affSColin Finck                     /* Execution continues */
174c2c66affSColin Finck                     return TRUE;
175c2c66affSColin Finck                 }
176*a4b6e0d9SHermès Bélusca-Maïto             }
177c2c66affSColin Finck 
178c2c66affSColin Finck             /* Continue searching */
179c2c66affSColin Finck             case ExceptionContinueSearch:
180*a4b6e0d9SHermès Bélusca-Maïto                 if (ExceptionRecord->ExceptionFlags & EXCEPTION_STACK_INVALID)
181*a4b6e0d9SHermès Bélusca-Maïto                 {
182*a4b6e0d9SHermès Bélusca-Maïto                     /* We have an invalid stack, bail out */
183*a4b6e0d9SHermès Bélusca-Maïto                     return FALSE;
184*a4b6e0d9SHermès Bélusca-Maïto                 }
185c2c66affSColin Finck                 break;
186c2c66affSColin Finck 
187c2c66affSColin Finck             /* Nested exception */
188c2c66affSColin Finck             case ExceptionNestedException:
189*a4b6e0d9SHermès Bélusca-Maïto             {
190c2c66affSColin Finck                 /* Turn the nested flag on */
191c2c66affSColin Finck                 ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
192c2c66affSColin Finck 
193c2c66affSColin Finck                 /* Update the current nested frame */
194c2c66affSColin Finck                 if (DispatcherContext.RegistrationPointer > NestedFrame)
195c2c66affSColin Finck                 {
196c2c66affSColin Finck                     /* Get the frame from the dispatcher context */
197c2c66affSColin Finck                     NestedFrame = DispatcherContext.RegistrationPointer;
198c2c66affSColin Finck                 }
199c2c66affSColin Finck                 break;
200*a4b6e0d9SHermès Bélusca-Maïto             }
201c2c66affSColin Finck 
202c2c66affSColin Finck             /* Anything else */
203c2c66affSColin Finck             default:
204*a4b6e0d9SHermès Bélusca-Maïto             {
205c2c66affSColin Finck                 /* Set up the exception record */
206c2c66affSColin Finck                 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
207c2c66affSColin Finck                 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
208c2c66affSColin Finck                 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
209c2c66affSColin Finck                 ExceptionRecord2.NumberParameters = 0;
210c2c66affSColin Finck 
211c2c66affSColin Finck                 /* Raise the exception */
212c2c66affSColin Finck                 RtlRaiseException(&ExceptionRecord2);
213c2c66affSColin Finck                 break;
214c2c66affSColin Finck             }
215*a4b6e0d9SHermès Bélusca-Maïto         }
216c2c66affSColin Finck 
217c2c66affSColin Finck         /* Go to the next frame */
218c2c66affSColin Finck         RegistrationFrame = RegistrationFrame->Next;
219c2c66affSColin Finck     }
220c2c66affSColin Finck 
221*a4b6e0d9SHermès Bélusca-Maïto     /* Unhandled, bail out */
222c2c66affSColin Finck     return FALSE;
223c2c66affSColin Finck }
224c2c66affSColin Finck 
225c2c66affSColin Finck /*
226c2c66affSColin Finck  * @implemented
227c2c66affSColin Finck  */
228c2c66affSColin Finck VOID
229c2c66affSColin Finck NTAPI
RtlUnwind(IN PVOID TargetFrame OPTIONAL,IN PVOID TargetIp OPTIONAL,IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,IN PVOID ReturnValue)230c2c66affSColin Finck RtlUnwind(IN PVOID TargetFrame OPTIONAL,
231c2c66affSColin Finck           IN PVOID TargetIp OPTIONAL,
232c2c66affSColin Finck           IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
233c2c66affSColin Finck           IN PVOID ReturnValue)
234c2c66affSColin Finck {
235c2c66affSColin Finck     PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame;
236c2c66affSColin Finck     DISPATCHER_CONTEXT DispatcherContext;
237c2c66affSColin Finck     EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3;
238c2c66affSColin Finck     EXCEPTION_DISPOSITION Disposition;
239c2c66affSColin Finck     ULONG_PTR StackLow, StackHigh;
240c2c66affSColin Finck     ULONG_PTR RegistrationFrameEnd;
241c2c66affSColin Finck     CONTEXT LocalContext;
242c2c66affSColin Finck     PCONTEXT Context;
243c2c66affSColin Finck 
244c2c66affSColin Finck     /* Get the current stack limits */
245c2c66affSColin Finck     RtlpGetStackLimits(&StackLow, &StackHigh);
246c2c66affSColin Finck 
247c2c66affSColin Finck     /* Check if we don't have an exception record */
248c2c66affSColin Finck     if (!ExceptionRecord)
249c2c66affSColin Finck     {
250c2c66affSColin Finck         /* Overwrite the argument */
251c2c66affSColin Finck         ExceptionRecord = &ExceptionRecord3;
252c2c66affSColin Finck 
253c2c66affSColin Finck         /* Setup a local one */
254c2c66affSColin Finck         ExceptionRecord3.ExceptionFlags = 0;
255c2c66affSColin Finck         ExceptionRecord3.ExceptionCode = STATUS_UNWIND;
256c2c66affSColin Finck         ExceptionRecord3.ExceptionRecord = NULL;
257c2c66affSColin Finck         ExceptionRecord3.ExceptionAddress = _ReturnAddress();
258c2c66affSColin Finck         ExceptionRecord3.NumberParameters = 0;
259c2c66affSColin Finck     }
260c2c66affSColin Finck 
261c2c66affSColin Finck     /* Check if we have a frame */
262c2c66affSColin Finck     if (TargetFrame)
263c2c66affSColin Finck     {
264c2c66affSColin Finck         /* Set it as unwinding */
265c2c66affSColin Finck         ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
266c2c66affSColin Finck     }
267c2c66affSColin Finck     else
268c2c66affSColin Finck     {
269c2c66affSColin Finck         /* Set the Exit Unwind flag as well */
270c2c66affSColin Finck         ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING |
271c2c66affSColin Finck                                             EXCEPTION_EXIT_UNWIND);
272c2c66affSColin Finck     }
273c2c66affSColin Finck 
274c2c66affSColin Finck     /* Now capture the context */
275c2c66affSColin Finck     Context = &LocalContext;
276c2c66affSColin Finck     LocalContext.ContextFlags = CONTEXT_INTEGER |
277c2c66affSColin Finck                                 CONTEXT_CONTROL |
278c2c66affSColin Finck                                 CONTEXT_SEGMENTS;
279c2c66affSColin Finck     RtlpCaptureContext(Context);
280c2c66affSColin Finck 
281c2c66affSColin Finck     /* Pop the current arguments off */
282c2c66affSColin Finck     Context->Esp += sizeof(TargetFrame) +
283c2c66affSColin Finck                     sizeof(TargetIp) +
284c2c66affSColin Finck                     sizeof(ExceptionRecord) +
285c2c66affSColin Finck                     sizeof(ReturnValue);
286c2c66affSColin Finck 
287c2c66affSColin Finck     /* Set the new value for EAX */
288c2c66affSColin Finck     Context->Eax = (ULONG)ReturnValue;
289c2c66affSColin Finck 
290c2c66affSColin Finck     /* Get the current frame */
291c2c66affSColin Finck     RegistrationFrame = RtlpGetExceptionList();
292c2c66affSColin Finck 
293c2c66affSColin Finck     /* Now loop every frame */
294c2c66affSColin Finck     while (RegistrationFrame != EXCEPTION_CHAIN_END)
295c2c66affSColin Finck     {
296c2c66affSColin Finck         /* Registration chain entries are never NULL */
297c2c66affSColin Finck         ASSERT(RegistrationFrame != NULL);
298c2c66affSColin Finck 
299c2c66affSColin Finck         /* If this is the target */
300c2c66affSColin Finck         if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE);
301c2c66affSColin Finck 
302c2c66affSColin Finck         /* Check if the frame is too low */
303c2c66affSColin Finck         if ((TargetFrame) &&
304c2c66affSColin Finck             ((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame))
305c2c66affSColin Finck         {
306c2c66affSColin Finck             /* Create an invalid unwind exception */
307c2c66affSColin Finck             ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
308c2c66affSColin Finck             ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
309c2c66affSColin Finck             ExceptionRecord2.ExceptionRecord = ExceptionRecord;
310c2c66affSColin Finck             ExceptionRecord2.NumberParameters = 0;
311c2c66affSColin Finck 
312c2c66affSColin Finck             /* Raise the exception */
313c2c66affSColin Finck             RtlRaiseException(&ExceptionRecord2);
314c2c66affSColin Finck         }
315c2c66affSColin Finck 
316c2c66affSColin Finck         /* Find out where it ends */
317c2c66affSColin Finck         RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
318c2c66affSColin Finck                                sizeof(EXCEPTION_REGISTRATION_RECORD);
319c2c66affSColin Finck 
320c2c66affSColin Finck         /* Make sure the registration frame is located within the stack */
321c2c66affSColin Finck         if ((RegistrationFrameEnd > StackHigh) ||
322c2c66affSColin Finck             ((ULONG_PTR)RegistrationFrame < StackLow) ||
323c2c66affSColin Finck             ((ULONG_PTR)RegistrationFrame & 0x3))
324c2c66affSColin Finck         {
325c2c66affSColin Finck             /* Check if this happened in the DPC Stack */
326c2c66affSColin Finck             if (RtlpHandleDpcStackException(RegistrationFrame,
327c2c66affSColin Finck                                             RegistrationFrameEnd,
328c2c66affSColin Finck                                             &StackLow,
329c2c66affSColin Finck                                             &StackHigh))
330c2c66affSColin Finck             {
331c2c66affSColin Finck                 /* Use DPC Stack Limits and restart */
332c2c66affSColin Finck                 continue;
333c2c66affSColin Finck             }
334c2c66affSColin Finck 
335c2c66affSColin Finck             /* Create an invalid stack exception */
336c2c66affSColin Finck             ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK;
337c2c66affSColin Finck             ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
338c2c66affSColin Finck             ExceptionRecord2.ExceptionRecord = ExceptionRecord;
339c2c66affSColin Finck             ExceptionRecord2.NumberParameters = 0;
340c2c66affSColin Finck 
341c2c66affSColin Finck             /* Raise the exception */
342c2c66affSColin Finck             RtlRaiseException(&ExceptionRecord2);
343c2c66affSColin Finck         }
344c2c66affSColin Finck         else
345c2c66affSColin Finck         {
346c2c66affSColin Finck             /* Call the handler */
347c2c66affSColin Finck             Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
348c2c66affSColin Finck                                                       RegistrationFrame,
349c2c66affSColin Finck                                                       Context,
350c2c66affSColin Finck                                                       &DispatcherContext,
351c2c66affSColin Finck                                                       RegistrationFrame->Handler);
352*a4b6e0d9SHermès Bélusca-Maïto 
353c2c66affSColin Finck             switch(Disposition)
354c2c66affSColin Finck             {
355c2c66affSColin Finck                 /* Continue searching */
356c2c66affSColin Finck                 case ExceptionContinueSearch:
357c2c66affSColin Finck                     break;
358c2c66affSColin Finck 
359*a4b6e0d9SHermès Bélusca-Maïto                 /* Collision */
360c2c66affSColin Finck                 case ExceptionCollidedUnwind:
361*a4b6e0d9SHermès Bélusca-Maïto                 {
362c2c66affSColin Finck                     /* Get the original frame */
363c2c66affSColin Finck                     RegistrationFrame = DispatcherContext.RegistrationPointer;
364c2c66affSColin Finck                     break;
365*a4b6e0d9SHermès Bélusca-Maïto                 }
366c2c66affSColin Finck 
367c2c66affSColin Finck                 /* Anything else */
368c2c66affSColin Finck                 default:
369*a4b6e0d9SHermès Bélusca-Maïto                 {
370c2c66affSColin Finck                     /* Set up the exception record */
371c2c66affSColin Finck                     ExceptionRecord2.ExceptionRecord = ExceptionRecord;
372c2c66affSColin Finck                     ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
373c2c66affSColin Finck                     ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
374c2c66affSColin Finck                     ExceptionRecord2.NumberParameters = 0;
375c2c66affSColin Finck 
376c2c66affSColin Finck                     /* Raise the exception */
377c2c66affSColin Finck                     RtlRaiseException(&ExceptionRecord2);
378c2c66affSColin Finck                     break;
379c2c66affSColin Finck                 }
380*a4b6e0d9SHermès Bélusca-Maïto             }
381c2c66affSColin Finck 
382c2c66affSColin Finck             /* Go to the next frame */
383c2c66affSColin Finck             OldFrame = RegistrationFrame;
384c2c66affSColin Finck             RegistrationFrame = RegistrationFrame->Next;
385c2c66affSColin Finck 
386c2c66affSColin Finck             /* Remove this handler */
387c2c66affSColin Finck             RtlpSetExceptionList(OldFrame);
388c2c66affSColin Finck         }
389c2c66affSColin Finck     }
390c2c66affSColin Finck 
391c2c66affSColin Finck     /* Check if we reached the end */
392c2c66affSColin Finck     if (TargetFrame == EXCEPTION_CHAIN_END)
393c2c66affSColin Finck     {
394c2c66affSColin Finck         /* Unwind completed, so we don't exit */
395c2c66affSColin Finck         ZwContinue(Context, FALSE);
396c2c66affSColin Finck     }
397c2c66affSColin Finck     else
398c2c66affSColin Finck     {
399c2c66affSColin Finck         /* This is an exit_unwind or the frame wasn't present in the list */
400c2c66affSColin Finck         ZwRaiseException(ExceptionRecord, Context, FALSE);
401c2c66affSColin Finck     }
402c2c66affSColin Finck }
403c2c66affSColin Finck 
404c2c66affSColin Finck /* EOF */
405