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
);
198 fulltrylevel
->SHT_Common
.ST_Body
,
199 fulltrylevel
->SHT_Esp
,
200 fulltrylevel
->SHT_Ebp
,
201 fulltrylevel
->SHT_Ebx
,
202 fulltrylevel
->SHT_Esi
,
203 fulltrylevel
->SHT_Edi
208 int __cdecl _SEH2FrameHandler
210 struct _EXCEPTION_RECORD
* ExceptionRecord
,
211 void * EstablisherFrame
,
212 struct _CONTEXT
* ContextRecord
,
213 void * DispatcherContext
216 _SEH2Frame_t
* frame
;
218 frame
= EstablisherFrame
;
221 if(ExceptionRecord
->ExceptionFlags
& (EXCEPTION_EXIT_UNWIND
| EXCEPTION_UNWINDING
))
223 _SEH2LocalUnwind(frame
, NULL
);
229 volatile _SEH2TryLevel_t
* trylevel
;
230 EXCEPTION_POINTERS ep
;
232 ep
.ExceptionRecord
= ExceptionRecord
;
233 ep
.ContextRecord
= ContextRecord
;
235 frame
->SF_Code
= ExceptionRecord
->ExceptionCode
;
237 for(trylevel
= frame
->SF_TopTryLevel
; trylevel
!= NULL
; trylevel
= trylevel
->ST_Next
)
239 ret
= _SEH2Except(frame
, trylevel
, &ep
);
242 return ExceptionContinueExecution
;
244 _SEH2Handle(frame
, trylevel
);
248 return ExceptionContinueSearch
;
252 void __cdecl
_SEH2EnterFrame(_SEH2Frame_t
* frame
)
254 frame
->SF_Registration
.SER_Handler
= __SEH2FrameHandler
;
256 __SEH2EnterFrame(&frame
->SF_Registration
);
260 int __cdecl
_SEH2EnterFrameAndTrylevel(_SEH2Frame_t
* frame
, volatile _SEH2TryLevel_t
* trylevel
)
262 frame
->SF_TopTryLevel
= trylevel
;
263 _SEH2EnterFrame(frame
);
268 void __cdecl
_SEH2LeaveFrame(void)
274 void __cdecl
_SEH2Return(void)
276 _SEH2LocalUnwind(CONTAINING_RECORD(_SEH2CurrentRegistration(), _SEH2Frame_t
, SF_Registration
), NULL
);