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&a…
==============================================================================
--- 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=572…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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(a)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?re…
==============================================================================
--- 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=…
==============================================================================
--- 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(a)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(a)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