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