• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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