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 PSEH3$_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 PSEH3$_REGISTRATION_FRAME RegistrationFrame
);
99 __attribute__((regparm(1)))
100 _SEH3$
_InvokeEmbeddedFilterFromRegistration(
101 PSEH3$_REGISTRATION_FRAME RegistrationFrame
);
106 PSEH3$_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 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 20(%%ecx), %%esp\n"
201 "movl 24(%%ecx), %%ebp\n"
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 20(%%ecx), %%esp\n"
219 "movl 24(%%ecx), %%ebp\n"
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
244 __attribute__ ((__target__ ("cld")))
245 _SEH3$
_except_handler(
246 struct _EXCEPTION_RECORD
* ExceptionRecord
,
247 PSEH3$_REGISTRATION_FRAME EstablisherFrame
,
248 struct _CONTEXT
* ContextRecord
,
249 void * DispatcherContext
)
251 PSEH3$_REGISTRATION_FRAME CurrentFrame
, TargetFrame
;
252 SEH3$_EXCEPTION_POINTERS ExceptionPointers
;
255 /* Clear the direction flag. */
256 asm volatile ("cld\n" : : : "memory");
258 /* Save the exception pointers on the stack */
259 ExceptionPointers
.ExceptionRecord
= ExceptionRecord
;
260 ExceptionPointers
.ContextRecord
= ContextRecord
;
262 /* Check if this is an unwind */
263 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWINDING
)
265 /* Unwind all local frames */
266 TargetFrame
= EstablisherFrame
->Next
;
270 /* Loop all frames for this registration */
271 CurrentFrame
= EstablisherFrame
->EndOfChain
;
274 /* Check if we have an exception handler */
275 if (CurrentFrame
->ScopeTable
->Target
!= NULL
)
277 /* Set exception pointers for this frame */
278 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
280 /* Get the filter result */
281 FilterResult
= _SEH3$
_GetFilterResult(CurrentFrame
);
283 /* Check, if continuuing is requested */
284 if (FilterResult
== EXCEPTION_CONTINUE_EXECUTION
)
286 return ExceptionContinueExecution
;
289 /* Check if the except handler shall be executed */
290 if (FilterResult
== EXCEPTION_EXECUTE_HANDLER
) break;
293 /* Bail out if this is the last handler */
294 if (CurrentFrame
== EstablisherFrame
)
295 return ExceptionContinueSearch
;
297 /* Go to the next frame */
298 CurrentFrame
= CurrentFrame
->Next
;
301 /* Call RtlUnwind to unwind the frames below this one */
302 _SEH3$
_CallRtlUnwind(EstablisherFrame
);
304 /* Do a local unwind up to this frame */
305 TargetFrame
= CurrentFrame
;
308 /* Loop frames up to the target frame */
309 for (CurrentFrame
= EstablisherFrame
->EndOfChain
;
310 CurrentFrame
!= TargetFrame
;
311 CurrentFrame
= CurrentFrame
->Next
)
313 /* Manually unregister the frame */
314 _SEH3$
_Unregister(CurrentFrame
);
316 /* Check if this is an unwind frame */
317 if (CurrentFrame
->ScopeTable
->Target
== NULL
)
319 /* Set exception pointers for this frame */
320 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
322 /* Call the finally function */
323 _SEH3$
_CallFinally(CurrentFrame
);
327 /* Check if this was an unwind */
328 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWINDING
)
330 return ExceptionContinueSearch
;
333 /* Unregister the frame. It will be unregistered again at the end of the
334 __except block, due to auto cleanup, but that doesn't hurt.
335 All we do is set either fs:[0] or EstablisherFrame->EndOfChain to
336 CurrentFrame->Next, which will not change it's value. */
337 _SEH3$
_Unregister(CurrentFrame
);
339 /* Jump to the __except block (does not return) */
340 _SEH3$
_JumpToTarget(CurrentFrame
);