1 /*
2 Copyright (c) 2004/2005 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_
24 #define STRICT
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27
28 #include <pseh/pseh.h>
29 #include <pseh/framebased/internal.h>
30 #include <pseh/excpt.h>
31 #include <pseh/framebased.h>
32
33 #include <excpt.h>
34
35 /* Tracing */
36 #ifdef _SEH_ENABLE_TRACE
37 extern unsigned long __cdecl DbgPrint(const char * format, ...);
38
39 #define _SEH_TRACE_HEADER_(FRAME_) \
40 DbgPrint("[PSEH:%p]%s:%d:", FRAME_, __FILE__, __LINE__);
41
42 #define _SEH_TRACE_TRAILER_ \
43 DbgPrint("\n");
44
45 #define _SEH_FILTER_RET_STRING_(RET_) \
46 (((int)(RET_) < 0) ? "_SEH_CONTINUE_EXECUTION" : (((int)(RET_) > 0) ? "_SEH_EXECUTE_HANDLER" : "_SEH_CONTINUE_SEARCH"))
47
48 #define _SEH_TRACE_LINE_(FRAME_, ARGS_) \
49 { \
50 _SEH_TRACE_HEADER_(FRAME_); \
51 DbgPrint ARGS_; \
52 _SEH_TRACE_TRAILER_; \
53 }
54
55 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_) \
56 { \
57 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
58 { \
59 _SEH_TRACE_HEADER_(FRAME_); \
60 DbgPrint(">>> %s(", (FUNCNAME_)); \
61 DbgPrint ARGS_; \
62 DbgPrint(")"); \
63 _SEH_TRACE_TRAILER_; \
64 } \
65 }
66
67 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_) \
68 { \
69 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_ENTER_LEAVE) \
70 { \
71 _SEH_TRACE_HEADER_(FRAME_); \
72 DbgPrint("<<< %s => ", (FUNCNAME_)); \
73 DbgPrint ARGS_; \
74 _SEH_TRACE_TRAILER_; \
75 } \
76 }
77
78 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_) \
79 { \
80 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_EXCEPTION_RECORD) \
81 { \
82 _SEH_TRACE_LINE_ \
83 ( \
84 (FRAME_), \
85 ( \
86 "ExceptionRecord %p = { ExceptionCode : %08X, ExceptionFlags : %08X, ExceptionRecord : %p, ExceptionAddress : %p }", \
87 (ER_), \
88 (ER_)->ExceptionCode, \
89 (ER_)->ExceptionFlags, \
90 (ER_)->ExceptionRecord, \
91 (ER_)->ExceptionAddress \
92 ) \
93 ); \
94 } \
95 }
96
97 #ifdef _X86_
98 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_) \
99 { \
100 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CONTEXT) \
101 { \
102 if(((CONTEXT_)->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) \
103 { \
104 _SEH_TRACE_LINE_ \
105 ( \
106 (FRAME_), \
107 ( \
108 "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X", \
109 (CONTEXT_)->Eax, \
110 (CONTEXT_)->Ebx, \
111 (CONTEXT_)->Ecx, \
112 (CONTEXT_)->Edx, \
113 (CONTEXT_)->Esi, \
114 (CONTEXT_)->Edi \
115 ) \
116 ); \
117 } \
118 \
119 if(((CONTEXT_)->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) \
120 { \
121 _SEH_TRACE_LINE_ \
122 ( \
123 (FRAME_), \
124 ( \
125 "eip=%08X esp=%08X ebp=%08X efl=%08X cs=%08X ss=%08X", \
126 (CONTEXT_)->Eip, \
127 (CONTEXT_)->Esp, \
128 (CONTEXT_)->Ebp, \
129 (CONTEXT_)->EFlags, \
130 (CONTEXT_)->SegCs, \
131 (CONTEXT_)->SegSs \
132 ) \
133 ); \
134 } \
135 \
136 if(((CONTEXT_)->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) \
137 { \
138 _SEH_TRACE_LINE_ \
139 ( \
140 (FRAME_), \
141 ( \
142 "ds=%08X es=%08X fs=%08X gs=%08X", \
143 (CONTEXT_)->SegDs, \
144 (CONTEXT_)->SegEs, \
145 (CONTEXT_)->SegFs, \
146 (CONTEXT_)->SegGs \
147 ) \
148 ); \
149 } \
150 } \
151 }
152 #else
153 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
154 #endif
155
156 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_) \
157 { \
158 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_UNWIND) \
159 { \
160 _SEH_TRACE_LINE_((FRAME_), ARGS_); \
161 } \
162 }
163
164 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_) \
165 { \
166 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_TRYLEVEL) \
167 { \
168 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, filter %p", (TRYLEVEL_), (TRYLEVEL_)->SPT_Handlers.SH_Filter)); \
169 } \
170 }
171
172 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_) \
173 { \
174 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
175 { \
176 _SEH_TRACE_LINE_ \
177 ( \
178 (FRAME_), \
179 ( \
180 "trylevel %p, calling filter %p, ExceptionCode %08X", \
181 (TRYLEVEL_), \
182 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
183 (ER_)->ExceptionCode \
184 ) \
185 ); \
186 } \
187 }
188
189 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_) \
190 { \
191 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FILTER) \
192 { \
193 _SEH_TRACE_LINE_ \
194 ( \
195 (FRAME_), \
196 ( \
197 "trylevel %p, filter %p => %s", \
198 (TRYLEVEL_), \
199 (TRYLEVEL_)->SPT_Handlers.SH_Filter, \
200 _SEH_FILTER_RET_STRING_(RET_) \
201 ) \
202 ); \
203 } \
204 }
205
206 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_) \
207 { \
208 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_FILTER) \
209 { \
210 _SEH_TRACE_LINE_ \
211 ( \
212 (FRAME_), \
213 ( \
214 "trylevel %p => %s", \
215 (TRYLEVEL_), \
216 _SEH_FILTER_RET_STRING_(RET_) \
217 ) \
218 ); \
219 } \
220 }
221
222 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_) \
223 { \
224 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_HANDLER) \
225 { \
226 _SEH_TRACE_LINE_((FRAME_), ("trylevel %p, handling", (TRYLEVEL_))); \
227 } \
228 }
229
230 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_) \
231 { \
232 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
233 { \
234 _SEH_TRACE_LINE_ \
235 ( \
236 (FRAME_), \
237 ( \
238 "trylevel %p, calling exit routine %p", \
239 (TRYLEVEL_), \
240 (TRYLEVEL_)->SPT_Handlers.SH_Finally \
241 ) \
242 ); \
243 } \
244 }
245
246 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_) \
247 { \
248 if((FRAME_)->SPF_Tracing & _SEH_DO_TRACE_CALL_FINALLY) \
249 { \
250 _SEH_TRACE_LINE_ \
251 ( \
252 (FRAME_), \
253 ( \
254 "trylevel %p, exit routine %p returned", \
255 (TRYLEVEL_), \
256 (TRYLEVEL_)->SPT_Handlers.SH_Finally \
257 ) \
258 ); \
259 } \
260 }
261
262 #else
263 #define _SEH_TRACE_ENTER(FRAME_, FUNCNAME_, ARGS_)
264 #define _SEH_TRACE_LEAVE(FRAME_, FUNCNAME_, ARGS_)
265 #define _SEH_TRACE_EXCEPTION_RECORD(FRAME_, ER_)
266 #define _SEH_TRACE_CONTEXT(FRAME_, CONTEXT_)
267 #define _SEH_TRACE_UNWIND(FRAME_, ARGS_)
268 #define _SEH_TRACE_TRYLEVEL(FRAME_, TRYLEVEL_)
269 #define _SEH_TRACE_ENTER_CALL_FILTER(FRAME_, TRYLEVEL_, ER_)
270 #define _SEH_TRACE_LEAVE_CALL_FILTER(FRAME_, TRYLEVEL_, RET_)
271 #define _SEH_TRACE_FILTER(FRAME_, TRYLEVEL_, RET_)
272 #define _SEH_TRACE_ENTER_CALL_HANDLER(FRAME_, TRYLEVEL_)
273 #define _SEH_TRACE_ENTER_CALL_FINALLY(FRAME_, TRYLEVEL_)
274 #define _SEH_TRACE_LEAVE_CALL_FINALLY(FRAME_, TRYLEVEL_)
275 #endif
276
277 /* Assembly helpers, see i386/framebased.asm */
278 extern void __cdecl _SEHCleanHandlerEnvironment(void);
279 extern struct __SEHRegistration * __cdecl _SEHRegisterFrame(_SEHRegistration_t *);
280 extern void __cdecl _SEHUnregisterFrame(void);
281 extern void __cdecl _SEHGlobalUnwind(_SEHPortableFrame_t *);
282 extern _SEHRegistration_t * __cdecl _SEHCurrentRegistration(void);
283
_SEHLocalUnwind(_SEHPortableFrame_t * frame,_SEHPortableTryLevel_t * dsttrylevel)284 static void __stdcall _SEHLocalUnwind
285 (
286 _SEHPortableFrame_t * frame,
287 _SEHPortableTryLevel_t * dsttrylevel
288 )
289 {
290 _SEHPortableTryLevel_t * trylevel;
291
292 _SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
293
294 for
295 (
296 trylevel = frame->SPF_TopTryLevel;
297 trylevel != dsttrylevel;
298 trylevel = trylevel->SPT_Next
299 )
300 {
301 _SEHFinally_t pfnFinally;
302
303 /* ASSERT(trylevel); */
304
305 pfnFinally = trylevel->SPT_Handlers.SH_Finally;
306
307 if(pfnFinally)
308 {
309 _SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel);
310 pfnFinally(frame);
311 _SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel);
312 }
313 }
314
315 _SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
316 }
317
_SEHCallHandler(_SEHPortableFrame_t * frame,_SEHPortableTryLevel_t * trylevel)318 static void __cdecl _SEHCallHandler
319 (
320 _SEHPortableFrame_t * frame,
321 _SEHPortableTryLevel_t * trylevel
322 )
323 {
324 _SEHGlobalUnwind(frame);
325 _SEHLocalUnwind(frame, trylevel);
326 _SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel);
327 frame->SPF_Handler(trylevel);
328 /* ASSERT(0); */
329 }
330
_SEHFrameHandler(struct _EXCEPTION_RECORD * ExceptionRecord,void * EstablisherFrame,struct _CONTEXT * ContextRecord,void * DispatcherContext)331 static int __cdecl _SEHFrameHandler
332 (
333 struct _EXCEPTION_RECORD * ExceptionRecord,
334 void * EstablisherFrame,
335 struct _CONTEXT * ContextRecord,
336 void * DispatcherContext
337 )
338 {
339 _SEHPortableFrame_t * frame;
340
341 _SEHCleanHandlerEnvironment();
342
343 frame = EstablisherFrame;
344
345 _SEH_TRACE_ENTER
346 (
347 frame,
348 "_SEHFrameHandler",
349 (
350 "%p, %p, %p, %p",
351 ExceptionRecord,
352 EstablisherFrame,
353 ContextRecord,
354 DispatcherContext
355 )
356 );
357
358 _SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord);
359 _SEH_TRACE_CONTEXT(frame, ContextRecord);
360
361 /* Unwinding */
362 if(ExceptionRecord->ExceptionFlags & (4 | 2))
363 {
364 _SEH_TRACE_UNWIND(frame, ("enter forced unwind"));
365 _SEHLocalUnwind(frame, NULL);
366 _SEH_TRACE_UNWIND(frame, ("leave forced unwind"));
367 }
368 /* Handling */
369 else
370 {
371 int ret;
372 _SEHPortableTryLevel_t * trylevel;
373
374 if(ExceptionRecord->ExceptionCode)
375 frame->SPF_Code = ExceptionRecord->ExceptionCode;
376 else
377 frame->SPF_Code = 0xC0000001;
378
379 for
380 (
381 trylevel = frame->SPF_TopTryLevel;
382 trylevel != NULL;
383 trylevel = trylevel->SPT_Next
384 )
385 {
386 _SEHFilter_t pfnFilter = trylevel->SPT_Handlers.SH_Filter;
387
388 _SEH_TRACE_TRYLEVEL(frame, trylevel);
389
390 switch((UINT_PTR)pfnFilter)
391 {
392 case __SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER):
393 case __SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH):
394 case __SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION):
395 {
396 ret = (int)((UINT_PTR)pfnFilter) - 2;
397 break;
398 }
399
400 default:
401 {
402 if(trylevel->SPT_Handlers.SH_Filter)
403 {
404 EXCEPTION_POINTERS ep;
405
406 ep.ExceptionRecord = ExceptionRecord;
407 ep.ContextRecord = ContextRecord;
408
409 _SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord);
410 ret = pfnFilter(&ep, frame);
411 _SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret);
412 }
413 else
414 ret = _SEH_CONTINUE_SEARCH;
415
416 break;
417 }
418 }
419
420 _SEH_TRACE_FILTER(frame, trylevel, ret);
421
422 /* _SEH_CONTINUE_EXECUTION */
423 if(ret < 0)
424 {
425 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution"));
426 return ExceptionContinueExecution;
427 }
428 /* _SEH_EXECUTE_HANDLER */
429 else if(ret > 0)
430 _SEHCallHandler(frame, trylevel);
431 /* _SEH_CONTINUE_SEARCH */
432 else
433 continue;
434 }
435
436 /* FALLTHROUGH */
437 }
438
439 _SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch"));
440 return ExceptionContinueSearch;
441 }
442
_SEHEnterFrame_s(_SEHPortableFrame_t * frame)443 void __stdcall _SEHEnterFrame_s(_SEHPortableFrame_t * frame)
444 {
445 _SEHEnterFrame_f(frame);
446 }
447
_SEHLeaveFrame_s(void)448 void __stdcall _SEHLeaveFrame_s(void)
449 {
450 _SEHLeaveFrame_f();
451 }
452
_SEHReturn_s(void)453 void __stdcall _SEHReturn_s(void)
454 {
455 _SEHReturn_f();
456 }
457
_SEHEnterFrame_f(_SEHPortableFrame_t * frame)458 void _SEH_FASTCALL _SEHEnterFrame_f(_SEHPortableFrame_t * frame)
459 {
460 /* ASSERT(frame); */
461 /* ASSERT(trylevel); */
462 frame->SPF_Registration.SER_Handler = _SEHFrameHandler;
463 frame->SPF_Code = 0;
464 _SEHRegisterFrame(&frame->SPF_Registration);
465 }
466
_SEHLeaveFrame_f(void)467 void _SEH_FASTCALL _SEHLeaveFrame_f(void)
468 {
469 _SEHPortableFrame_t * frame;
470
471 frame = _SEH_CONTAINING_RECORD
472 (
473 _SEHCurrentRegistration(),
474 _SEHPortableFrame_t,
475 SPF_Registration
476 );
477
478 /* ASSERT(frame); */
479 /* ASSERT(frame->SPF_TopTryLevel == NULL) */
480
481 _SEHUnregisterFrame();
482 }
483
_SEHReturn_f(void)484 void _SEH_FASTCALL _SEHReturn_f(void)
485 {
486 _SEHPortableFrame_t * frame;
487
488 frame = _SEH_CONTAINING_RECORD
489 (
490 _SEHCurrentRegistration(),
491 _SEHPortableFrame_t,
492 SPF_Registration
493 );
494
495 _SEHLocalUnwind(frame, NULL);
496 _SEHUnregisterFrame();
497 }
498
499 /* EOF */
500