[ros-kernel] Macro SEH support, version 2 (Help needed: translating to AT&T assembler syntax)

Vizzini vizzini at plasmic.com
Sun Nov 2 00:07:49 CET 2003


I think it is really critical to get some exception handling implemented
in our system call handlers.  At this point, it's trivial to crash the 
whole operating system with a misbehaving user-mode app.  This macro
system, while not optimal, will tide us over until the MinGW
exception-handling work is complete.

Are there any assembler people out there who need a weekend project? 
This isn't terribly long, but it does need somebody who knows what
they're doing.  If you've been lurking for a while waiting to find
something you can contribute, this might just be the ticket!  Mail the
list or me directly if you're interested and I'll point you in the right
direction.

Nice work, Skywing.

 -Vizzini

On Mon, 2003-10-27 at 10:16, Skywing wrote:
> I've done a significant amount of reworking on the macro SEH support that I
> introduced on the mailinglist some time ago.  It now passes every test I can
> throw at it with flying colors, including interoperating with VC-style SEH.
> This includes unwinding and nested exception handlers.  This release fixes a
> number of bugs with the original implementation.
> 
> Request for help:  I don't know AT&T assembler, so somebody needs to port
> this if it's to be used with MinGW (which is the primary purpose for me
> writing it).  Unless somebody is willing to lend a hand with GNU-ASM'ing it,
> this will probably not benefit the ReactOS project much.
> 
> I've tried to code this as defensively as possible, so that any code in the
> handler or filter areas will properly run without any special knowledge
> about the values of the stack/other registers while in an exception handler.
> I'm pretty sure that the macros are virtually bulletproof against the
> compiler generating code that doesn't work inside of them, provided you
> follow these rules: Enable frame pointer generation.  This is absolutely
> crucial to any SEH implementation; without frame pointers, the macros will
> fall over and die. Preferably, exit the SEH exception handler with
> fallthrough.  If you must exit it otherwise, you can try using the
> ExceptCleanup() macro before leaving the handler with a return or similar
> statement.  Exiting the SEH handler inside the filter expression is probably
> a Bad Idea and may not work, as the "panic stack" will be used through the
> remainder of the function.
> 
> Additionally, GetExceptionCode() and GetExceptionPointers() should be
> available at the proper scopes.  You ought to get an undefined identifier
> error if you try to use them elsewhere.
> 
> The macros work with "heap-based" SEH in order to work around the Borland
> patent.  There are some limitations with using this with regular Microsoft
> Windows (see below), but it should be no problem to modify ReactOS to work
> with this scheme if necessary.
> 
> The semantics for using the macros are as follows:
> TRY
> {
>   try-protected-code;
> }
> EXCEPT(( filter-expression )) /* Note that double parens are needed */ {
> handler-code; } EXCEPT_END();
> 
> Issues with "heap-based" SEH:
> The default Microsoft RtlUnwind implementation will not call an exception
> handler if the exception registration is not within the threads stack
> limits.  It would be a good idea to ensure that the ReactOS RtlUnwind
> implementation does not have this limitation if we wish to use "heap-based"
> SEH and not "stack-based" SEH.
> 
> Issues with the macros and MSVC++:
> The VC compiler crashes if you use if(0) { code; } or goto label; { code; }
> label: instead of __asm jmp label; { code; } label; to prevent the exception
> handler from being executed by fallthrough.  I think that this is because
> the optimizer decides that the exception handler is unreachable and removes
> it, despite an existing reference to code in the handler (the label for the
> start of the OS-invoked SEH handler function itself).  Later this causes the
> compiler to crash, hence my workaround with __asm jmp EXCEPT_EndOfExcept.
> 
> ----- Macro definitions follow -----
> 
> #define ExceptCleanup() { \
> 	ExFreePool(EXCEPT_ExceptionPointers); \
> 	__asm { \
> 	__asm push		eax \
> 	__asm mov		eax, dword ptr fs:[0x00000000] \
> 	__asm mov		eax, dword ptr [eax] \
> 	__asm mov		dword ptr fs:[0x00000000], eax \
> 	__asm pop		eax \
> 	} \
> }
> #define GetExceptionCode() ((DWORD)(EXCEPT_ExceptionCode))
> #define GetExceptionPointers()
> ((PEXCEPTION_POINTERS)(&EXCEPT_ExceptionPointers))
> 
> #define EH_NONCONTINUABLE	0x00000001
> #define EH_UNWINDING		0x00000002
> #define EH_EXIT_UNWIND		0x00000004
> #define EH_STACK_INVALID	0x00000008
> #define EH_NESTED_CALL		0x00000010
> #define EH_UNWIND_CONTEXT	EH_UNWINDING | EH_EXIT_UNWIND
> 
> #define _TRY_SAVED_EBP		0x08
> #define _TRY_SAVED_EBX		0x0c
> #define _TRY_SAVED_ESI		0x10
> #define _TRY_SAVED_EDI		0x14
> #define _TRY_SAVED_ESP		0x18
> 
> #if 0 // Enable if you don't have these in scope
> typedef enum {
> 	ExceptionContinueExecution,
> 	ExceptionContinueSearch,
> 	ExceptionNestedException,
> 	ExceptionCollidedUnwind
> } EXCEPTION_DISPOSITION;
> #endif
> 
> #define TRY { \
> 	PVOID TRY_ExceptionRegistration = ExAllocatePoolWithTag(PagedPool,
> 28, ' HES'); \
> 	volatile DWORD EXCEPT_ExceptionCode; \
> 	__asm { \
> 		__asm push		eax \
> 		__asm push		ecx \
> 		__asm mov		eax, TRY_ExceptionRegistration \
> 		__asm mov		ecx, dword ptr fs:[0] \
> 		__asm mov		dword ptr [eax+0x00], ecx \
> 		__asm mov		dword ptr fs:[0], eax \
> 		__asm lea		ecx, EXCEPT_Handler \
> 		__asm mov		dword ptr [eax+0x04], ecx \
> 		__asm mov		dword ptr [eax+_TRY_SAVED_EBP], ebp
> \
> 		__asm mov		dword ptr [eax+_TRY_SAVED_EBX], ebx
> \
> 		__asm mov		dword ptr [eax+_TRY_SAVED_ESI], esi
> \
> 		__asm mov		dword ptr [eax+_TRY_SAVED_EDI], edi
> \
> 		__asm mov		dword ptr [eax+_TRY_SAVED_ESP], esp
> \
> 		__asm add		dword ptr [eax+_TRY_SAVED_ESP], 0x08
> \
> 		__asm pop		ecx \
> 		__asm pop		eax \
> 	}
> 
> #define EXCEPT_LOCALS TYPE CONTEXT + 20
> #define EXCEPT_CONTEXT_OFFSET 0
> #define EXCEPT_POINTERS_OFFSET TYPE CONTEXT
> 
> 
> #ifdef _MSC_VER
> #pragma comment(linker, "/INCLUDE:_RtlUnwind at 16")
> #endif
> 
> #if 0 // Enable if not in scope
> // RtlUnwind unwinds procedure call stack frames.
> extern "C"
> NTSYSAPI
> VOID
> NTAPI
> RtlUnwind(
> 	IN OUT PVOID TargetFrame OPTIONAL,
> 	IN PVOID TargetIp OPTIONAL,
> 	IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
> 	IN PVOID ReturnValue
> 	);
> #endif
> 
> #define EXCEPT(Expression) { __asm { jmp EXCEPT_EndOfExcept} \
> 	volatile EXCEPTION_POINTERS EXCEPT_ExceptionPointers; \
> 	EXCEPT_Handler: /* EXCEPTION_DISPOSITION __cdecl
> handler(EXCEPTION_RECORD* ExceptionRecord, void* EstablisherFrame, CONTEXT*
> ContextRecord, void* DispatcherContext) */ \
> 	__asm { \
> 		__asm mov		eax, dword ptr [esp+0x04] \
> 		__asm test		dword ptr
> [eax]EXCEPTION_RECORD.ExceptionFlags, EH_UNWIND_CONTEXT | EH_NESTED_CALL \
> 		__asm je		EXCEPT_DoHandler \
> \
> 		__asm xor		eax, eax \
> 		__asm or		eax, ExceptionContinueSearch \
> 		__asm ret \
> 	} \
> 	EXCEPT_DoHandler: /* Can't define this in inline asm macro + __asm{}
> block, or compiler complains. */ \
> 	__asm { \
> 		__asm sub		esp, EXCEPT_LOCALS \
> 		__asm mov		[esp]CONTEXT.Ebp, ebp \
> 		__asm mov		[esp]CONTEXT.Ebx, ebx \
> 		__asm mov		[esp]CONTEXT.Edi, edi \
> 		__asm mov		[esp]CONTEXT.Esi, esi \
> 		__asm pushfd \
> 		__asm pop		ecx \
> 		__asm mov		[esp]CONTEXT.EFlags, ecx \
> 		__asm mov		ebp, dword ptr
> [esp+0x08+EXCEPT_LOCALS] \
> 		__asm mov		ebp, dword ptr [ebp+0x08] \
> 		__asm lea		edx, EXCEPT_ExceptionPointers \
> 		__asm mov		ecx, dword ptr
> [esp+0x04+EXCEPT_LOCALS] \
> 		__asm mov
> [edx]EXCEPTION_POINTERS.ExceptionRecord, ecx \
> 		__asm mov		ecx, dword ptr
> [esp+0x0c+EXCEPT_LOCALS] \
> 		__asm mov
> [edx]EXCEPTION_POINTERS.ContextRecord, ecx \
> 		__asm mov		edx,
> [edx]EXCEPTION_POINTERS.ExceptionRecord \
> 		__asm mov		edx,
> [edx]EXCEPTION_RECORD.ExceptionCode \
> 		__asm mov		EXCEPT_ExceptionCode, edx \
> 		__asm mov		ebp, dword ptr
> [esp+0x0c+EXCEPT_LOCALS] \
> 		__asm mov		eax, [ebp]CONTEXT.EFlags \
> 		__asm push		eax \
> 		__asm popfd	\
> 		__asm mov		ebp, dword ptr
> [esp+0x08+EXCEPT_LOCALS] \
> 		__asm mov		ebx, dword ptr [ebp+_TRY_SAVED_EBX]
> \
> 		__asm mov		esi, dword ptr [ebp+_TRY_SAVED_ESI]
> \
> 		__asm mov		edi, dword ptr [ebp+_TRY_SAVED_EDI]
> \
> 		__asm mov		ebp, dword ptr [ebp+_TRY_SAVED_EBP]
> \
> 		__asm cld \
> 	} \
> \
> 	switch( (Expression) ) { \
> \
> 	case EXCEPTION_CONTINUE_SEARCH: \
> 		ExFreePool(TRY_ExceptionRegistration); \
> 		__asm { \
> 			__asm mov		ebp, [esp]CONTEXT.Ebp \
> 			__asm mov		ebx, [esp]CONTEXT.Ebx \
> 			__asm mov		edi, [esp]CONTEXT.Edi \
> 			__asm mov		esi, [esp]CONTEXT.Esi \
> 			__asm add		esp, EXCEPT_LOCALS \
> 			__asm xor		eax, eax \
> 			__asm or		eax, ExceptionContinueSearch
> \
> 			__asm ret \
> 		} \
> \
> 	case EXCEPTION_CONTINUE_EXECUTION: \
> 		ExFreePool(TRY_ExceptionRegistration); \
> 		__asm { \
> 			__asm mov		eax, dword ptr
> [esp+0x08+EXCEPT_LOCALS] \
> 			__asm push		0 \
> 			__asm push		0 \
> 			__asm push
> __ret_label_CONTINUE_EXECUTION \
> 			__asm push		eax \
> 			__asm call		dword ptr [RtlUnwind] \
> 		} \
> 		__ret_label_CONTINUE_EXECUTION: \
> 		__asm { \
> 			__asm mov		ebp, [esp]CONTEXT.Ebp \
> 			__asm mov		ebx, [esp]CONTEXT.Ebx \
> 			__asm mov		edi, [esp]CONTEXT.Edi \
> 			__asm mov		esi, [esp]CONTEXT.Esi \
> 			__asm add		esp, EXCEPT_LOCALS \
> 			__asm xor		eax, eax \
> 			__asm or		eax,
> ExceptionContinueExecution \
> 			__asm ret \
> 		} \
> \
> 	case EXCEPTION_EXECUTE_HANDLER: \
> 		__asm { \
> 			__asm pushad \
> 			__asm pushfd \
> 			__asm mov		eax, dword ptr
> [esp+0x08+0x04+0x20+EXCEPT_LOCALS] \
> 			__asm push		0 \
> 			__asm push		0 \
> 			__asm push		__ret_label_EXECUTE_HANDLER
> \
> 			__asm push		eax \
> 			__asm call		dword ptr [RtlUnwind] \
> 		} \
> 		__ret_label_EXECUTE_HANDLER: \
> 		 __asm { \
> 			__asm popfd \
> 			__asm popad \
> 		} \
> 		break; \
> \
> 	default: \
> 		DPRINT("SEH: Invalid disposition returned from filter
> expression!\n"); \
> 		RtlRaiseStatus(STATUS_INVALID_DISPOSITION); \
> \
> 	} \
> \
> 	__asm { \
> 		__asm mov		ebp, dword ptr
> [esp+0x08+EXCEPT_LOCALS] \
> 		__asm mov		ebx, dword ptr [ebp+_TRY_SAVED_EBX]
> \
> 		__asm mov		esi, dword ptr [ebp+_TRY_SAVED_ESI]
> \
> 		__asm mov		edi, dword ptr [ebp+_TRY_SAVED_EDI]
> \
> 		__asm mov		esp, dword ptr [ebp+_TRY_SAVED_ESP]
> \
> 		__asm mov		ebp, dword ptr [ebp+0x08] \
> 	} }
> 
> -- End --
> 
> 
> _______________________________________________
> Ros-kernel mailing list
> Ros-kernel at reactos.com
> http://reactos.geldorp.nl:8080/mailman/listinfo/ros-kernel
> 



More information about the Ros-kernel mailing list