xref: /reactos/sdk/lib/pseh/framebased.c (revision 40462c92)
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 
284 /* Borland C++ uses a different decoration (i.e. none) for stdcall functions */
285 extern void __stdcall RtlUnwind(void *, void *, PEXCEPTION_RECORD, void *);
286 void const * _SEHRtlUnwind = RtlUnwind;
287 
288 static void __stdcall _SEHLocalUnwind
289 (
290 	_SEHPortableFrame_t * frame,
291 	_SEHPortableTryLevel_t * dsttrylevel
292 )
293 {
294 	_SEHPortableTryLevel_t * trylevel;
295 
296 	_SEH_TRACE_UNWIND(frame, ("enter local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
297 
298 	for
299 	(
300 		trylevel = frame->SPF_TopTryLevel;
301 		trylevel != dsttrylevel;
302 		trylevel = trylevel->SPT_Next
303 	)
304 	{
305 		_SEHFinally_t pfnFinally;
306 
307 		/* ASSERT(trylevel); */
308 
309 		pfnFinally = trylevel->SPT_Handlers.SH_Finally;
310 
311 		if(pfnFinally)
312 		{
313 			_SEH_TRACE_ENTER_CALL_FINALLY(frame, trylevel);
314 			pfnFinally(frame);
315 			_SEH_TRACE_LEAVE_CALL_FINALLY(frame, trylevel);
316 		}
317 	}
318 
319 	_SEH_TRACE_UNWIND(frame, ("leave local unwind from %p to %p", frame->SPF_TopTryLevel, dsttrylevel));
320 }
321 
322 static void __cdecl _SEHCallHandler
323 (
324 	_SEHPortableFrame_t * frame,
325 	_SEHPortableTryLevel_t * trylevel
326 )
327 {
328 	_SEHGlobalUnwind(frame);
329 	_SEHLocalUnwind(frame, trylevel);
330 	_SEH_TRACE_ENTER_CALL_HANDLER(frame, trylevel);
331 	frame->SPF_Handler(trylevel);
332 	/* ASSERT(0); */
333 }
334 
335 static int __cdecl _SEHFrameHandler
336 (
337 	struct _EXCEPTION_RECORD * ExceptionRecord,
338 	void * EstablisherFrame,
339 	struct _CONTEXT * ContextRecord,
340 	void * DispatcherContext
341 )
342 {
343 	_SEHPortableFrame_t * frame;
344 
345 	_SEHCleanHandlerEnvironment();
346 
347 	frame = EstablisherFrame;
348 
349 	_SEH_TRACE_ENTER
350 	(
351 		frame,
352 		"_SEHFrameHandler",
353 		(
354 			"%p, %p, %p, %p",
355 			ExceptionRecord,
356 			EstablisherFrame,
357 			ContextRecord,
358 			DispatcherContext
359 		)
360 	);
361 
362 	_SEH_TRACE_EXCEPTION_RECORD(frame, ExceptionRecord);
363 	_SEH_TRACE_CONTEXT(frame, ContextRecord);
364 
365 	/* Unwinding */
366 	if(ExceptionRecord->ExceptionFlags & (4 | 2))
367 	{
368 		_SEH_TRACE_UNWIND(frame, ("enter forced unwind"));
369 		_SEHLocalUnwind(frame, NULL);
370 		_SEH_TRACE_UNWIND(frame, ("leave forced unwind"));
371 	}
372 	/* Handling */
373 	else
374 	{
375 		int ret;
376 		_SEHPortableTryLevel_t * trylevel;
377 
378 		if(ExceptionRecord->ExceptionCode)
379 			frame->SPF_Code = ExceptionRecord->ExceptionCode;
380 		else
381 			frame->SPF_Code = 0xC0000001;
382 
383 		for
384 		(
385 			trylevel = frame->SPF_TopTryLevel;
386 			trylevel != NULL;
387 			trylevel = trylevel->SPT_Next
388 		)
389 		{
390 			_SEHFilter_t pfnFilter = trylevel->SPT_Handlers.SH_Filter;
391 
392 			_SEH_TRACE_TRYLEVEL(frame, trylevel);
393 
394 			switch((UINT_PTR)pfnFilter)
395 			{
396 				case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER):
397 				case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH):
398 				case (UINT_PTR)_SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION):
399 				{
400 					ret = (int)((UINT_PTR)pfnFilter) - 2;
401 					break;
402 				}
403 
404 				default:
405 				{
406 					if(trylevel->SPT_Handlers.SH_Filter)
407 					{
408 						EXCEPTION_POINTERS ep;
409 
410 						ep.ExceptionRecord = ExceptionRecord;
411 						ep.ContextRecord = ContextRecord;
412 
413 						_SEH_TRACE_ENTER_CALL_FILTER(frame, trylevel, ExceptionRecord);
414 						ret = pfnFilter(&ep, frame);
415 						_SEH_TRACE_LEAVE_CALL_FILTER(frame, trylevel, ret);
416 					}
417 					else
418 						ret = _SEH_CONTINUE_SEARCH;
419 
420 					break;
421 				}
422 			}
423 
424 			_SEH_TRACE_FILTER(frame, trylevel, ret);
425 
426 			/* _SEH_CONTINUE_EXECUTION */
427 			if(ret < 0)
428 			{
429 				_SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueExecution"));
430 				return ExceptionContinueExecution;
431 			}
432 			/* _SEH_EXECUTE_HANDLER */
433 			else if(ret > 0)
434 				_SEHCallHandler(frame, trylevel);
435 			/* _SEH_CONTINUE_SEARCH */
436 			else
437 				continue;
438 		}
439 
440 		/* FALLTHROUGH */
441 	}
442 
443 	_SEH_TRACE_LEAVE(frame, "_SEHFrameHandler", ("ExceptionContinueSearch"));
444 	return ExceptionContinueSearch;
445 }
446 
447 void __stdcall _SEHEnterFrame_s(_SEHPortableFrame_t * frame)
448 {
449 	_SEHEnterFrame_f(frame);
450 }
451 
452 void __stdcall _SEHLeaveFrame_s(void)
453 {
454 	_SEHLeaveFrame_f();
455 }
456 
457 void __stdcall _SEHReturn_s(void)
458 {
459 	_SEHReturn_f();
460 }
461 
462 void _SEH_FASTCALL _SEHEnterFrame_f(_SEHPortableFrame_t * frame)
463 {
464 	/* ASSERT(frame); */
465 	/* ASSERT(trylevel); */
466 	frame->SPF_Registration.SER_Handler = _SEHFrameHandler;
467 	frame->SPF_Code = 0;
468 	_SEHRegisterFrame(&frame->SPF_Registration);
469 }
470 
471 void _SEH_FASTCALL _SEHLeaveFrame_f(void)
472 {
473 	/* _SEHPortableFrame_t * frame;
474 
475 	frame = _SEH_CONTAINING_RECORD
476 	(
477 		_SEHCurrentRegistration(),
478 		_SEHPortableFrame_t,
479 		SPF_Registration
480 	); */
481 
482 	/* ASSERT(frame); */
483 	/* ASSERT(frame->SPF_TopTryLevel == NULL) */
484 
485 	_SEHUnregisterFrame();
486 }
487 
488 void _SEH_FASTCALL _SEHReturn_f(void)
489 {
490 	_SEHPortableFrame_t * frame;
491 
492 	frame = _SEH_CONTAINING_RECORD
493 	(
494 		_SEHCurrentRegistration(),
495 		_SEHPortableFrame_t,
496 		SPF_Registration
497 	);
498 
499 	_SEHLocalUnwind(frame, NULL);
500 	_SEHUnregisterFrame();
501 }
502 
503 /* EOF */
504