Author: tkreuzer Date: Sun Sep 9 21:12:00 2012 New Revision: 57259
URL: http://svn.reactos.org/svn/reactos?rev=57259&view=rev Log: [PSEH3] Implement PSEH 3.0. Currently disabled by default. Dedicated to Amine Khaldi.
Added: trunk/reactos/include/reactos/libs/pseh/pseh3.h (with props) trunk/reactos/lib/pseh/i386/pseh3.c (with props) trunk/reactos/lib/pseh/i386/pseh3_asmdef.h (with props) trunk/reactos/lib/pseh/i386/pseh3_i386.S (with props) Modified: trunk/reactos/CMakeLists.txt trunk/reactos/cmake/config.cmake trunk/reactos/include/reactos/libs/pseh/pseh2.h trunk/reactos/lib/pseh/CMakeLists.txt
Modified: trunk/reactos/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/CMakeLists.txt?rev=57259&am... ============================================================================== --- trunk/reactos/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/CMakeLists.txt [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -120,6 +120,10 @@
if(_WINKD_) add_definitions(-D_WINKD_=1) + endif() + + if(USE_PSEH3) + add_definitions(-D_USE_PSEH3=1) endif()
# Version Options
Modified: trunk/reactos/cmake/config.cmake URL: http://svn.reactos.org/svn/reactos/trunk/reactos/cmake/config.cmake?rev=5725... ============================================================================== --- trunk/reactos/cmake/config.cmake [iso-8859-1] (original) +++ trunk/reactos/cmake/config.cmake [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -44,7 +44,7 @@ else() set(_WINKD_ TRUE CACHE BOOL "Whether to compile with the KD protocol.") endif() - + else() set(KDBG TRUE CACHE BOOL "Whether to compile in the integrated kernel debugger.") @@ -75,4 +75,9 @@ set(_VS_ANALYZE_ FALSE CACHE BOOL "Whether to enable static analysis while compiling.")
+else() + +set(USE_PSEH3 FALSE CACHE BOOL +"Whether to use the new PSEH3 library (requires GCC 4.5 and newer).") + endif()
Modified: trunk/reactos/include/reactos/libs/pseh/pseh2.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/pseh/p... ============================================================================== --- trunk/reactos/include/reactos/libs/pseh/pseh2.h [iso-8859-1] (original) +++ trunk/reactos/include/reactos/libs/pseh/pseh2.h [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -23,7 +23,7 @@ #ifndef KJK_PSEH2_H_ #define KJK_PSEH2_H_
-#if defined(USE_NATIVE_SEH) || defined(_MSC_VER) +#if defined(_USE_NATIVE_SEH) || defined(_MSC_VER)
#include <excpt.h> #define _SEH2_TRY __try @@ -36,7 +36,7 @@ #define _SEH2_YIELD(STMT_) STMT_ #define _SEH2_LEAVE __leave
-#elif defined(USE_DUMMY_PSEH) || defined (__arm__) || defined(__clang__) || defined(_M_AMD64) +#elif defined(_USE_DUMMY_PSEH) || defined (__arm__) || defined(__clang__) || defined(_M_AMD64)
#define _SEH2_TRY { #define _SEH2_FINALLY } { @@ -47,6 +47,21 @@ #define _SEH2_AbnormalTermination() #define _SEH2_YIELD(STMT_) STMT_ #define _SEH2_LEAVE + +#elif defined(_USE_PSEH3) + +#include "pseh3.h" + +/* Compatibility macros */ +#define _SEH2_TRY _SEH3_TRY +#define _SEH2_EXCEPT _SEH3_EXCEPT +#define _SEH2_FINALLY _SEH3_FINALLY +#define _SEH2_END _SEH3_END +#define _SEH2_GetExceptionInformation() ((struct _EXCEPTION_POINTERS*)_exception_info()) +#define _SEH2_GetExceptionCode _exception_code +#define _SEH2_AbnormalTermination _abnormal_termination +#define _SEH2_LEAVE _SEH3_LEAVE +#define _SEH2_YIELD(x) x
#elif defined(__GNUC__)
Added: trunk/reactos/include/reactos/libs/pseh/pseh3.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/pseh/p... ============================================================================== --- trunk/reactos/include/reactos/libs/pseh/pseh3.h (added) +++ trunk/reactos/include/reactos/libs/pseh/pseh3.h [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -1,0 +1,292 @@ +/* + * PROJECT: ReactOS system libraries + * LICENSE: GNU GPL - See COPYING in the top level directory + * PURPOSE: Header for PSEH3 + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* For additional information see pseh3.c in the related library. */ + +#pragma once +#define _PSEH3_H_ + +#include "excpt.h" + +typedef struct _SEH3$_SCOPE_TABLE +{ + void *Target; + void *Filter; +} SEH3$_SCOPE_TABLE, *PSEH3$_SCOPE_TABLE; + +typedef struct _SEH3$_EXCEPTION_POINTERS +{ + struct _EXCEPTION_RECORD *ExceptionRecord; + struct _CONTEXT *ContextRecord; +} SEH3$_EXCEPTION_POINTERS, *PSEH3$_EXCEPTION_POINTERS; + +typedef struct _SEH3$_REGISTRATION_FRAME +{ + /* First the Windows base record. Don't move this! */ + struct _SEH3$_REGISTRATION_FRAME *Next; + void *Handler; + + /* Points to the end of the internal registration chain */ + struct _SEH3$_REGISTRATION_FRAME *EndOfChain; + + /* Pointer to the static scope table */ + PSEH3$_SCOPE_TABLE ScopeTable; + + /* Except handler stores pointer to exception pointers here */ + PSEH3$_EXCEPTION_POINTERS volatile ExceptionPointers; + + /* Registers that we need to save */ + unsigned long Esp; + unsigned long Ebp; + +} SEH3$_REGISTRATION_FRAME ,*PSEH3$_REGISTRATION_FRAME; + +extern inline __attribute__((always_inline,gnu_inline)) +void _SEH3$_UnregisterFrame(volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame) +{ + asm volatile ("movl %k[NewHead], %%fs:0" + : : [NewHead] "ir" (RegistrationFrame->Next) : "memory"); +} + +extern inline __attribute__((always_inline,gnu_inline)) +void _SEH3$_UnregisterTryLevel( + volatile SEH3$_REGISTRATION_FRAME *TrylevelFrame) +{ + volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame; + asm volatile ("movl %%fs:0, %k[RegistrationFrame]" + : [RegistrationFrame] "=r" (RegistrationFrame) : ); + RegistrationFrame->EndOfChain = TrylevelFrame->Next; +} + +enum +{ + _SEH3$_TryLevel = 0, +}; + +/* These are global dummy definitions, that get overwritten in the local context of __finally / __except blocks */ +int __cdecl __attribute__((error ("Can only be used inside a __finally block."))) _abnormal_termination(void); +unsigned long __cdecl __attribute__((error("Can only be used inside an exception filter or __except block."))) _exception_code(void); +void * __cdecl __attribute__((error("Can only be used inside an exception filter."))) _exception_info(void); + +/* Define the registers that get clobbered, when reaching the __except block. + We specify ebp on optimized builds without frame pointer, since it will be + used by GCC as a general purpose register then. */ +#if defined(__OPTIMIZE__) && defined(_ALLOW_OMIT_FRAME_POINTER) +#define _SEH3$_CLOBBER_ON_EXCEPTION "ebp", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory" +#else +#define _SEH3$_CLOBBER_ON_EXCEPTION "ebx", "ecx", "edx", "esi", "edi", "flags", "memory" +#endif + +/* This attribute allows automatic cleanup of the registered frames */ +#define _SEH3$_AUTO_CLEANUP __attribute__((cleanup(_SEH3$_AutoCleanup))) + +#define _SEH3$_ASM_GOTO(_Asm, _Label, ...) asm goto (_Asm : : : "memory", ## __VA_ARGS__ : _Label) + +#define _SEH3$_DECLARE_EXCEPT_INTRINSICS() \ + inline __attribute__((always_inline, gnu_inline)) \ + unsigned long _exception_code() { return _SEH3$_TrylevelFrame.ExceptionPointers->ExceptionRecord->ExceptionCode; } \ + +/* This is an asm wrapper around _SEH3$_RegisterFrame */ +#define _SEH3$_RegisterFrame(_TrylevelFrame, _DataTable, _Target) \ + asm goto ("call __SEH3$_RegisterFrame\n" \ + : \ + : "c" (_TrylevelFrame), "a" (_DataTable) \ + : "edx", "memory" \ + : _Target) + +/* This is an asm wrapper around _SEH3$_EnterTryLevel */ +#define _SEH3$_RegisterTryLevel(_TrylevelFrame, _DataTable, _Target) \ + asm goto ("call __SEH3$_RegisterTryLevel\n" \ + : \ + : "c" (_TrylevelFrame), "a" (_DataTable) \ + : "edx", "memory" \ + : _Target) + +/* On GCC the filter function is a nested function with __fastcall calling + convention. The eax register contains a base address the function uses + to address the callers stack frame. __fastcall is chosen, because it gives + us an effective was of passing one argument to the function, that we need + to tell the function in a first pass to return informtion about the frame + base address. Since this is something GCC chooses arbitrarily, we call + the function with an arbitrary base address in eax first and then use the + result to calculate the correct address for a second call to the function. */ +#define _SEH3$_DECLARE_FILTER_FUNC(_Name) \ + auto int __fastcall _Name(int Action) + +#define _SEH3$_NESTED_FUNC_OPEN(_Name) \ + int __fastcall _Name(int Action) \ + { \ + /* This is a fancy way to get information about the frame layout */ \ + if (Action == 0) return (int)&_SEH3$_TrylevelFrame; + +#define _SEH3$_DEFINE_FILTER_FUNC(_Name, expression) \ + _SEH3$_NESTED_FUNC_OPEN(_Name) \ + /* Declare the intrinsics for exception filters */ \ + inline __attribute__((always_inline, gnu_inline)) \ + unsigned long _exception_code() { return _SEH3$_TrylevelFrame.ExceptionPointers->ExceptionRecord->ExceptionCode; } \ + inline __attribute__((always_inline, gnu_inline)) \ + void * _exception_info() { return _SEH3$_TrylevelFrame.ExceptionPointers; } \ +\ + /* Now handle the actual filter expression */ \ + return (expression); \ + } + +#define _SEH3$_FINALLY_FUNC_OPEN(_Name) \ + _SEH3$_NESTED_FUNC_OPEN(_Name) \ + /* Declare the intrinsics for the finally function */ \ + inline __attribute__((always_inline, gnu_inline)) \ + int _abnormal_termination() { return (_SEH3$_TrylevelFrame.ScopeTable != 0); } \ + +#define _SEH3$_FILTER(_Filter, _FilterExpression) \ + (__builtin_constant_p(_FilterExpression) ? (void*)(unsigned long)(unsigned char)(unsigned long)(_FilterExpression) : _Filter) + +#define _SEH3$_DEFINE_DUMMY_FINALLY(_Name) \ + auto inline __attribute__((always_inline,gnu_inline)) int _Name(int Action) { return 0; } + +#define _SEH3$_DECLARE_CLEANUP_FUNC(_Name) \ + auto inline __attribute__((always_inline,gnu_inline)) void _Name(volatile SEH3$_REGISTRATION_FRAME *p) + +#define _SEH3$_DEFINE_CLEANUP_FUNC(_Name) \ + _SEH3$_DECLARE_CLEANUP_FUNC(_Name) \ + { \ + /* Unregister the frame */ \ + if (_SEH3$_TryLevel == 1) _SEH3$_UnregisterFrame(&_SEH3$_TrylevelFrame); \ + else _SEH3$_UnregisterTryLevel(&_SEH3$_TrylevelFrame); \ +\ + /* Invoke the finally function (an inline dummy in the __except case) */ \ + _SEH3$_FinallyFunction(1); \ + } + +/* This construct scares GCC so much, that it will stop moving code + around into places that are never executed. */ +#define _SEH3$_SCARE_GCC() \ + void *plabel; \ + _SEH3$_ASM_GOTO("#\n", _SEH3$_l_HandlerTarget); \ + asm volatile ("#" : "=a"(plabel) : "p"(&&_SEH3$_l_BeforeTry), "p"(&&_SEH3$_l_HandlerTarget), "p"(&&_SEH3$_l_OnException) \ + : _SEH3$_CLOBBER_ON_EXCEPTION ); \ + goto *plabel; + + +#define _SEH3_TRY \ + /* Enter the outer scope */ \ + do { \ + /* Declare local labels */ \ + __label__ _SEH3$_l_BeforeTry; \ + __label__ _SEH3$_l_DoTry; \ + __label__ _SEH3$_l_AfterTry; \ + __label__ _SEH3$_l_EndTry; \ + __label__ _SEH3$_l_HandlerTarget; \ + __label__ _SEH3$_l_OnException; \ +\ + /* Count the try level. Outside of any __try, _SEH3$_TryLevel is 0 */ \ + enum { \ + _SEH3$_PreviousTryLevel = _SEH3$_TryLevel, \ + _SEH3$_TryLevel = _SEH3$_PreviousTryLevel + 1, \ + }; \ +\ + /* Forward declaration of the auto cleanup function */ \ + _SEH3$_DECLARE_CLEANUP_FUNC(_SEH3$_AutoCleanup); \ +\ + /* Allocate a registration frame */ \ + volatile SEH3$_REGISTRATION_FRAME _SEH3$_AUTO_CLEANUP _SEH3$_TrylevelFrame; \ +\ + goto _SEH3$_l_BeforeTry; \ + /* Silence warning */ goto _SEH3$_l_AfterTry; \ +\ + _SEH3$_l_DoTry: \ + do + + +#define _SEH3_EXCEPT(...) \ + /* End the try block */ \ + while (0); \ + _SEH3$_l_AfterTry: (void)0; \ + goto _SEH3$_l_EndTry; \ +\ + _SEH3$_l_BeforeTry: (void)0; \ + _SEH3$_ASM_GOTO("#\n", _SEH3$_l_OnException); \ +\ + /* Forward declaration of the filter function */ \ + _SEH3$_DECLARE_FILTER_FUNC(_SEH3$_FilterFunction); \ +\ + /* Create a static data table that contains the jump target and filter function */ \ + static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { &&_SEH3$_l_HandlerTarget, _SEH3$_FILTER(&_SEH3$_FilterFunction, (__VA_ARGS__)) }; \ +\ + /* Register the registration record. */ \ + if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable, _SEH3$_l_HandlerTarget); \ + else _SEH3$_RegisterTryLevel(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable, _SEH3$_l_HandlerTarget); \ +\ + /* Emit the filter function */ \ + _SEH3$_DEFINE_FILTER_FUNC(_SEH3$_FilterFunction, (__VA_ARGS__)) \ +\ + /* Define an empty inline finally function */ \ + _SEH3$_DEFINE_DUMMY_FINALLY(_SEH3$_FinallyFunction) \ +\ + /* Allow intrinsics for __except to be used */ \ + _SEH3$_DECLARE_EXCEPT_INTRINSICS() \ +\ + goto _SEH3$_l_DoTry; \ +\ + _SEH3$_l_HandlerTarget: (void)0; \ +\ + if (1) \ + { \ + do + + +#define _SEH3_FINALLY \ + /* End the try block */ \ + while (0); \ + _SEH3$_l_AfterTry: (void)0; \ + /* Set ScopeTable to 0, this is used by _abnormal_termination() */ \ + _SEH3$_TrylevelFrame.ScopeTable = 0; \ +\ + goto _SEH3$_l_EndTry; \ +\ + _SEH3$_l_BeforeTry: (void)0; \ + _SEH3$_ASM_GOTO("#\n", _SEH3$_l_OnException); \ +\ + /* Forward declaration of the finally function */ \ + _SEH3$_DECLARE_FILTER_FUNC(_SEH3$_FinallyFunction); \ +\ + /* Create a static data table that contains the finally function */ \ + static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { 0, &_SEH3$_FinallyFunction }; \ +\ + /* Register the registration record. */ \ + if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable, _SEH3$_l_HandlerTarget); \ + else _SEH3$_RegisterTryLevel(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable, _SEH3$_l_HandlerTarget); \ +\ + goto _SEH3$_l_DoTry; \ +\ + _SEH3$_l_HandlerTarget: (void)0; \ +\ + _SEH3$_FINALLY_FUNC_OPEN(_SEH3$_FinallyFunction) \ + /* This construct makes sure that the finally function returns */ \ + /* a proper value at the end */ \ + for (; ; (void)({return 0; 0;})) + + +#define _SEH3_END \ + while (0); \ + }; \ + goto _SEH3$_l_EndTry; \ +\ + _SEH3$_l_OnException: (void)0; \ + /* Force GCC to create proper code pathes */ \ + _SEH3$_SCARE_GCC() \ +\ + _SEH3$_l_EndTry:(void)0; \ + _SEH3$_ASM_GOTO("#\n", _SEH3$_l_OnException); \ +\ + /* Implementation of the auto cleanup function */ \ + _SEH3$_DEFINE_CLEANUP_FUNC(_SEH3$_AutoCleanup); \ +\ + /* Close the outer scope */ \ + } while (0); + +#define _SEH3_LEAVE goto _SEH3$_l_AfterTry +
Propchange: trunk/reactos/include/reactos/libs/pseh/pseh3.h ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/lib/pseh/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/CMakeLists.txt?rev... ============================================================================== --- trunk/reactos/lib/pseh/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/lib/pseh/CMakeLists.txt [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -1,8 +1,12 @@
if(NOT MSVC)
- list(APPEND SOURCE framebased.c) - if(ARCH STREQUAL "i386") + if (USE_PSEH3) + include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs/pseh) + list(APPEND SOURCE + i386/pseh3.c + i386/pseh3_i386.S) + elseif(ARCH STREQUAL "i386") list(APPEND SOURCE i386/framebased.S i386/framebased-gcchack.c
Added: trunk/reactos/lib/pseh/i386/pseh3.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3.c?rev=5... ============================================================================== --- trunk/reactos/lib/pseh/i386/pseh3.c (added) +++ trunk/reactos/lib/pseh/i386/pseh3.c [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -1,0 +1,275 @@ +/* + * PROJECT: ReactOS system libraries + * LICENSE: GNU GPL - See COPYING in the top level directory + * PURPOSE: Support library for PSEH3 + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* + * - Naming: To avoid naming conflicts, all internal identifiers are prefixed + * with _SEH3$_. + * - Frame graph: PSEH3 uses the same registration frame for every trylevel. + * Only the top trylevel is registered in FS:0, the inner trylevels are linked + * to the first trylevel frame. Only the first trylevel frame has the Handler + * member set, it's 0 for all others as an identification. The EndOfChain + * member of the FS:0 registered frame points to the last internal frame, + * which is the frame itself, when only 1 trylevel is present. + * + * The registration graph looks like this: + * + * newer handlers + * ----------------> + * + * fs:0 /----------------\ + * |-----------|<-\ |-----------|<-\ / |----------|<-\ ->|----------| + * | <Next> | -| <Next> | --/--| <Next> | ---| <Next> | + * | <Handler> | | <Handler> | / | <NULL> | | <NULL> | + * |-----------| |-----------| / |----------| |----------| + * |EndOfChain |---/ + * | ... | + * |-----------| + */ + +#include <stdarg.h> +#include <windef.h> +#include <winnt.h> + +#include "pseh3.h" +#include "pseh3_asmdef.h" + +/* Make sure the asm definitions match the structures */ +C_ASSERT(SEH3_REGISTRATION_FRAME_Next == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, Next)); +C_ASSERT(SEH3_REGISTRATION_FRAME_Handler == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, Handler)); +C_ASSERT(SEH3_REGISTRATION_FRAME_EndOfChain == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, EndOfChain)); +C_ASSERT(SEH3_REGISTRATION_FRAME_ScopeTable == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, ScopeTable)); +C_ASSERT(SEH3_REGISTRATION_FRAME_ExceptionPointers == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, ExceptionPointers)); +C_ASSERT(SEH3_REGISTRATION_FRAME_Esp == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, Esp)); +C_ASSERT(SEH3_REGISTRATION_FRAME_Ebp == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, Ebp)); +C_ASSERT(SEH3_SCOPE_TABLE_Filter == FIELD_OFFSET(SEH3$_SCOPE_TABLE, Filter)); +C_ASSERT(SEH3_SCOPE_TABLE_Target == FIELD_OFFSET(SEH3$_SCOPE_TABLE, Target)); + +static inline +void _SEH3$_Unregister( + volatile SEH3$_REGISTRATION_FRAME *Frame) +{ + if (Frame->Handler) + _SEH3$_UnregisterFrame(Frame); + else + _SEH3$_UnregisterTryLevel(Frame); +} + +static inline +LONG +_SEH3$_InvokeFilter( + PVOID Record, + PVOID Filter) +{ + LONG FilterResult; + + asm volatile ( + /* First call with param = 0 to get the frame layout */ + "xorl %%ecx, %%ecx\n\t" + "xorl %%eax, %%eax\n\t" + "call *%[Filter]\n\t" + + /* The result is the frame base address that we passed in (0) plus the + offset to the registration record. */ + "negl %%eax\n\t" + "addl %[Record], %%eax\n\t" + + /* Second call to get the filter result */ + "mov $1, %%ecx\n\t" + "call *%[Filter]\n\t" + : "=a"(FilterResult) + : [Record] "m" (Record), [Filter] "m" (Filter) + : "ecx", "edx"); + + return FilterResult; +} + +static inline +LONG +_SEH3$_GetFilterResult( + PSEH3$_REGISTRATION_FRAME Record) +{ + PVOID Filter = Record->ScopeTable->Filter; + LONG Result; + + if (Record->ScopeTable->Target == NULL) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + /* Check if we have a constant filter */ + if (((ULONG)Filter & 0xFFFFFF00) == 0) + { + /* Lowest 8 bit are sign extended to give the result */ + Result = (LONG)(CHAR)(ULONG)Filter; + } + else + { + /* Call the filter function */ + Result = _SEH3$_InvokeFilter(Record, Filter); + } + + /* Normalize the result */ + if (Result < 0) return EXCEPTION_CONTINUE_EXECUTION; + else if (Result > 0) return EXCEPTION_EXECUTE_HANDLER; + else return EXCEPTION_CONTINUE_SEARCH; +} + +static inline +VOID +_SEH3$_CallFinally( + PSEH3$_REGISTRATION_FRAME Record) +{ + _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter); +} + +__attribute__((noreturn)) +static inline +void +_SEH3$_JumpToTarget( + PSEH3$_REGISTRATION_FRAME RegistrationFrame) +{ + asm volatile ( + /* Load the registers */ + "movl 20(%%ecx), %%esp\n" + "movl 24(%%ecx), %%ebp\n" + + /* Stack pointer is 4 off from the call to __SEH3$_RegisterFrame */ + "addl $4, %%esp\n" + + /* Jump into the exception handler */ + "jmp *%[Target]\n" + : : + "c" (RegistrationFrame), + "a" (RegistrationFrame->ScopeTable), + [Target] "m" (RegistrationFrame->ScopeTable->Target) + ); + + __builtin_unreachable(); +} + +static inline +void +_SEH3$_CallRtlUnwind( + PSEH3$_REGISTRATION_FRAME RegistrationFrame) +{ + LONG ClobberedEax; + + asm volatile( + "push %%ebp\n" + "push $0\n" + "push $0\n" + "push $0\n" + "push %[TargetFrame]\n" + "call _RtlUnwind@16\n" + "pop %%ebp\n" + : "=a" (ClobberedEax) + : [TargetFrame] "a" (RegistrationFrame) + : "ebx", "ecx", "edx", "esi", + "edi", "flags", "memory"); +} + +EXCEPTION_DISPOSITION +__cdecl +__attribute__ ((__target__ ("cld"))) +_SEH3$_except_handler( + struct _EXCEPTION_RECORD * ExceptionRecord, + PSEH3$_REGISTRATION_FRAME EstablisherFrame, + struct _CONTEXT * ContextRecord, + void * DispatcherContext) +{ + PSEH3$_REGISTRATION_FRAME CurrentFrame, TargetFrame; + SEH3$_EXCEPTION_POINTERS ExceptionPointers; + LONG FilterResult; + + /* Clear the direction flag. */ + asm volatile ("cld\n" : : : "memory"); + + /* Check if this is an unwind */ + if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWIND) + { + /* Unwind all local frames */ + TargetFrame = EstablisherFrame->Next; + } + else + { + /* Save the exception pointers on the stack */ + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + + /* Loop all frames for this registration */ + CurrentFrame = EstablisherFrame->EndOfChain; + for (;;) + { + /* Check if we have an exception handler */ + if (CurrentFrame->ScopeTable->Target != NULL) + { + /* Set exception pointers for this frame */ + CurrentFrame->ExceptionPointers = &ExceptionPointers; + + /* Get the filter result */ + FilterResult = _SEH3$_GetFilterResult(CurrentFrame); + + /* Check, if continuuing is requested */ + if (FilterResult == EXCEPTION_CONTINUE_EXECUTION) + { + return ExceptionContinueExecution; + } + + /* Check if the except handler shall be executed */ + if (FilterResult == EXCEPTION_EXECUTE_HANDLER) break; + } + + /* Bail out if this is the last handler */ + if (CurrentFrame == EstablisherFrame) + return ExceptionContinueSearch; + + /* Go to the next frame */ + CurrentFrame = CurrentFrame->Next; + } + + /* Call RtlUnwind to unwind the frames below this one */ + _SEH3$_CallRtlUnwind(EstablisherFrame); + + /* Do a local unwind up to this frame */ + TargetFrame = CurrentFrame; + } + + /* Loop frames up to the target frame */ + for (CurrentFrame = EstablisherFrame->EndOfChain; + CurrentFrame != TargetFrame; + CurrentFrame = CurrentFrame->Next) + { + /* Manually unregister the frame */ + _SEH3$_Unregister(CurrentFrame); + + /* Check if this is an unwind frame */ + if (CurrentFrame->ScopeTable->Target == NULL) + { + /* Set exception pointers for this frame */ + CurrentFrame->ExceptionPointers = &ExceptionPointers; + + /* Call the finally function */ + _SEH3$_CallFinally(CurrentFrame); + } + } + + /* Check if this was an unwind */ + if (ExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING) + { + return ExceptionContinueSearch; + } + + /* Unregister the frame. It will be unregistered again at the end of the + __except block, due to auto cleanup, but that doesn't hurt. + All we do is set either fs:[0] or EstablisherFrame->EndOfChain to + CurrentFrame->Next, which will not change it's value. */ + _SEH3$_Unregister(CurrentFrame); + + /* Jump to the __except block (does not return) */ + _SEH3$_JumpToTarget(CurrentFrame); +} +
Propchange: trunk/reactos/lib/pseh/i386/pseh3.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/lib/pseh/i386/pseh3_asmdef.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3_asmdef.... ============================================================================== --- trunk/reactos/lib/pseh/i386/pseh3_asmdef.h (added) +++ trunk/reactos/lib/pseh/i386/pseh3_asmdef.h [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -1,0 +1,12 @@ + + +#define SEH3_REGISTRATION_FRAME_Next 0 +#define SEH3_REGISTRATION_FRAME_Handler 4 +#define SEH3_REGISTRATION_FRAME_EndOfChain 8 +#define SEH3_REGISTRATION_FRAME_ScopeTable 12 +#define SEH3_REGISTRATION_FRAME_ExceptionPointers 16 +#define SEH3_REGISTRATION_FRAME_Esp 20 +#define SEH3_REGISTRATION_FRAME_Ebp 24 + +#define SEH3_SCOPE_TABLE_Target 0 +#define SEH3_SCOPE_TABLE_Filter 4
Propchange: trunk/reactos/lib/pseh/i386/pseh3_asmdef.h ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/lib/pseh/i386/pseh3_i386.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/i386/pseh3_i386.S?... ============================================================================== --- trunk/reactos/lib/pseh/i386/pseh3_i386.S (added) +++ trunk/reactos/lib/pseh/i386/pseh3_i386.S [iso-8859-1] Sun Sep 9 21:12:00 2012 @@ -1,0 +1,72 @@ +/* + * PROJECT: ReactOS system libraries + * LICENSE: GNU GPL - See COPYING in the top level directory + * PURPOSE: Support library for PSEH3 + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#include "pseh3_asmdef.h" + +.intel_syntax noprefix + +.text + + +.extern __SEH3$_except_handler + +/* + * void + * _SEH3$_RegisterFrame( + * PSEH_REGISTRATION_FRAME RegistrationRecord<ecx>, + * PSEH_DATA_TABLE DataTable<eax>); + */ +.global __SEH3$_RegisterFrame +__SEH3$_RegisterFrame: + + /* Save the address of the static data table */ + mov [ecx + SEH3_REGISTRATION_FRAME_ScopeTable], eax + + /* Set the handler address */ + mov dword ptr [ecx + SEH3_REGISTRATION_FRAME_Handler], offset __SEH3$_except_handler + + /* Set this as the end of the internal chain */ + mov dword ptr [ecx + SEH3_REGISTRATION_FRAME_EndOfChain], ecx + + /* Register the frame in the TEB */ + mov eax, dword ptr fs:[0] + mov [ecx + SEH3_REGISTRATION_FRAME_Next], eax + mov dword ptr fs:[0], ecx + + /* Save the registers */ + mov [ecx + SEH3_REGISTRATION_FRAME_Esp], esp + mov [ecx + SEH3_REGISTRATION_FRAME_Ebp], ebp + + ret + + +.global __SEH3$_RegisterTryLevel +__SEH3$_RegisterTryLevel: + + /* Save the address of the static data table */ + mov [ecx + SEH3_REGISTRATION_FRAME_ScopeTable], eax + + /* Set the handler address to NULL as identification */ + and dword ptr [ecx + SEH3_REGISTRATION_FRAME_Handler], 0 + + /* Get the current registered frame */ + mov eax, dword ptr fs:[0] + + /* Get the current end of the chain and set this as Next */ + mov edx, [eax + SEH3_REGISTRATION_FRAME_EndOfChain] + mov [ecx + SEH3_REGISTRATION_FRAME_Next], edx + + /* Set this as the end of the internal chain */ + mov dword ptr [eax + SEH3_REGISTRATION_FRAME_EndOfChain], ecx + + /* Save the registers */ + mov [ecx + SEH3_REGISTRATION_FRAME_Esp], esp + mov [ecx + SEH3_REGISTRATION_FRAME_Ebp], ebp + + ret + +
Propchange: trunk/reactos/lib/pseh/i386/pseh3_i386.S ------------------------------------------------------------------------------ svn:eol-style = native