mirror of
https://github.com/reactos/reactos.git
synced 2025-04-05 21:21:33 +00:00
[PSEH3]
Implement PSEH 3.0. Currently disabled by default. Dedicated to Amine Khaldi. svn path=/trunk/; revision=57259
This commit is contained in:
parent
0d50ee63ce
commit
59f075b683
8 changed files with 684 additions and 5 deletions
|
@ -122,6 +122,10 @@ else()
|
|||
add_definitions(-D_WINKD_=1)
|
||||
endif()
|
||||
|
||||
if(USE_PSEH3)
|
||||
add_definitions(-D_USE_PSEH3=1)
|
||||
endif()
|
||||
|
||||
# Version Options
|
||||
add_definitions(-DWINVER=0x502
|
||||
-D_WIN32_IE=0x600
|
||||
|
|
|
@ -44,7 +44,7 @@ if(MSVC)
|
|||
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(_PREFAST_ FALSE CACHE BOOL
|
|||
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()
|
||||
|
|
|
@ -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 } {
|
||||
|
@ -48,6 +48,21 @@
|
|||
#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__)
|
||||
|
||||
struct _EXCEPTION_RECORD;
|
||||
|
|
292
reactos/include/reactos/libs/pseh/pseh3.h
Normal file
292
reactos/include/reactos/libs/pseh/pseh3.h
Normal file
|
@ -0,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
|
||||
|
|
@ -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
|
||||
|
|
275
reactos/lib/pseh/i386/pseh3.c
Normal file
275
reactos/lib/pseh/i386/pseh3.c
Normal file
|
@ -0,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);
|
||||
}
|
||||
|
12
reactos/lib/pseh/i386/pseh3_asmdef.h
Normal file
12
reactos/lib/pseh/i386/pseh3_asmdef.h
Normal file
|
@ -0,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
|
72
reactos/lib/pseh/i386/pseh3_i386.S
Normal file
72
reactos/lib/pseh/i386/pseh3_i386.S
Normal file
|
@ -0,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
|
||||
|
||||
|
Loading…
Reference in a new issue