[ros-kernel] Macro SEH support, version 2 (Help needed: translating to AT&T assembler syntax)
Steven Edwards
steven_ed4153 at yahoo.com
Mon Oct 27 10:57:15 CST 2003
Hello Skywing,
I have forwarded your request to wine-devel also in the event your SEH
implementation might help them.
Thanks
Steven
--- Skywing <skywing at valhallalegends.com> 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.
>
__________________________________
Do you Yahoo!?
Exclusive Video Premiere - Britney Spears
http://launch.yahoo.com/promos/britneyspears/
-------------- next part --------------
#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] \
} }
More information about the wine-devel
mailing list