From d23ee5f3651a723744e16d1625cd9f61b41d3a49 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 4 Jul 2025 20:06:19 +0300 Subject: [PATCH] [PSEH] Make structures more SEH3 compatible --- sdk/lib/pseh/i386/pseh3.c | 103 +++++++++++++++++++++++------- sdk/lib/pseh/i386/pseh3_asmdef.h | 22 ++++--- sdk/lib/pseh/i386/pseh3_i386.S | 3 - sdk/lib/pseh/include/pseh/pseh3.h | 78 ++++++++++++---------- 4 files changed, 137 insertions(+), 69 deletions(-) diff --git a/sdk/lib/pseh/i386/pseh3.c b/sdk/lib/pseh/i386/pseh3.c index 7b74100e03f..2ad8fdfa5d1 100644 --- a/sdk/lib/pseh/i386/pseh3.c +++ b/sdk/lib/pseh/i386/pseh3.c @@ -45,8 +45,9 @@ /* 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_TryLevel == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, TryLevel)); +C_ASSERT(SEH3_REGISTRATION_FRAME_EndOfChain == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, EndOfChain)); C_ASSERT(SEH3_REGISTRATION_FRAME_ExceptionPointers == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, ExceptionPointers)); C_ASSERT(SEH3_REGISTRATION_FRAME_ExceptionCode == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, ExceptionCode)); C_ASSERT(SEH3_REGISTRATION_FRAME_Esp == FIELD_OFFSET(SEH3$_REGISTRATION_FRAME, Esp)); @@ -63,6 +64,13 @@ C_ASSERT(SEH3_REGISTRATION_FRAME_ReturnAddress == FIELD_OFFSET(SEH3$_REGISTRATIO C_ASSERT(SEH3_SCOPE_TABLE_Filter == FIELD_OFFSET(SEH3$_SCOPE_TABLE, Filter)); C_ASSERT(SEH3_SCOPE_TABLE_Target == FIELD_OFFSET(SEH3$_SCOPE_TABLE, Target)); +enum +{ + _SEH3$_NESTED_HANDLER = 0, + _SEH3$_CPP_HANDLER = 1, + _SEH3$_CLANG_HANDLER = 2, +}; + void __attribute__((regparm(1))) _SEH3$_Unregister( @@ -76,7 +84,7 @@ _SEH3$_Unregister( /* There shouldn't be any more nested try-level frames */ ASSERT(Frame->EndOfChain == Frame); - /* During unwinding on Windows ExecuteHandler2 installs it's own EH frame, + /* During unwinding on Windows ExecuteHandler2 installs its own EH frame, so there can be one or even multiple frames before our own one and we need to search for the link that points to our head frame. */ CurrentFrame = (SEH3$_REGISTRATION_FRAME*)__readfsdword(0); @@ -156,20 +164,21 @@ static inline LONG _SEH3$_InvokeFilter( volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame, - PVOID Filter) + PVOID Filter, + int HandlerType) { LONG FilterResult; - if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_NESTED_HANDLER) + if (HandlerType == _SEH3$_NESTED_HANDLER) { return _SEH3$_InvokeNestedFunctionFilter(RegistrationFrame, Filter); } - else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CPP_HANDLER) + else if (HandlerType == _SEH3$_CPP_HANDLER) { /* Call the embedded filter function */ return _SEH3$_InvokeEmbeddedFilter(RegistrationFrame); } - else if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER) + else if (HandlerType == _SEH3$_CLANG_HANDLER) { return _SEH3$_InvokeEmbeddedFilterFromRegistration(RegistrationFrame); } @@ -184,7 +193,7 @@ _SEH3$_InvokeFilter( void __attribute__((regparm(1))) -_SEH3$_AutoCleanup( +_SEH3$_C_AutoCleanup( volatile SEH3$_REGISTRATION_FRAME *Frame) { _SEH3$_Unregister(Frame); @@ -192,15 +201,37 @@ _SEH3$_AutoCleanup( /* Check for __finally frames */ if (Frame->ScopeTable->Target == NULL) { - _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter); +#ifdef __clang__ + _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_CLANG_HANDLER); +#else + _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_NESTED_HANDLER); +#endif } - } +void +__attribute__((regparm(1))) +_SEH3$_CPP_AutoCleanup( + volatile SEH3$_REGISTRATION_FRAME *Frame) +{ + if (Frame->Handler) + _SEH3$_UnregisterFrame(Frame); + else + _SEH3$_UnregisterTryLevel(Frame); + + /* Check for __finally frames */ + if (Frame->ScopeTable->Target == NULL) + { + _SEH3$_InvokeFilter(Frame, Frame->ScopeTable->Filter, _SEH3$_CPP_HANDLER); + } +} + + static inline LONG _SEH3$_GetFilterResult( - PSEH3$_REGISTRATION_FRAME Record) + PSEH3$_REGISTRATION_FRAME Record, + int HandlerType) { PVOID Filter = Record->ScopeTable->Filter; LONG Result; @@ -214,7 +245,7 @@ _SEH3$_GetFilterResult( else { /* Call the filter function */ - Result = _SEH3$_InvokeFilter(Record, Filter); + Result = _SEH3$_InvokeFilter(Record, Filter, HandlerType); } /* Normalize the result */ @@ -226,9 +257,10 @@ _SEH3$_GetFilterResult( static inline VOID _SEH3$_CallFinally( - PSEH3$_REGISTRATION_FRAME Record) + PSEH3$_REGISTRATION_FRAME Record, + int HandlerType) { - _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter); + _SEH3$_InvokeFilter(Record, Record->ScopeTable->Filter, HandlerType); } __attribute__((noreturn)) @@ -237,8 +269,7 @@ void _SEH3$_JumpToTarget( PSEH3$_REGISTRATION_FRAME RegistrationFrame) { - if (RegistrationFrame->ScopeTable->HandlerType == _SEH3$_CLANG_HANDLER) - { +#ifdef __clang__ asm volatile ( /* Load the registers */ "movl 24(%%ecx), %%esp\n\t" @@ -258,9 +289,7 @@ _SEH3$_JumpToTarget( "a" (RegistrationFrame->ScopeTable), [Target] "m" (RegistrationFrame->ScopeTable->Target) ); - } - else - { +#else asm volatile ( /* Load the registers */ "movl 24(%%ecx), %%esp\n\t" @@ -276,7 +305,7 @@ _SEH3$_JumpToTarget( "a" (RegistrationFrame->ScopeTable), [Target] "m" (RegistrationFrame->ScopeTable->Target) ); - } +#endif __builtin_unreachable(); } @@ -287,16 +316,17 @@ _SEH3$_CallRtlUnwind( PSEH3$_REGISTRATION_FRAME RegistrationFrame); -EXCEPTION_DISPOSITION +int // EXCEPTION_DISPOSITION __cdecl #ifndef __clang__ __attribute__ ((__target__ ("cld"))) #endif -_SEH3$_except_handler( +_SEH3$_common_except_handler( struct _EXCEPTION_RECORD * ExceptionRecord, PSEH3$_REGISTRATION_FRAME EstablisherFrame, struct _CONTEXT * ContextRecord, - void * DispatcherContext) + void * DispatcherContext, + int HandlerType) { PSEH3$_REGISTRATION_FRAME CurrentFrame, TargetFrame; SEH3$_EXCEPTION_POINTERS ExceptionPointers; @@ -329,7 +359,7 @@ _SEH3$_except_handler( CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode; /* Get the filter result */ - FilterResult = _SEH3$_GetFilterResult(CurrentFrame); + FilterResult = _SEH3$_GetFilterResult(CurrentFrame, HandlerType); /* Check, if continuuing is requested */ if (FilterResult == EXCEPTION_CONTINUE_EXECUTION) @@ -372,7 +402,7 @@ _SEH3$_except_handler( CurrentFrame->ExceptionCode = ExceptionRecord->ExceptionCode; /* Call the finally function */ - _SEH3$_CallFinally(CurrentFrame); + _SEH3$_CallFinally(CurrentFrame, HandlerType); } } @@ -392,3 +422,28 @@ _SEH3$_except_handler( _SEH3$_JumpToTarget(CurrentFrame); } +int // EXCEPTION_DISPOSITION +__cdecl +_SEH3$_C_except_handler( + struct _EXCEPTION_RECORD* ExceptionRecord, + PSEH3$_REGISTRATION_FRAME EstablisherFrame, + struct _CONTEXT* ContextRecord, + void* DispatcherContext) +{ +#ifdef __clang__ + return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_CLANG_HANDLER); +#else + return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_NESTED_HANDLER); +#endif +} + +int // EXCEPTION_DISPOSITION +__cdecl +_SEH3$_CPP_except_handler( + struct _EXCEPTION_RECORD* ExceptionRecord, + PSEH3$_REGISTRATION_FRAME EstablisherFrame, + struct _CONTEXT* ContextRecord, + void* DispatcherContext) +{ + return _SEH3$_common_except_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext, _SEH3$_CPP_HANDLER); +} diff --git a/sdk/lib/pseh/i386/pseh3_asmdef.h b/sdk/lib/pseh/i386/pseh3_asmdef.h index 0650155ee3a..edd25cd7b6d 100644 --- a/sdk/lib/pseh/i386/pseh3_asmdef.h +++ b/sdk/lib/pseh/i386/pseh3_asmdef.h @@ -2,17 +2,19 @@ #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_ExceptionCode 20 +#define SEH3_REGISTRATION_FRAME_ScopeTable 8 +#define SEH3_REGISTRATION_FRAME_TryLevel 12 +#define SEH3_REGISTRATION_FRAME_EndOfChain 16 +#define SEH3_REGISTRATION_FRAME_ExceptionPointers 20 #define SEH3_REGISTRATION_FRAME_Esp 24 #define SEH3_REGISTRATION_FRAME_Ebp 28 -#define SEH3_REGISTRATION_FRAME_AllocaFrame 32 -#define SEH3_REGISTRATION_FRAME_Ebx 36 -#define SEH3_REGISTRATION_FRAME_Esi 40 -#define SEH3_REGISTRATION_FRAME_Edi 44 -#define SEH3_REGISTRATION_FRAME_ReturnAddress 48 +#define SEH3_REGISTRATION_FRAME_ExceptionCode 32 +#define SEH3_REGISTRATION_FRAME_AllocaFrame 36 +#define SEH3_REGISTRATION_FRAME_Ebx 40 +#define SEH3_REGISTRATION_FRAME_Esi 44 +#define SEH3_REGISTRATION_FRAME_Edi 48 +#define SEH3_REGISTRATION_FRAME_ReturnAddress 52 -#define SEH3_SCOPE_TABLE_Target 0 +#define SEH3_SCOPE_TABLE_EnclosingLevel 0 #define SEH3_SCOPE_TABLE_Filter 4 +#define SEH3_SCOPE_TABLE_Target 8 diff --git a/sdk/lib/pseh/i386/pseh3_i386.S b/sdk/lib/pseh/i386/pseh3_i386.S index c4d9b3962b5..a5f9aa326f0 100644 --- a/sdk/lib/pseh/i386/pseh3_i386.S +++ b/sdk/lib/pseh/i386/pseh3_i386.S @@ -47,9 +47,6 @@ __SEH3$_RegisterFrame: /* Save the address of the static data table */ mov [eax + SEH3_REGISTRATION_FRAME_ScopeTable], edx - /* Set the handler address */ - mov dword ptr [eax + SEH3_REGISTRATION_FRAME_Handler], offset __SEH3$_except_handler - /* Set this as the end of the internal chain */ mov dword ptr [eax + SEH3_REGISTRATION_FRAME_EndOfChain], eax diff --git a/sdk/lib/pseh/include/pseh/pseh3.h b/sdk/lib/pseh/include/pseh/pseh3.h index b8aa437589a..b8b5a519896 100644 --- a/sdk/lib/pseh/include/pseh/pseh3.h +++ b/sdk/lib/pseh/include/pseh/pseh3.h @@ -21,26 +21,11 @@ extern "C" { #define _SEH3$_FRAME_ALL_NONVOLATILES 1 #endif -enum -{ - _SEH3$_NESTED_HANDLER = 0, - _SEH3$_CPP_HANDLER = 1, - _SEH3$_CLANG_HANDLER = 2, -#ifdef __clang__ - _SEH3$_HANDLER_TYPE = _SEH3$_CLANG_HANDLER, -#elif defined(__cplusplus) - _SEH3$_HANDLER_TYPE = _SEH3$_CPP_HANDLER, -#else - _SEH3$_HANDLER_TYPE = _SEH3$_NESTED_HANDLER, -#endif -}; - typedef struct _SEH3$_SCOPE_TABLE { - void *Target; + unsigned long EnclosingLevel; void *Filter; - unsigned char TryLevel; - unsigned char HandlerType; + void *Target; } SEH3$_SCOPE_TABLE, *PSEH3$_SCOPE_TABLE; typedef struct _SEH3$_EXCEPTION_POINTERS @@ -55,22 +40,25 @@ typedef struct _SEH3$_REGISTRATION_FRAME 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; + /* Index into ScopeTable array */ + unsigned long TryLevel; + + /* Points to the end of the internal registration chain */ + struct _SEH3$_REGISTRATION_FRAME *EndOfChain; + /* Except handler stores pointer to exception pointers here */ PSEH3$_EXCEPTION_POINTERS volatile ExceptionPointers; - /* Except handler stores the exception code here */ - unsigned long ExceptionCode; - /* Registers that we need to save */ unsigned long Esp; unsigned long Ebp; + /* Except handler stores the exception code here */ + unsigned long ExceptionCode; + char* AllocaFrame; #ifdef _SEH3$_FRAME_ALL_NONVOLATILES unsigned long Ebx; @@ -82,6 +70,22 @@ typedef struct _SEH3$_REGISTRATION_FRAME #endif } SEH3$_REGISTRATION_FRAME ,*PSEH3$_REGISTRATION_FRAME; +#if defined(__cplusplus) + #define _SEH3$_except_handler _SEH3$_CPP_except_handler + #define _SEH3$_AutoCleanup _SEH3$_CPP_AutoCleanup +#else + #define _SEH3$_except_handler _SEH3$_C_except_handler + #define _SEH3$_AutoCleanup _SEH3$_C_AutoCleanup +#endif + +int +__cdecl +_SEH3$_except_handler( + struct _EXCEPTION_RECORD * ExceptionRecord, + PSEH3$_REGISTRATION_FRAME EstablisherFrame, + struct _CONTEXT * ContextRecord, + void * DispatcherContext); + /* Prevent gcc from inlining functions that use SEH. */ static inline __attribute__((always_inline)) __attribute__((returns_twice)) void _SEH3$_PreventInlining() {} @@ -106,7 +110,7 @@ void _SEH3$_UnregisterTryLevel( enum { - _SEH3$_TryLevel = 0, + _SEH3$_TryLevel = -1, }; #ifndef __clang__ @@ -146,6 +150,8 @@ _SEH3$_RegisterTryLevelWithNonVolatiles( #define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \ do { \ + (_TrylevelFrame)->Handler = (void*)_SEH3$_except_handler; \ + (_TrylevelFrame)->TryLevel = 0; \ int result = _SEH3$_RegisterFrameWithNonVolatiles(_TrylevelFrame, _DataTable, __builtin_alloca(0)); \ if (__builtin_expect(result != 0, 0)) \ { \ @@ -157,6 +163,7 @@ _SEH3$_RegisterTryLevelWithNonVolatiles( #define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \ do { \ + (_TrylevelFrame)->TryLevel = _SEH3$_TryLevel; \ int result = _SEH3$_RegisterTryLevelWithNonVolatiles(_TrylevelFrame, _DataTable, __builtin_alloca(0)); \ if (__builtin_expect(result != 0, 0)) \ { \ @@ -198,11 +205,18 @@ _SEH3$_RegisterTryLevelWithNonVolatiles( /* This is an asm wrapper around _SEH3$_RegisterFrame */ #define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \ - _SEH3$_CALL_WRAPPER(__SEH3$_RegisterFrame, _TrylevelFrame, _DataTable) + do { \ + (_TrylevelFrame)->Handler = (void*)_SEH3$_except_handler; \ + (_TrylevelFrame)->TryLevel = 0; \ + _SEH3$_CALL_WRAPPER(__SEH3$_RegisterFrame, _TrylevelFrame, _DataTable); \ + } while (0) /* This is an asm wrapper around _SEH3$_RegisterTryLevel */ #define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \ - _SEH3$_CALL_WRAPPER(__SEH3$_RegisterTryLevel, _TrylevelFrame, _DataTable) + do { \ + (_TrylevelFrame)->TryLevel = _SEH3$_TryLevel; \ + _SEH3$_CALL_WRAPPER(__SEH3$_RegisterTryLevel, _TrylevelFrame, _DataTable); \ + } while (0) /* This construct scares GCC so much, that it will stop moving code around into places that are never executed. */ @@ -330,7 +344,7 @@ _Pragma("GCC diagnostic pop") \ { \ (void)p; \ /* Unregister the frame */ \ - if (_SEH3$_TryLevel == 1) _SEH3$_UnregisterFrame(&_SEH3$_TrylevelFrame); \ + if (_SEH3$_TryLevel == 0) _SEH3$_UnregisterFrame(&_SEH3$_TrylevelFrame); \ else _SEH3$_UnregisterTryLevel(&_SEH3$_TrylevelFrame); \ \ /* Invoke the finally function (an inline dummy in the __except case) */ \ @@ -358,7 +372,7 @@ _Pragma("GCC diagnostic pop") \ (void)&&_SEH3$_l_BeforeFilterOrFinally; \ (void)&&_SEH3$_l_FilterOrFinally; \ \ - /* Count the try level. Outside of any __try, _SEH3$_TryLevel is 0 */ \ + /* Count the try level. Outside of any __try, _SEH3$_TryLevel is -1 */ \ enum { \ _SEH3$_PreviousTryLevel = _SEH3$_TryLevel, \ _SEH3$_TryLevel = _SEH3$_PreviousTryLevel + 1, \ @@ -394,10 +408,10 @@ _Pragma("GCC diagnostic pop") \ _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__)), _SEH3$_TryLevel, _SEH3$_HANDLER_TYPE }; \ + static const SEH3$_SCOPE_TABLE __attribute__((section(".xdata$x"))) _SEH3$_ScopeTable = { (unsigned)(_SEH3$_TryLevel - 1), _SEH3$_FILTER(&_SEH3$_FilterFunction, (__VA_ARGS__)), &&_SEH3$_l_HandlerTarget }; \ \ /* Register the registration record. */ \ - if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ + if (_SEH3$_TryLevel == 0) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ else _SEH3$_RegisterTryLevel_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ \ /* Define an empty inline finally function */ \ @@ -442,10 +456,10 @@ _Pragma("GCC diagnostic pop") \ _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$_FINALLY(&_SEH3$_FinallyFunction), _SEH3$_TryLevel, _SEH3$_HANDLER_TYPE }; \ + static const SEH3$_SCOPE_TABLE __attribute__((section(".xdata$x"))) _SEH3$_ScopeTable = { (unsigned)(_SEH3$_TryLevel - 1), _SEH3$_FINALLY(&_SEH3$_FinallyFunction), 0 }; \ \ /* Register the registration record. */ \ - if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ + if (_SEH3$_TryLevel == 0) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ else _SEH3$_RegisterTryLevel_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \ _SEH3$_TrylevelFrame.ExceptionPointers = (PSEH3$_EXCEPTION_POINTERS)1; \ \