2 * PROJECT: ReactOS system libraries
3 * LICENSE: GNU GPL - See COPYING in the top level directory
4 * PURPOSE: Support library for PSEH3
5 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
9 * - Naming: To avoid naming conflicts, all internal identifiers are prefixed
11 * - Frame graph: PSEH3 uses the same registration frame for every trylevel.
12 * Only the top trylevel is registered in FS:0, the inner trylevels are linked
13 * to the first trylevel frame. Only the first trylevel frame has the Handler
14 * member set, it's 0 for all others as an identification. The EndOfChain
15 * member of the FS:0 registered frame points to the last internal frame,
16 * which is the frame itself, when only 1 trylevel is present.
18 * The registration graph looks like this:
23 * fs:0 /----------------\
24 * |-----------|<-\ |-----------|<-\ / |----------|<-\ \->|----------|
25 * | <Next> | \-| <Next> | \--/--| <Next> | \---| <Next> |
26 * | <Handler> | | <Handler> | / | <NULL> | | <NULL> |
27 * |-----------| |-----------| / |----------| |----------|
37 /* We need the full structure with all non-volatile */
38 #define _SEH3$_FRAME_ALL_NONVOLATILES 1
40 #include "pseh3_asmdef.h"
42 /* Make sure the asm definitions match the structures */
43 C_ASSERT(SEH3_REGISTRATION_FRAME_Next
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Next
));
44 C_ASSERT(SEH3_REGISTRATION_FRAME_Handler
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Handler
));
45 C_ASSERT(SEH3_REGISTRATION_FRAME_EndOfChain
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, EndOfChain
));
46 C_ASSERT(SEH3_REGISTRATION_FRAME_ScopeTable
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, ScopeTable
));
47 C_ASSERT(SEH3_REGISTRATION_FRAME_ExceptionPointers
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, ExceptionPointers
));
48 C_ASSERT(SEH3_REGISTRATION_FRAME_Esp
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Esp
));
49 C_ASSERT(SEH3_REGISTRATION_FRAME_Ebp
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Ebp
));
50 C_ASSERT(SEH3_SCOPE_TABLE_Filter
== FIELD_OFFSET(SEH3$_SCOPE_TABLE
, Filter
));
51 C_ASSERT(SEH3_SCOPE_TABLE_Target
== FIELD_OFFSET(SEH3$_SCOPE_TABLE
, Target
));
54 __attribute__((regparm(1)))
56 volatile SEH3$_REGISTRATION_FRAME
*Frame
)
59 _SEH3$
_UnregisterFrame(Frame
);
61 _SEH3$
_UnregisterTryLevel(Frame
);
66 _SEH3$
_InvokeNestedFunctionFilter(
67 volatile SEH3$_REGISTRATION_FRAME
*RegistrationFrame
,
73 /* First call with param = 0 to get the frame layout */
74 "xorl %%ecx, %%ecx\n\t"
75 "xorl %%eax, %%eax\n\t"
78 /* The result is the frame base address that we passed in (0) plus the
79 offset to the registration record. */
81 "addl %[RegistrationFrame], %%eax\n\t"
83 /* Second call to get the filter result */
87 : [RegistrationFrame
] "m" (RegistrationFrame
), [Filter
] "m" (Filter
)
94 __attribute__((regparm(1)))
95 _SEH3$
_InvokeEmbeddedFilter(
96 volatile SEH3$_REGISTRATION_FRAME
*RegistrationFrame
);
99 __attribute__((regparm(1)))
100 _SEH3$
_InvokeEmbeddedFilterFromRegistration(
101 volatile SEH3$_REGISTRATION_FRAME
*RegistrationFrame
);
106 volatile SEH3$_REGISTRATION_FRAME
*RegistrationFrame
,
111 if (RegistrationFrame
->ScopeTable
->HandlerType
== _SEH3$_NESTED_HANDLER
)
113 return _SEH3$
_InvokeNestedFunctionFilter(RegistrationFrame
, Filter
);
115 else if (RegistrationFrame
->ScopeTable
->HandlerType
== _SEH3$_CPP_HANDLER
)
117 /* Call the embedded filter function */
118 return _SEH3$
_InvokeEmbeddedFilter(RegistrationFrame
);
120 else if (RegistrationFrame
->ScopeTable
->HandlerType
== _SEH3$_CLANG_HANDLER
)
122 return _SEH3$
_InvokeEmbeddedFilterFromRegistration(RegistrationFrame
);
126 /* Should not happen! Skip this handler */
127 FilterResult
= EXCEPTION_CONTINUE_SEARCH
;
134 __attribute__((regparm(1)))
136 volatile SEH3$_REGISTRATION_FRAME
*Frame
)
138 /* Check for __finally frames */
139 if (Frame
->ScopeTable
->Target
== NULL
)
141 _SEH3$
_InvokeFilter(Frame
, Frame
->ScopeTable
->Filter
);
145 _SEH3$
_UnregisterFrame(Frame
);
147 _SEH3$
_UnregisterTryLevel(Frame
);
152 _SEH3$
_GetFilterResult(
153 PSEH3$_REGISTRATION_FRAME Record
)
155 PVOID Filter
= Record
->ScopeTable
->Filter
;
158 /* Check for __finally frames */
159 if (Record
->ScopeTable
->Target
== NULL
)
161 return EXCEPTION_CONTINUE_SEARCH
;
164 /* Check if we have a constant filter */
165 if (((ULONG
)Filter
& 0xFFFFFF00) == 0)
167 /* Lowest 8 bit are sign extended to give the result */
168 Result
= (LONG
)(CHAR
)(ULONG
)Filter
;
172 /* Call the filter function */
173 Result
= _SEH3$
_InvokeFilter(Record
, Filter
);
176 /* Normalize the result */
177 if (Result
< 0) return EXCEPTION_CONTINUE_EXECUTION
;
178 else if (Result
> 0) return EXCEPTION_EXECUTE_HANDLER
;
179 else return EXCEPTION_CONTINUE_SEARCH
;
185 PSEH3$_REGISTRATION_FRAME Record
)
187 _SEH3$
_InvokeFilter(Record
, Record
->ScopeTable
->Filter
);
190 __attribute__((noreturn
))
194 PSEH3$_REGISTRATION_FRAME RegistrationFrame
)
196 if (RegistrationFrame
->ScopeTable
->HandlerType
== _SEH3$_CLANG_HANDLER
)
199 /* Load the registers */
200 "movl 24(%%ecx), %%esp\n\t"
201 "movl 28(%%ecx), %%ebp\n\t"
203 /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
206 /* Jump into the exception handler */
209 "c" (RegistrationFrame
),
210 "a" (RegistrationFrame
->ScopeTable
),
211 [Target
] "m" (RegistrationFrame
->ScopeTable
->Target
)
217 /* Load the registers */
218 "movl 24(%%ecx), %%esp\n\t"
219 "movl 28(%%ecx), %%ebp\n\t"
221 /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
224 /* Jump into the exception handler */
227 "c" (RegistrationFrame
),
228 "a" (RegistrationFrame
->ScopeTable
),
229 [Target
] "m" (RegistrationFrame
->ScopeTable
->Target
)
233 __builtin_unreachable();
238 _SEH3$
_CallRtlUnwind(
239 PSEH3$_REGISTRATION_FRAME RegistrationFrame
);
242 EXCEPTION_DISPOSITION
245 __attribute__ ((__target__ ("cld")))
247 _SEH3$
_except_handler(
248 struct _EXCEPTION_RECORD
* ExceptionRecord
,
249 PSEH3$_REGISTRATION_FRAME EstablisherFrame
,
250 struct _CONTEXT
* ContextRecord
,
251 void * DispatcherContext
)
253 PSEH3$_REGISTRATION_FRAME CurrentFrame
, TargetFrame
;
254 SEH3$_EXCEPTION_POINTERS ExceptionPointers
;
257 /* Clear the direction flag. */
258 asm volatile ("cld" : : : "memory");
260 /* Save the exception pointers on the stack */
261 ExceptionPointers
.ExceptionRecord
= ExceptionRecord
;
262 ExceptionPointers
.ContextRecord
= ContextRecord
;
264 /* Check if this is an unwind */
265 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWINDING
)
267 /* Unwind all local frames */
268 TargetFrame
= EstablisherFrame
->Next
;
272 /* Loop all frames for this registration */
273 CurrentFrame
= EstablisherFrame
->EndOfChain
;
276 /* Check if we have an exception handler */
277 if (CurrentFrame
->ScopeTable
->Target
!= NULL
)
279 /* Set exception pointers and code for this frame */
280 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
281 CurrentFrame
->ExceptionCode
= ExceptionRecord
->ExceptionCode
;
283 /* Get the filter result */
284 FilterResult
= _SEH3$
_GetFilterResult(CurrentFrame
);
286 /* Check, if continuuing is requested */
287 if (FilterResult
== EXCEPTION_CONTINUE_EXECUTION
)
289 return ExceptionContinueExecution
;
292 /* Check if the except handler shall be executed */
293 if (FilterResult
== EXCEPTION_EXECUTE_HANDLER
) break;
296 /* Bail out if this is the last handler */
297 if (CurrentFrame
== EstablisherFrame
)
298 return ExceptionContinueSearch
;
300 /* Go to the next frame */
301 CurrentFrame
= CurrentFrame
->Next
;
304 /* Call RtlUnwind to unwind the frames below this one */
305 _SEH3$
_CallRtlUnwind(EstablisherFrame
);
307 /* Do a local unwind up to this frame */
308 TargetFrame
= CurrentFrame
;
311 /* Loop frames up to the target frame */
312 for (CurrentFrame
= EstablisherFrame
->EndOfChain
;
313 CurrentFrame
!= TargetFrame
;
314 CurrentFrame
= CurrentFrame
->Next
)
316 /* Manually unregister the frame */
317 _SEH3$
_Unregister(CurrentFrame
);
319 /* Check if this is an unwind frame */
320 if (CurrentFrame
->ScopeTable
->Target
== NULL
)
322 /* Set exception pointers and code for this frame */
323 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
324 CurrentFrame
->ExceptionCode
= ExceptionRecord
->ExceptionCode
;
326 /* Call the finally function */
327 _SEH3$
_CallFinally(CurrentFrame
);
331 /* Check if this was an unwind */
332 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWINDING
)
334 return ExceptionContinueSearch
;
337 /* Unregister the frame. It will be unregistered again at the end of the
338 __except block, due to auto cleanup, but that doesn't hurt.
339 All we do is set either fs:[0] or EstablisherFrame->EndOfChain to
340 CurrentFrame->Next, which will not change it's value. */
341 _SEH3$
_Unregister(CurrentFrame
);
343 /* Jump to the __except block (does not return) */
344 _SEH3$
_JumpToTarget(CurrentFrame
);