[PSEH] Make structures more SEH3 compatible

This commit is contained in:
Timo Kreuzer 2025-07-04 20:06:19 +03:00
parent 6d2eb03402
commit d23ee5f365
4 changed files with 137 additions and 69 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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; \
\