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 * |-----------| |-----------| / |----------| |----------|
38 #include "pseh3_asmdef.h"
40 /* Make sure the asm definitions match the structures */
41 C_ASSERT(SEH3_REGISTRATION_FRAME_Next
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Next
));
42 C_ASSERT(SEH3_REGISTRATION_FRAME_Handler
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Handler
));
43 C_ASSERT(SEH3_REGISTRATION_FRAME_EndOfChain
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, EndOfChain
));
44 C_ASSERT(SEH3_REGISTRATION_FRAME_ScopeTable
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, ScopeTable
));
45 C_ASSERT(SEH3_REGISTRATION_FRAME_ExceptionPointers
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, ExceptionPointers
));
46 C_ASSERT(SEH3_REGISTRATION_FRAME_Esp
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Esp
));
47 C_ASSERT(SEH3_REGISTRATION_FRAME_Ebp
== FIELD_OFFSET(SEH3$_REGISTRATION_FRAME
, Ebp
));
48 C_ASSERT(SEH3_SCOPE_TABLE_Filter
== FIELD_OFFSET(SEH3$_SCOPE_TABLE
, Filter
));
49 C_ASSERT(SEH3_SCOPE_TABLE_Target
== FIELD_OFFSET(SEH3$_SCOPE_TABLE
, Target
));
52 void _SEH3$
_Unregister(
53 volatile SEH3$_REGISTRATION_FRAME
*Frame
)
56 _SEH3$
_UnregisterFrame(Frame
);
58 _SEH3$
_UnregisterTryLevel(Frame
);
70 /* First call with param = 0 to get the frame layout */
71 "xorl %%ecx, %%ecx\n\t"
72 "xorl %%eax, %%eax\n\t"
75 /* The result is the frame base address that we passed in (0) plus the
76 offset to the registration record. */
78 "addl %[Record], %%eax\n\t"
80 /* Second call to get the filter result */
84 : [Record
] "m" (Record
), [Filter
] "m" (Filter
)
92 _SEH3$
_GetFilterResult(
93 PSEH3$_REGISTRATION_FRAME Record
)
95 PVOID Filter
= Record
->ScopeTable
->Filter
;
98 if (Record
->ScopeTable
->Target
== NULL
)
100 return EXCEPTION_CONTINUE_SEARCH
;
103 /* Check if we have a constant filter */
104 if (((ULONG
)Filter
& 0xFFFFFF00) == 0)
106 /* Lowest 8 bit are sign extended to give the result */
107 Result
= (LONG
)(CHAR
)(ULONG
)Filter
;
111 /* Call the filter function */
112 Result
= _SEH3$
_InvokeFilter(Record
, Filter
);
115 /* Normalize the result */
116 if (Result
< 0) return EXCEPTION_CONTINUE_EXECUTION
;
117 else if (Result
> 0) return EXCEPTION_EXECUTE_HANDLER
;
118 else return EXCEPTION_CONTINUE_SEARCH
;
124 PSEH3$_REGISTRATION_FRAME Record
)
126 _SEH3$
_InvokeFilter(Record
, Record
->ScopeTable
->Filter
);
129 __attribute__((noreturn
))
133 PSEH3$_REGISTRATION_FRAME RegistrationFrame
)
136 /* Load the registers */
137 "movl 20(%%ecx), %%esp\n"
138 "movl 24(%%ecx), %%ebp\n"
140 /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */
143 /* Jump into the exception handler */
146 "c" (RegistrationFrame
),
147 "a" (RegistrationFrame
->ScopeTable
),
148 [Target
] "m" (RegistrationFrame
->ScopeTable
->Target
)
151 __builtin_unreachable();
156 _SEH3$
_CallRtlUnwind(
157 PSEH3$_REGISTRATION_FRAME RegistrationFrame
)
166 "push %[TargetFrame]\n"
167 "call _RtlUnwind@16\n"
169 : "=a" (ClobberedEax
)
170 : [TargetFrame
] "a" (RegistrationFrame
)
171 : "ebx", "ecx", "edx", "esi",
172 "edi", "flags", "memory");
175 EXCEPTION_DISPOSITION
177 __attribute__ ((__target__ ("cld")))
178 _SEH3$
_except_handler(
179 struct _EXCEPTION_RECORD
* ExceptionRecord
,
180 PSEH3$_REGISTRATION_FRAME EstablisherFrame
,
181 struct _CONTEXT
* ContextRecord
,
182 void * DispatcherContext
)
184 PSEH3$_REGISTRATION_FRAME CurrentFrame
, TargetFrame
;
185 SEH3$_EXCEPTION_POINTERS ExceptionPointers
;
188 /* Clear the direction flag. */
189 asm volatile ("cld\n" : : : "memory");
191 /* Check if this is an unwind */
192 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWIND
)
194 /* Unwind all local frames */
195 TargetFrame
= EstablisherFrame
->Next
;
199 /* Save the exception pointers on the stack */
200 ExceptionPointers
.ExceptionRecord
= ExceptionRecord
;
201 ExceptionPointers
.ContextRecord
= ContextRecord
;
203 /* Loop all frames for this registration */
204 CurrentFrame
= EstablisherFrame
->EndOfChain
;
207 /* Check if we have an exception handler */
208 if (CurrentFrame
->ScopeTable
->Target
!= NULL
)
210 /* Set exception pointers for this frame */
211 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
213 /* Get the filter result */
214 FilterResult
= _SEH3$
_GetFilterResult(CurrentFrame
);
216 /* Check, if continuuing is requested */
217 if (FilterResult
== EXCEPTION_CONTINUE_EXECUTION
)
219 return ExceptionContinueExecution
;
222 /* Check if the except handler shall be executed */
223 if (FilterResult
== EXCEPTION_EXECUTE_HANDLER
) break;
226 /* Bail out if this is the last handler */
227 if (CurrentFrame
== EstablisherFrame
)
228 return ExceptionContinueSearch
;
230 /* Go to the next frame */
231 CurrentFrame
= CurrentFrame
->Next
;
234 /* Call RtlUnwind to unwind the frames below this one */
235 _SEH3$
_CallRtlUnwind(EstablisherFrame
);
237 /* Do a local unwind up to this frame */
238 TargetFrame
= CurrentFrame
;
241 /* Loop frames up to the target frame */
242 for (CurrentFrame
= EstablisherFrame
->EndOfChain
;
243 CurrentFrame
!= TargetFrame
;
244 CurrentFrame
= CurrentFrame
->Next
)
246 /* Manually unregister the frame */
247 _SEH3$
_Unregister(CurrentFrame
);
249 /* Check if this is an unwind frame */
250 if (CurrentFrame
->ScopeTable
->Target
== NULL
)
252 /* Set exception pointers for this frame */
253 CurrentFrame
->ExceptionPointers
= &ExceptionPointers
;
255 /* Call the finally function */
256 _SEH3$
_CallFinally(CurrentFrame
);
260 /* Check if this was an unwind */
261 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_UNWINDING
)
263 return ExceptionContinueSearch
;
266 /* Unregister the frame. It will be unregistered again at the end of the
267 __except block, due to auto cleanup, but that doesn't hurt.
268 All we do is set either fs:[0] or EstablisherFrame->EndOfChain to
269 CurrentFrame->Next, which will not change it's value. */
270 _SEH3$
_Unregister(CurrentFrame
);
272 /* Jump to the __except block (does not return) */
273 _SEH3$
_JumpToTarget(CurrentFrame
);