1*c2c66affSColin Finck /*
2*c2c66affSColin Finck Copyright (c) 2008 KJK::Hyperion
3*c2c66affSColin Finck
4*c2c66affSColin Finck Permission is hereby granted, free of charge, to any person obtaining a
5*c2c66affSColin Finck copy of this software and associated documentation files (the "Software"),
6*c2c66affSColin Finck to deal in the Software without restriction, including without limitation
7*c2c66affSColin Finck the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*c2c66affSColin Finck and/or sell copies of the Software, and to permit persons to whom the
9*c2c66affSColin Finck Software is furnished to do so, subject to the following conditions:
10*c2c66affSColin Finck
11*c2c66affSColin Finck The above copyright notice and this permission notice shall be included in
12*c2c66affSColin Finck all copies or substantial portions of the Software.
13*c2c66affSColin Finck
14*c2c66affSColin Finck THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*c2c66affSColin Finck IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*c2c66affSColin Finck FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*c2c66affSColin Finck AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*c2c66affSColin Finck LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19*c2c66affSColin Finck FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20*c2c66affSColin Finck DEALINGS IN THE SOFTWARE.
21*c2c66affSColin Finck */
22*c2c66affSColin Finck
23*c2c66affSColin Finck #define _NTSYSTEM_ /* removes dllimport attribute from RtlUnwind */
24*c2c66affSColin Finck
25*c2c66affSColin Finck #define STRICT
26*c2c66affSColin Finck #include <windef.h>
27*c2c66affSColin Finck #include <stdarg.h>
28*c2c66affSColin Finck
29*c2c66affSColin Finck #include <pseh/pseh2.h>
30*c2c66affSColin Finck #include <excpt.h>
31*c2c66affSColin Finck #include <intrin.h>
32*c2c66affSColin Finck
33*c2c66affSColin Finck #ifndef EXCEPTION_EXIT_UNWIND
34*c2c66affSColin Finck #define EXCEPTION_EXIT_UNWIND 4
35*c2c66affSColin Finck #endif
36*c2c66affSColin Finck
37*c2c66affSColin Finck #ifndef EXCEPTION_UNWINDING
38*c2c66affSColin Finck #define EXCEPTION_UNWINDING 2
39*c2c66affSColin Finck #endif
40*c2c66affSColin Finck
41*c2c66affSColin Finck extern DECLSPEC_NORETURN int __SEH2Handle(void *, void *, void *, void *, void *, void *);
42*c2c66affSColin Finck extern int __cdecl __SEH2FrameHandler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
43*c2c66affSColin Finck extern int __cdecl __SEH2UnwindHandler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
44*c2c66affSColin Finck
45*c2c66affSColin Finck typedef struct __SEHTrampoline
46*c2c66affSColin Finck {
47*c2c66affSColin Finck unsigned char STR_MovEcx;
48*c2c66affSColin Finck unsigned char * STR_Closure;
49*c2c66affSColin Finck unsigned char STR_Jmp;
50*c2c66affSColin Finck unsigned char * STR_Function;
51*c2c66affSColin Finck }
52*c2c66affSColin Finck __attribute__((packed))
53*c2c66affSColin Finck _SEHTrampoline_t;
54*c2c66affSColin Finck
55*c2c66affSColin Finck FORCEINLINE
_SEHIsTrampoline(_SEHTrampoline_t * trampoline_)56*c2c66affSColin Finck int _SEHIsTrampoline(_SEHTrampoline_t * trampoline_)
57*c2c66affSColin Finck {
58*c2c66affSColin Finck return trampoline_->STR_MovEcx == 0xb9 && trampoline_->STR_Jmp == 0xe9;
59*c2c66affSColin Finck }
60*c2c66affSColin Finck
61*c2c66affSColin Finck FORCEINLINE
_SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)62*c2c66affSColin Finck void * _SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)
63*c2c66affSColin Finck {
64*c2c66affSColin Finck return (int)(trampoline_ + 1) + trampoline_->STR_Function;
65*c2c66affSColin Finck }
66*c2c66affSColin Finck
67*c2c66affSColin Finck FORCEINLINE
_SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)68*c2c66affSColin Finck void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
69*c2c66affSColin Finck {
70*c2c66affSColin Finck return trampoline_->STR_Closure;
71*c2c66affSColin Finck }
72*c2c66affSColin Finck
73*c2c66affSColin Finck FORCEINLINE
_SEH2CurrentRegistration(void)74*c2c66affSColin Finck _SEH2Registration_t * __cdecl _SEH2CurrentRegistration(void)
75*c2c66affSColin Finck {
76*c2c66affSColin Finck return (_SEH2Registration_t *)__readfsdword(0);
77*c2c66affSColin Finck }
78*c2c66affSColin Finck
79*c2c66affSColin Finck FORCEINLINE
__SEH2EnterFrame(_SEH2Registration_t * frame)80*c2c66affSColin Finck void __cdecl __SEH2EnterFrame(_SEH2Registration_t * frame)
81*c2c66affSColin Finck {
82*c2c66affSColin Finck frame->SER_Prev = _SEH2CurrentRegistration();
83*c2c66affSColin Finck __writefsdword(0, (unsigned long)frame);
84*c2c66affSColin Finck }
85*c2c66affSColin Finck
86*c2c66affSColin Finck FORCEINLINE
__SEH2LeaveFrame(void)87*c2c66affSColin Finck void __cdecl __SEH2LeaveFrame(void)
88*c2c66affSColin Finck {
89*c2c66affSColin Finck __writefsdword(0, (unsigned long)_SEH2CurrentRegistration()->SER_Prev);
90*c2c66affSColin Finck }
91*c2c66affSColin Finck
92*c2c66affSColin Finck FORCEINLINE
_SEH2GlobalUnwind(void * target)93*c2c66affSColin Finck void _SEH2GlobalUnwind(void * target)
94*c2c66affSColin Finck {
95*c2c66affSColin Finck __asm__ __volatile__
96*c2c66affSColin Finck (
97*c2c66affSColin Finck "push %%ebp\n\t"
98*c2c66affSColin Finck "push $0\n\t"
99*c2c66affSColin Finck "push $0\n\t"
100*c2c66affSColin Finck "push $Return%=\n\t"
101*c2c66affSColin Finck "push %[target]\n\t"
102*c2c66affSColin Finck "call %c[RtlUnwind]\n"
103*c2c66affSColin Finck "Return%=:\n\t"
104*c2c66affSColin Finck "pop %%ebp" :
105*c2c66affSColin Finck :
106*c2c66affSColin Finck [target] "g" (target), [RtlUnwind] "g" (&RtlUnwind) :
107*c2c66affSColin Finck "eax", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory"
108*c2c66affSColin Finck );
109*c2c66affSColin Finck }
110*c2c66affSColin Finck
111*c2c66affSColin Finck static
_SEH2Except(_SEH2Frame_t * frame,volatile _SEH2TryLevel_t * trylevel,struct _EXCEPTION_POINTERS * ep)112*c2c66affSColin Finck __SEH_EXCEPT_RET _SEH2Except(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel, struct _EXCEPTION_POINTERS * ep)
113*c2c66affSColin Finck {
114*c2c66affSColin Finck void * filter = trylevel->ST_Filter;
115*c2c66affSColin Finck void * context = NULL;
116*c2c66affSColin Finck __SEH_EXCEPT_RET ret;
117*c2c66affSColin Finck
118*c2c66affSColin Finck if(filter == (void *)0)
119*c2c66affSColin Finck return 0;
120*c2c66affSColin Finck
121*c2c66affSColin Finck if(filter == (void *)1)
122*c2c66affSColin Finck return 1;
123*c2c66affSColin Finck
124*c2c66affSColin Finck if(filter == (void *)-1)
125*c2c66affSColin Finck return -1;
126*c2c66affSColin Finck
127*c2c66affSColin Finck if(_SEHIsTrampoline((_SEHTrampoline_t *)filter))
128*c2c66affSColin Finck {
129*c2c66affSColin Finck context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)filter);
130*c2c66affSColin Finck filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)filter);
131*c2c66affSColin Finck }
132*c2c66affSColin Finck
133*c2c66affSColin Finck __asm__ __volatile__
134*c2c66affSColin Finck (
135*c2c66affSColin Finck "push %[ep]\n\t"
136*c2c66affSColin Finck "push %[frame]\n\t"
137*c2c66affSColin Finck "call *%[filter]\n\t"
138*c2c66affSColin Finck "pop %%edx\n\t"
139*c2c66affSColin Finck "pop %%edx" :
140*c2c66affSColin Finck [ret] "=a" (ret) :
141*c2c66affSColin Finck "c" (context), [filter] "r" (filter), [frame] "r" (frame), [ep] "r" (ep) :
142*c2c66affSColin Finck "edx", "flags", "memory"
143*c2c66affSColin Finck );
144*c2c66affSColin Finck
145*c2c66affSColin Finck return ret;
146*c2c66affSColin Finck }
147*c2c66affSColin Finck
148*c2c66affSColin Finck static
_SEH2Finally(_SEH2Frame_t * frame,volatile _SEH2TryLevel_t * trylevel)149*c2c66affSColin Finck void _SEH2Finally(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
150*c2c66affSColin Finck {
151*c2c66affSColin Finck if(trylevel->ST_Filter == NULL && trylevel->ST_Body != NULL)
152*c2c66affSColin Finck {
153*c2c66affSColin Finck void * body = trylevel->ST_Body;
154*c2c66affSColin Finck void * context = NULL;
155*c2c66affSColin Finck
156*c2c66affSColin Finck if(_SEHIsTrampoline((_SEHTrampoline_t *)body))
157*c2c66affSColin Finck {
158*c2c66affSColin Finck context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)body);
159*c2c66affSColin Finck body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)body);
160*c2c66affSColin Finck }
161*c2c66affSColin Finck
162*c2c66affSColin Finck __asm__ __volatile__("call *%1" : : "c" (context), "r" (body) : "eax", "edx", "flags", "memory");
163*c2c66affSColin Finck }
164*c2c66affSColin Finck }
165*c2c66affSColin Finck
166*c2c66affSColin Finck typedef struct __SEH2UnwindFrame
167*c2c66affSColin Finck {
168*c2c66affSColin Finck _SEH2Registration_t SUF_Registration;
169*c2c66affSColin Finck _SEH2Frame_t * SUF_Frame;
170*c2c66affSColin Finck volatile _SEH2TryLevel_t * SUF_TargetTryLevel;
171*c2c66affSColin Finck }
172*c2c66affSColin Finck _SEH2UnwindFrame_t;
173*c2c66affSColin Finck
174*c2c66affSColin Finck static void _SEH2LocalUnwind(_SEH2Frame_t *, volatile _SEH2TryLevel_t *);
175*c2c66affSColin Finck
176*c2c66affSColin Finck extern
_SEH2UnwindHandler(struct _EXCEPTION_RECORD * ExceptionRecord,void * EstablisherFrame,struct _CONTEXT * ContextRecord,void * DispatcherContext)177*c2c66affSColin Finck int __cdecl _SEH2UnwindHandler
178*c2c66affSColin Finck (
179*c2c66affSColin Finck struct _EXCEPTION_RECORD * ExceptionRecord,
180*c2c66affSColin Finck void * EstablisherFrame,
181*c2c66affSColin Finck struct _CONTEXT * ContextRecord,
182*c2c66affSColin Finck void * DispatcherContext
183*c2c66affSColin Finck )
184*c2c66affSColin Finck {
185*c2c66affSColin Finck if(ExceptionRecord->ExceptionFlags & (EXCEPTION_EXIT_UNWIND | EXCEPTION_UNWINDING))
186*c2c66affSColin Finck {
187*c2c66affSColin Finck _SEH2UnwindFrame_t * unwindframe = CONTAINING_RECORD(EstablisherFrame, _SEH2UnwindFrame_t, SUF_Registration);
188*c2c66affSColin Finck _SEH2LocalUnwind(unwindframe->SUF_Frame, unwindframe->SUF_TargetTryLevel);
189*c2c66affSColin Finck *((void **)DispatcherContext) = EstablisherFrame;
190*c2c66affSColin Finck return ExceptionCollidedUnwind;
191*c2c66affSColin Finck }
192*c2c66affSColin Finck
193*c2c66affSColin Finck return ExceptionContinueSearch;
194*c2c66affSColin Finck }
195*c2c66affSColin Finck
196*c2c66affSColin Finck static
_SEH2LocalUnwind(_SEH2Frame_t * frame,volatile _SEH2TryLevel_t * dsttrylevel)197*c2c66affSColin Finck void _SEH2LocalUnwind(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * dsttrylevel)
198*c2c66affSColin Finck {
199*c2c66affSColin Finck volatile _SEH2TryLevel_t * trylevel;
200*c2c66affSColin Finck _SEH2UnwindFrame_t unwindframe;
201*c2c66affSColin Finck
202*c2c66affSColin Finck unwindframe.SUF_Frame = frame;
203*c2c66affSColin Finck unwindframe.SUF_TargetTryLevel = dsttrylevel;
204*c2c66affSColin Finck
205*c2c66affSColin Finck unwindframe.SUF_Registration.SER_Handler = &__SEH2UnwindHandler;
206*c2c66affSColin Finck __SEH2EnterFrame(&unwindframe.SUF_Registration);
207*c2c66affSColin Finck
208*c2c66affSColin Finck for(trylevel = frame->SF_TopTryLevel; trylevel && trylevel != dsttrylevel; trylevel = trylevel->ST_Next)
209*c2c66affSColin Finck {
210*c2c66affSColin Finck frame->SF_TopTryLevel = trylevel->ST_Next;
211*c2c66affSColin Finck _SEH2Finally(frame, trylevel);
212*c2c66affSColin Finck }
213*c2c66affSColin Finck
214*c2c66affSColin Finck __SEH2LeaveFrame();
215*c2c66affSColin Finck }
216*c2c66affSColin Finck
217*c2c66affSColin Finck static DECLSPEC_NORETURN
_SEH2Handle(_SEH2Frame_t * frame,volatile _SEH2TryLevel_t * trylevel)218*c2c66affSColin Finck void _SEH2Handle(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
219*c2c66affSColin Finck {
220*c2c66affSColin Finck volatile _SEH2HandleTryLevel_t * fulltrylevel = CONTAINING_RECORD(trylevel, _SEH2HandleTryLevel_t, SHT_Common);
221*c2c66affSColin Finck
222*c2c66affSColin Finck _SEH2GlobalUnwind(frame);
223*c2c66affSColin Finck _SEH2LocalUnwind(frame, &fulltrylevel->SHT_Common);
224*c2c66affSColin Finck frame->SF_TopTryLevel = fulltrylevel->SHT_Common.ST_Next;
225*c2c66affSColin Finck
226*c2c66affSColin Finck __SEH2Handle
227*c2c66affSColin Finck (
228*c2c66affSColin Finck fulltrylevel->SHT_Common.ST_Body,
229*c2c66affSColin Finck fulltrylevel->SHT_Esp,
230*c2c66affSColin Finck fulltrylevel->SHT_Ebp,
231*c2c66affSColin Finck fulltrylevel->SHT_Ebx,
232*c2c66affSColin Finck fulltrylevel->SHT_Esi,
233*c2c66affSColin Finck fulltrylevel->SHT_Edi
234*c2c66affSColin Finck );
235*c2c66affSColin Finck }
236*c2c66affSColin Finck
237*c2c66affSColin Finck extern
_SEH2FrameHandler(struct _EXCEPTION_RECORD * ExceptionRecord,void * EstablisherFrame,struct _CONTEXT * ContextRecord,void * DispatcherContext)238*c2c66affSColin Finck int __cdecl _SEH2FrameHandler
239*c2c66affSColin Finck (
240*c2c66affSColin Finck struct _EXCEPTION_RECORD * ExceptionRecord,
241*c2c66affSColin Finck void * EstablisherFrame,
242*c2c66affSColin Finck struct _CONTEXT * ContextRecord,
243*c2c66affSColin Finck void * DispatcherContext
244*c2c66affSColin Finck )
245*c2c66affSColin Finck {
246*c2c66affSColin Finck _SEH2Frame_t * frame;
247*c2c66affSColin Finck
248*c2c66affSColin Finck frame = EstablisherFrame;
249*c2c66affSColin Finck
250*c2c66affSColin Finck /* Unwinding */
251*c2c66affSColin Finck if(ExceptionRecord->ExceptionFlags & (EXCEPTION_EXIT_UNWIND | EXCEPTION_UNWINDING))
252*c2c66affSColin Finck {
253*c2c66affSColin Finck _SEH2LocalUnwind(frame, NULL);
254*c2c66affSColin Finck }
255*c2c66affSColin Finck /* Handling */
256*c2c66affSColin Finck else
257*c2c66affSColin Finck {
258*c2c66affSColin Finck int ret = 0;
259*c2c66affSColin Finck volatile _SEH2TryLevel_t * trylevel;
260*c2c66affSColin Finck EXCEPTION_POINTERS ep;
261*c2c66affSColin Finck
262*c2c66affSColin Finck ep.ExceptionRecord = ExceptionRecord;
263*c2c66affSColin Finck ep.ContextRecord = ContextRecord;
264*c2c66affSColin Finck
265*c2c66affSColin Finck frame->SF_Code = ExceptionRecord->ExceptionCode;
266*c2c66affSColin Finck
267*c2c66affSColin Finck for(trylevel = frame->SF_TopTryLevel; trylevel != NULL; trylevel = trylevel->ST_Next)
268*c2c66affSColin Finck {
269*c2c66affSColin Finck ret = _SEH2Except(frame, trylevel, &ep);
270*c2c66affSColin Finck
271*c2c66affSColin Finck if(ret < 0)
272*c2c66affSColin Finck return ExceptionContinueExecution;
273*c2c66affSColin Finck else if(ret > 0)
274*c2c66affSColin Finck _SEH2Handle(frame, trylevel);
275*c2c66affSColin Finck }
276*c2c66affSColin Finck }
277*c2c66affSColin Finck
278*c2c66affSColin Finck return ExceptionContinueSearch;
279*c2c66affSColin Finck }
280*c2c66affSColin Finck
281*c2c66affSColin Finck extern
_SEH2EnterFrame(_SEH2Frame_t * frame)282*c2c66affSColin Finck void __cdecl _SEH2EnterFrame(_SEH2Frame_t * frame)
283*c2c66affSColin Finck {
284*c2c66affSColin Finck frame->SF_Registration.SER_Handler = __SEH2FrameHandler;
285*c2c66affSColin Finck frame->SF_Code = 0;
286*c2c66affSColin Finck __SEH2EnterFrame(&frame->SF_Registration);
287*c2c66affSColin Finck }
288*c2c66affSColin Finck
289*c2c66affSColin Finck extern
_SEH2EnterFrameAndTrylevel(_SEH2Frame_t * frame,volatile _SEH2TryLevel_t * trylevel)290*c2c66affSColin Finck int __cdecl _SEH2EnterFrameAndTrylevel(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
291*c2c66affSColin Finck {
292*c2c66affSColin Finck frame->SF_TopTryLevel = trylevel;
293*c2c66affSColin Finck _SEH2EnterFrame(frame);
294*c2c66affSColin Finck return 0;
295*c2c66affSColin Finck }
296*c2c66affSColin Finck
297*c2c66affSColin Finck extern
_SEH2LeaveFrame(void)298*c2c66affSColin Finck void __cdecl _SEH2LeaveFrame(void)
299*c2c66affSColin Finck {
300*c2c66affSColin Finck __SEH2LeaveFrame();
301*c2c66affSColin Finck }
302*c2c66affSColin Finck
303*c2c66affSColin Finck extern
_SEH2Return(void)304*c2c66affSColin Finck void __cdecl _SEH2Return(void)
305*c2c66affSColin Finck {
306*c2c66affSColin Finck _SEH2LocalUnwind(CONTAINING_RECORD(_SEH2CurrentRegistration(), _SEH2Frame_t, SF_Registration), NULL);
307*c2c66affSColin Finck _SEH2LeaveFrame();
308*c2c66affSColin Finck }
309*c2c66affSColin Finck
310*c2c66affSColin Finck /* EOF */
311