- Revert 44301
[reactos.git] / lib / pseh / i386 / framebased-gcchack.c
1 /*
2 Copyright (c) 2008 KJK::Hyperion
3
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:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
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.
21 */
22
23 #define _NTSYSTEM_ /* removes dllimport attribute from RtlUnwind */
24
25 #define STRICT
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28
29 #include <pseh/pseh2.h>
30 #include <excpt.h>
31 #include <intrin.h>
32
33 #ifndef EXCEPTION_EXIT_UNWIND
34 #define EXCEPTION_EXIT_UNWIND 4
35 #endif
36
37 #ifndef EXCEPTION_UNWINDING
38 #define EXCEPTION_UNWINDING 2
39 #endif
40
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 *);
44
45 typedef struct __SEHTrampoline
46 {
47 unsigned char STR_MovEcx;
48 unsigned char * STR_Closure;
49 unsigned char STR_Jmp;
50 unsigned char * STR_Function;
51 }
52 __attribute__((packed))
53 _SEHTrampoline_t;
54
55 FORCEINLINE
56 int _SEHIsTrampoline(_SEHTrampoline_t * trampoline_)
57 {
58 return trampoline_->STR_MovEcx == 0xb9 && trampoline_->STR_Jmp == 0xe9;
59 }
60
61 FORCEINLINE
62 void * _SEHFunctionFromTrampoline(_SEHTrampoline_t * trampoline_)
63 {
64 return (int)(trampoline_ + 1) + trampoline_->STR_Function;
65 }
66
67 FORCEINLINE
68 void * _SEHClosureFromTrampoline(_SEHTrampoline_t * trampoline_)
69 {
70 return trampoline_->STR_Closure;
71 }
72
73 FORCEINLINE
74 _SEH2Registration_t * __cdecl _SEH2CurrentRegistration(void)
75 {
76 return (_SEH2Registration_t *)__readfsdword(0);
77 }
78
79 FORCEINLINE
80 void __cdecl __SEH2EnterFrame(_SEH2Registration_t * frame)
81 {
82 frame->SER_Prev = _SEH2CurrentRegistration();
83 __writefsdword(0, (unsigned long)frame);
84 }
85
86 FORCEINLINE
87 void __cdecl __SEH2LeaveFrame(void)
88 {
89 __writefsdword(0, (unsigned long)_SEH2CurrentRegistration()->SER_Prev);
90 }
91
92 FORCEINLINE
93 void _SEH2GlobalUnwind(void * target)
94 {
95 __asm__ __volatile__
96 (
97 "push %%ebp\n"
98 "push $0\n"
99 "push $0\n"
100 "push $Return%=\n"
101 "push %[target]\n"
102 "call %c[RtlUnwind]\n"
103 "Return%=: pop %%ebp\n" :
104 :
105 [target] "g" (target), [RtlUnwind] "g" (&RtlUnwind) :
106 "eax", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory"
107 );
108 }
109
110 static
111 __SEH_EXCEPT_RET _SEH2Except(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel, struct _EXCEPTION_POINTERS * ep)
112 {
113 void * filter = trylevel->ST_Filter;
114 void * context = NULL;
115 __SEH_EXCEPT_RET ret;
116
117 if(filter == (void *)0)
118 return 0;
119
120 if(filter == (void *)1)
121 return 1;
122
123 if(filter == (void *)-1)
124 return -1;
125
126 if(_SEHIsTrampoline((_SEHTrampoline_t *)filter))
127 {
128 context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)filter);
129 filter = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)filter);
130 }
131
132 __asm__ __volatile__
133 (
134 "push %[ep]\n"
135 "push %[frame]\n"
136 "call *%[filter]\n"
137 "pop %%edx\n"
138 "pop %%edx\n" :
139 [ret] "=a" (ret) :
140 "c" (context), [filter] "r" (filter), [frame] "g" (frame), [ep] "g" (ep) :
141 "edx", "flags", "memory"
142 );
143
144 return ret;
145 }
146
147 static
148 void _SEH2Finally(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
149 {
150 if(trylevel->ST_Filter == NULL && trylevel->ST_Body != NULL)
151 {
152 void * body = trylevel->ST_Body;
153 void * context = NULL;
154
155 if(_SEHIsTrampoline((_SEHTrampoline_t *)body))
156 {
157 context = _SEHClosureFromTrampoline((_SEHTrampoline_t *)body);
158 body = _SEHFunctionFromTrampoline((_SEHTrampoline_t *)body);
159 }
160
161 __asm__ __volatile__("call *%1\n" : : "c" (context), "r" (body) : "eax", "edx", "flags", "memory");
162 }
163 }
164
165 typedef struct __SEH2UnwindFrame
166 {
167 _SEH2Registration_t SUF_Registration;
168 _SEH2Frame_t * SUF_Frame;
169 volatile _SEH2TryLevel_t * SUF_TargetTryLevel;
170 }
171 _SEH2UnwindFrame_t;
172
173 static void _SEH2LocalUnwind(_SEH2Frame_t *, volatile _SEH2TryLevel_t *);
174
175 extern
176 int __cdecl _SEH2UnwindHandler
177 (
178 struct _EXCEPTION_RECORD * ExceptionRecord,
179 void * EstablisherFrame,
180 struct _CONTEXT * ContextRecord,
181 void * DispatcherContext
182 )
183 {
184 if(ExceptionRecord->ExceptionFlags & (EXCEPTION_EXIT_UNWIND | EXCEPTION_UNWINDING))
185 {
186 _SEH2UnwindFrame_t * unwindframe = CONTAINING_RECORD(EstablisherFrame, _SEH2UnwindFrame_t, SUF_Registration);
187 _SEH2LocalUnwind(unwindframe->SUF_Frame, unwindframe->SUF_TargetTryLevel);
188 *((void **)DispatcherContext) = EstablisherFrame;
189 return ExceptionCollidedUnwind;
190 }
191
192 return ExceptionContinueSearch;
193 }
194
195 static
196 void _SEH2LocalUnwind(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * dsttrylevel)
197 {
198 volatile _SEH2TryLevel_t * trylevel;
199 _SEH2UnwindFrame_t unwindframe;
200
201 unwindframe.SUF_Frame = frame;
202 unwindframe.SUF_TargetTryLevel = dsttrylevel;
203
204 unwindframe.SUF_Registration.SER_Handler = &__SEH2UnwindHandler;
205 __SEH2EnterFrame(&unwindframe.SUF_Registration);
206
207 for(trylevel = frame->SF_TopTryLevel; trylevel && trylevel != dsttrylevel; trylevel = trylevel->ST_Next)
208 {
209 frame->SF_TopTryLevel = trylevel->ST_Next;
210 _SEH2Finally(frame, trylevel);
211 }
212
213 __SEH2LeaveFrame();
214 }
215
216 static DECLSPEC_NORETURN
217 void _SEH2Handle(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
218 {
219 volatile _SEH2HandleTryLevel_t * fulltrylevel = CONTAINING_RECORD(trylevel, _SEH2HandleTryLevel_t, SHT_Common);
220
221 _SEH2GlobalUnwind(frame);
222 _SEH2LocalUnwind(frame, &fulltrylevel->SHT_Common);
223 frame->SF_TopTryLevel = fulltrylevel->SHT_Common.ST_Next;
224
225 __SEH2Handle
226 (
227 fulltrylevel->SHT_Common.ST_Body,
228 fulltrylevel->SHT_Esp,
229 fulltrylevel->SHT_Ebp,
230 fulltrylevel->SHT_Ebx,
231 fulltrylevel->SHT_Esi,
232 fulltrylevel->SHT_Edi
233 );
234 }
235
236 extern
237 int __cdecl _SEH2FrameHandler
238 (
239 struct _EXCEPTION_RECORD * ExceptionRecord,
240 void * EstablisherFrame,
241 struct _CONTEXT * ContextRecord,
242 void * DispatcherContext
243 )
244 {
245 _SEH2Frame_t * frame;
246
247 frame = EstablisherFrame;
248
249 /* Unwinding */
250 if(ExceptionRecord->ExceptionFlags & (EXCEPTION_EXIT_UNWIND | EXCEPTION_UNWINDING))
251 {
252 _SEH2LocalUnwind(frame, NULL);
253 }
254 /* Handling */
255 else
256 {
257 int ret = 0;
258 volatile _SEH2TryLevel_t * trylevel;
259 EXCEPTION_POINTERS ep;
260
261 ep.ExceptionRecord = ExceptionRecord;
262 ep.ContextRecord = ContextRecord;
263
264 frame->SF_Code = ExceptionRecord->ExceptionCode;
265
266 for(trylevel = frame->SF_TopTryLevel; trylevel != NULL; trylevel = trylevel->ST_Next)
267 {
268 ret = _SEH2Except(frame, trylevel, &ep);
269
270 if(ret < 0)
271 return ExceptionContinueExecution;
272 else if(ret > 0)
273 _SEH2Handle(frame, trylevel);
274 }
275 }
276
277 return ExceptionContinueSearch;
278 }
279
280 extern
281 void __cdecl _SEH2EnterFrame(_SEH2Frame_t * frame)
282 {
283 frame->SF_Registration.SER_Handler = __SEH2FrameHandler;
284 frame->SF_Code = 0;
285 __SEH2EnterFrame(&frame->SF_Registration);
286 }
287
288 extern
289 int __cdecl _SEH2EnterFrameAndTrylevel(_SEH2Frame_t * frame, volatile _SEH2TryLevel_t * trylevel)
290 {
291 frame->SF_TopTryLevel = trylevel;
292 _SEH2EnterFrame(frame);
293 return 0;
294 }
295
296 extern
297 void __cdecl _SEH2LeaveFrame(void)
298 {
299 __SEH2LeaveFrame();
300 }
301
302 extern
303 void __cdecl _SEH2Return(void)
304 {
305 _SEH2LocalUnwind(CONTAINING_RECORD(_SEH2CurrentRegistration(), _SEH2Frame_t, SF_Registration), NULL);
306 _SEH2LeaveFrame();
307 }
308
309 /* EOF */