2 Copyright (c) 2008 KJK::Hyperion
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
23 #define _NTSYSTEM_ /* removes dllimport attribute from RtlUnwind */
26 #define WIN32_LEAN_AND_MEAN
29 #include <pseh/pseh2.h>
33 #ifndef EXCEPTION_EXIT_UNWIND
34 #define EXCEPTION_EXIT_UNWIND 4
37 #ifndef EXCEPTION_UNWINDING
38 #define EXCEPTION_UNWINDING 2
41 extern DECLSPEC_NORETURN
int __SEH2Handle(void *, void *, void *, void *, void *, void *);
42 extern int __cdecl
__SEH2FrameHandler(struct _EXCEPTION_RECORD
*, void *, struct _CONTEXT
*, void *);
43 extern int __cdecl
__SEH2UnwindHandler(struct _EXCEPTION_RECORD
*, void *, struct _CONTEXT
*, void *);
46 _SEH2Registration_t
* __cdecl
_SEH2CurrentRegistration(void)
48 return (_SEH2Registration_t
*)__readfsdword(0);
52 void __cdecl
__SEH2EnterFrame(_SEH2Registration_t
* frame
)
54 frame
->SER_Prev
= _SEH2CurrentRegistration();
55 __writefsdword(0, (unsigned long)frame
);
59 void __cdecl
__SEH2LeaveFrame(void)
61 __writefsdword(0, (unsigned long)_SEH2CurrentRegistration()->SER_Prev
);
65 void _SEH2GlobalUnwind(void * target
)
74 "call %c[RtlUnwind]\n"
75 "Return%=: pop %%ebp\n" :
77 [target
] "g" (target
), [RtlUnwind
] "g" (&RtlUnwind
) :
78 "eax", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory"
83 __SEH_EXCEPT_RET
_SEH2Except(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* trylevel
, struct _EXCEPTION_POINTERS
* ep
)
85 void * filter
= trylevel
->ST_Filter
;
86 void * context
= NULL
;
89 if(filter
== (void *)0)
92 if(filter
== (void *)1)
95 if(filter
== (void *)-1)
98 if(_SEHIsTrampoline((_SEHTrampoline_t
*)filter
))
100 context
= _SEHClosureFromTrampoline((_SEHTrampoline_t
*)filter
);
101 filter
= _SEHFunctionFromTrampoline((_SEHTrampoline_t
*)filter
);
112 "c" (context
), [filter
] "r" (filter
), [frame
] "g" (frame
), [ep
] "g" (ep
) :
113 "edx", "flags", "memory"
120 void _SEH2Finally(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* trylevel
)
122 if(trylevel
->ST_Filter
== NULL
&& trylevel
->ST_Body
!= NULL
)
124 void * body
= trylevel
->ST_Body
;
125 void * context
= NULL
;
127 if(_SEHIsTrampoline((_SEHTrampoline_t
*)body
))
129 context
= _SEHClosureFromTrampoline((_SEHTrampoline_t
*)body
);
130 body
= _SEHFunctionFromTrampoline((_SEHTrampoline_t
*)body
);
133 __asm__
__volatile__("call *%1\n" : : "c" (context
), "r" (body
) : "eax", "edx", "flags", "memory");
137 typedef struct __SEH2UnwindFrame
139 _SEH2Registration_t SUF_Registration
;
140 _SEH2Frame_t
* SUF_Frame
;
141 volatile _SEH2TryLevel_t
* SUF_TargetTryLevel
;
145 static void _SEH2LocalUnwind(_SEH2Frame_t
*, volatile _SEH2TryLevel_t
*);
148 int __cdecl _SEH2UnwindHandler
150 struct _EXCEPTION_RECORD
* ExceptionRecord
,
151 void * EstablisherFrame
,
152 struct _CONTEXT
* ContextRecord
,
153 void * DispatcherContext
156 if(ExceptionRecord
->ExceptionFlags
& (EXCEPTION_EXIT_UNWIND
| EXCEPTION_UNWINDING
))
158 _SEH2UnwindFrame_t
* unwindframe
= CONTAINING_RECORD(EstablisherFrame
, _SEH2UnwindFrame_t
, SUF_Registration
);
159 _SEH2LocalUnwind(unwindframe
->SUF_Frame
, unwindframe
->SUF_TargetTryLevel
);
160 *((void **)DispatcherContext
) = EstablisherFrame
;
161 return ExceptionCollidedUnwind
;
164 return ExceptionContinueSearch
;
168 void _SEH2LocalUnwind(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* dsttrylevel
)
170 volatile _SEH2TryLevel_t
* trylevel
;
171 _SEH2UnwindFrame_t unwindframe
;
173 unwindframe
.SUF_Frame
= frame
;
174 unwindframe
.SUF_TargetTryLevel
= dsttrylevel
;
176 unwindframe
.SUF_Registration
.SER_Handler
= &__SEH2UnwindHandler
;
177 __SEH2EnterFrame(&unwindframe
.SUF_Registration
);
179 for(trylevel
= frame
->SF_TopTryLevel
; trylevel
&& trylevel
!= dsttrylevel
; trylevel
= trylevel
->ST_Next
)
181 frame
->SF_TopTryLevel
= trylevel
->ST_Next
;
182 _SEH2Finally(frame
, trylevel
);
188 static DECLSPEC_NORETURN
189 void _SEH2Handle(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* trylevel
)
191 volatile _SEH2HandleTryLevel_t
* fulltrylevel
= CONTAINING_RECORD(trylevel
, _SEH2HandleTryLevel_t
, SHT_Common
);
193 _SEH2GlobalUnwind(frame
);
194 _SEH2LocalUnwind(frame
, &fulltrylevel
->SHT_Common
);
195 frame
->SF_TopTryLevel
= fulltrylevel
->SHT_Common
.ST_Next
;
199 fulltrylevel
->SHT_Common
.ST_Body
,
200 fulltrylevel
->SHT_Esp
,
201 fulltrylevel
->SHT_Ebp
,
202 fulltrylevel
->SHT_Ebx
,
203 fulltrylevel
->SHT_Esi
,
204 fulltrylevel
->SHT_Edi
209 int __cdecl _SEH2FrameHandler
211 struct _EXCEPTION_RECORD
* ExceptionRecord
,
212 void * EstablisherFrame
,
213 struct _CONTEXT
* ContextRecord
,
214 void * DispatcherContext
217 _SEH2Frame_t
* frame
;
219 frame
= EstablisherFrame
;
222 if(ExceptionRecord
->ExceptionFlags
& (EXCEPTION_EXIT_UNWIND
| EXCEPTION_UNWINDING
))
224 _SEH2LocalUnwind(frame
, NULL
);
230 volatile _SEH2TryLevel_t
* trylevel
;
231 EXCEPTION_POINTERS ep
;
233 ep
.ExceptionRecord
= ExceptionRecord
;
234 ep
.ContextRecord
= ContextRecord
;
236 frame
->SF_Code
= ExceptionRecord
->ExceptionCode
;
238 for(trylevel
= frame
->SF_TopTryLevel
; trylevel
!= NULL
; trylevel
= trylevel
->ST_Next
)
240 ret
= _SEH2Except(frame
, trylevel
, &ep
);
243 return ExceptionContinueExecution
;
245 _SEH2Handle(frame
, trylevel
);
249 return ExceptionContinueSearch
;
253 void __cdecl
_SEH2EnterFrame(_SEH2Frame_t
* frame
)
255 frame
->SF_Registration
.SER_Handler
= __SEH2FrameHandler
;
257 __SEH2EnterFrame(&frame
->SF_Registration
);
261 int __cdecl
_SEH2EnterFrameAndTrylevel(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* trylevel
)
263 frame
->SF_TopTryLevel
= trylevel
;
264 _SEH2EnterFrame(frame
);
269 void __cdecl
_SEH2LeaveFrame(void)
275 void __cdecl
_SEH2Return(void)
277 _SEH2LocalUnwind(CONTAINING_RECORD(_SEH2CurrentRegistration(), _SEH2Frame_t
, SF_Registration
), NULL
);