xref: /reactos/sdk/lib/pseh/i386/framebased-gcchack.c (revision c2c66aff)
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