[PSEH] Add implementation for GCC amd64

Also, put include directory next to the library and use
target_include_directories(.. INTERFACE ..) to get this right.
This is because :
 - Having includes & implementation in two different places buggers me
 - This makes sure that there is no "if it compiles everything is fine" behaviour from anyone
   because now even static libraries need it for GCC amd64 build
Also add __USE_PSEH2__ define for the non SEH-aware compilers out there and use it in a few headers
where we define macros involving __try
This commit is contained in:
Jérôme Gardou 2021-04-22 11:11:34 +02:00 committed by Jérôme Gardou
parent d31856cda1
commit ba74a05a17
14 changed files with 230 additions and 50 deletions

View file

@ -8,12 +8,13 @@
#include <wine/test.h>
#undef WIN32_NO_STATUS
#include <pseh/pseh2.h>
/* See kmtests/include/kmt_test.h */
#define InvalidPointer ((PVOID)0x5555555555555555ULL)
// #define InvalidPointer ((PVOID)0x0123456789ABCDEFULL)
#ifdef __USE_PSEH2__
#include <pseh/pseh2.h>
#define StartSeh() \
{ \
NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
@ -31,6 +32,24 @@
"Exception 0x%08lx, expected 0x%08lx\n", \
ExceptionStatus, (ExpectedStatus)); \
}
#else
#define StartSeh() \
{ \
NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
__try \
{
#define EndSeh(ExpectedStatus) \
} \
__except(EXCEPTION_EXECUTE_HANDLER) \
{ \
ExceptionStatus = GetExceptionCode(); \
} \
ok(ExceptionStatus == (ExpectedStatus), \
"Exception 0x%08lx, expected 0x%08lx\n", \
ExceptionStatus, (ExpectedStatus)); \
}
#endif
#define ok_hr(status, expected) ok_hex(status, expected)
#define ok_hr_(file, line, status, expected) ok_hex_(file, line, status, expected)

View file

@ -35,6 +35,7 @@ function(setup_host_tools)
-DCMAKE_INSTALL_PREFIX=${REACTOS_BINARY_DIR}/host-tools
-DTOOLS_FOLDER=${REACTOS_BINARY_DIR}/host-tools/bin
-DGCC_PLUGIN_DIR=${GCC_PLUGIN_DIR}
-DTARGET_COMPILER_ID=${CMAKE_C_COMPILER_ID}
BUILD_ALWAYS TRUE
INSTALL_COMMAND ${CMAKE_COMMAND} -E true
BUILD_BYPRODUCTS ${HOST_TOOLS_OUTPUT}

View file

@ -5,7 +5,7 @@
#endif /* _INC_WINDOWS */
#endif
#ifndef RC_INVOKED
#if defined(__USE_PSEH2__) && !defined(RC_INVOKED)
#include <pseh/pseh2.h>
#endif
@ -122,7 +122,7 @@ typedef int RPC_STATUS;
#include <excpt.h>
#include <winerror.h>
#ifndef __GNUC__
#ifndef __USE_PSEH2__
#define RpcTryExcept __try {
#define RpcExcept(expr) } __except (expr) {
#define RpcEndExcept }

View file

@ -1,37 +0,0 @@
#ifndef KJK_PSEH2_H_
#define KJK_PSEH2_H_
#define _SEH2_TRY if(1) {
#define _SEH2_EXCEPT(...) } if(0) {
#define _SEH2_END }
#define _SEH2_YIELD(STMT_) STMT_
#define _SEH2_LEAVE
#define _SEH2_FINALLY } if(1) {
#define _SEH2_GetExceptionInformation() (GetExceptionInformation())
#define _SEH2_GetExceptionCode() (0)
#define _SEH2_AbnormalTermination() (0)
struct _EXCEPTION_RECORD;
struct _EXCEPTION_POINTERS;
struct _CONTEXT;
typedef int (__cdecl * _SEH2FrameHandler_t)
(
struct _EXCEPTION_RECORD *,
void *,
struct _CONTEXT *,
void *
);
typedef struct __SEH2Registration
{
struct __SEH2Registration * SER_Prev;
_SEH2FrameHandler_t SER_Handler;
}
_SEH2Registration_t;
#endif
/* EOF */

View file

@ -3,8 +3,10 @@
#include <setjmp.h>
#include <intrin.h>
#include <pseh/pseh2.h>
#include <pseh/excpt.h>
#ifdef __USE_PSEH2__
# include <pseh/pseh2.h>
# include <pseh/excpt.h>
#endif
#ifdef __cplusplus
extern "C" {
@ -56,6 +58,7 @@ typedef struct _WINE_EXCEPTION_REGISTRATION_RECORD
#define PEXCEPTION_REGISTRATION_RECORD PWINE_EXCEPTION_REGISTRATION_RECORD
#endif
#ifdef __USE_PSEH2__
#define __TRY _SEH2_TRY
#define __EXCEPT(func) _SEH2_EXCEPT(func(_SEH2_GetExceptionInformation()))
#define __EXCEPT_CTX(func, ctx) _SEH2_EXCEPT((func)(GetExceptionInformation(), ctx))
@ -76,7 +79,16 @@ typedef struct _WINE_EXCEPTION_REGISTRATION_RECORD
#ifndef AbnormalTermination
#define AbnormalTermination() _SEH2_AbnormalTermination()
#endif
#else
#define __TRY __try
#define __EXCEPT(func) __except(func(GetExceptionInformation()))
#define __EXCEPT_CTX(func, ctx) __except((func)(GetExceptionInformation(), ctx))
#define __EXCEPT_PAGE_FAULT __except(GetExceptionCode() == STATUS_ACCESS_VIOLATION)
#define __EXCEPT_ALL __except(1)
#define __ENDTRY
#define __FINALLY(func) __finally { func(!AbnormalTermination()); }
#define __FINALLY_CTX(func, ctx) __finally { func(!AbnormalTermination(), ctx); }
#endif
#if defined(__MINGW32__) || defined(__CYGWIN__)
#define sigjmp_buf jmp_buf

View file

@ -12,13 +12,15 @@ elseif(ARCH STREQUAL "arm")
arm/seh_prolog.s)
endif()
if(MSVC OR ARCH STREQUAL "amd64")
if(MSVC OR ((CMAKE_C_COMPILER_ID STREQUAL "Clang") AND (ARCH STREQUAL "amd64")))
list(APPEND SOURCE dummy.c)
add_asm_files(pseh_asm ${ASM_SOURCE})
add_library(pseh ${SOURCE} ${pseh_asm})
add_dependencies(pseh asm)
elseif((CMAKE_C_COMPILER_ID STREQUAL "GNU") AND (ARCH STREQUAL "amd64"))
# for GCC amd64 this is just an interface library, with our home-made plugin
add_library(pseh INTERFACE)
target_compile_options(pseh INTERFACE -fplugin=$<TARGET_FILE:native-gcc_plugin_seh>)
else()
if(USE_PSEH3)
@ -43,4 +45,13 @@ else()
target_link_libraries(pseh chkstk)
add_dependencies(pseh psdk)
target_include_directories(pseh PRIVATE include/pseh)
endif()
target_include_directories(pseh INTERFACE include)
# Make it clear that we are using PSEH2
if ((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR
((CMAKE_C_COMPILER_ID STREQUAL "Clang") AND (NOT (ARCH STREQUAL "amd64"))))
target_compile_definitions(pseh INTERFACE __USE_PSEH2__)
endif()

View file

@ -37,6 +37,10 @@
#define _SEH2_LEAVE __leave
#define _SEH2_VOLATILE
#elif defined(__GNUC__) && !defined(__clang__) && defined(_M_AMD64)
#include "pseh2_64.h"
#elif defined(_USE_DUMMY_PSEH) || defined (__arm__) || defined(_M_AMD64)
extern int _SEH2_Volatile0;

View file

@ -0,0 +1,169 @@
#pragma once
/* Declare our global trampoline function for filter and unwinder */
__asm__(
".p2align 4, 0x90\n"
".seh_proc __seh2_global_filter_func\n"
"__seh2_global_filter_func:\n"
"\tpush %rbp\n"
"\t.seh_pushreg %rbp\n"
"\tsub $32, %rsp\n"
"\t.seh_stackalloc 32\n"
"\t.seh_endprologue\n"
/* Restore frame pointer. */
"\tmov %rdx, %rbp\n"
/* Actually execute the filter funclet */
"\tjmp *%rax\n"
"__seh2_global_filter_func_exit:\n"
"\t.p2align 4\n"
"\tadd $32, %rsp\n"
"\tpop %rbp\n"
"\tret\n"
"\t.seh_endproc");
#define _SEH2_TRY \
{ \
__label__ __seh2$$begin_try__; \
__label__ __seh2$$end_try__; \
/* \
* We close the current SEH block for this function and install our own. \
* At this point GCC emitted its prologue, and if it saves more \
* registers, the relevant instruction will be valid for our scope as well. \
* We also count the number of try blocks at assembly level \
* to properly set the handler data when we're done. \
*/ \
__seh2$$begin_try__: \
{ \
__label__ __seh2$$leave_scope__;
#define _SEH2_EXCEPT(...) \
__seh2$$leave_scope__: __MINGW_ATTRIB_UNUSED; \
} \
__seh2$$end_try__: \
/* Call our home-made pragma */ \
_Pragma("REACTOS seh(except)") \
if (0) \
{ \
__label__ __seh2$$leave_scope__; \
__label__ __seh2$$filter__; \
__label__ __seh2$$begin_except__; \
LONG __MINGW_ATTRIB_UNUSED __seh2$$exception_code__ = 0; \
/* Add our handlers to the list */ \
__asm__ __volatile__ goto ("\n" \
"\t.seh_handlerdata\n" \
"\t.rva %l0\n" /* Begin of tried code */ \
"\t.rva %l1 + 1\n" /* End of tried code */ \
"\t.rva %l2\n" /* Filter function */ \
"\t.rva %l3\n" /* Called on except */ \
"\t.seh_code\n" \
: /* No output */ \
: /* No input */ \
: /* No clobber */ \
: __seh2$$begin_try__, \
__seh2$$end_try__, \
__seh2$$filter__, \
__seh2$$begin_except__); \
if (0) \
{ \
/* Jump to the global filter. Tell it where the filter funclet lies */ \
__label__ __seh2$$filter_funclet__; \
__seh2$$filter__: \
__asm__ __volatile__ goto( \
"\tleaq %l0(%%rip), %%rax\n" \
"\tjmp __seh2_global_filter_func\n" \
: /* No output */ \
: /* No input */ \
: "%rax" \
: __seh2$$filter_funclet__); \
/* Actually declare our filter funclet */ \
struct _EXCEPTION_POINTERS* __seh2$$exception_ptr__; \
__seh2$$filter_funclet__: \
/* At this point, the compiler can't count on any register being valid */ \
__asm__ __volatile__("" \
: "=c"(__seh2$$exception_ptr__) /* First argument of the filter function */ \
: /* No input */ \
: /* Everything */ \
"%rax", "%rbx","%rdx", "%rdi", "%rsi", \
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"); \
/* Save exception code */ \
__seh2$$exception_code__ = __seh2$$exception_ptr__->ExceptionRecord->ExceptionCode; \
/* Actually evaluate our filter */ \
register long __MINGW_ATTRIB_UNUSED __seh2$$filter_funclet_ret __asm__("eax") = \
((__VA_ARGS__)); \
/* Go back to the global filter function */ \
__asm__("jmp __seh2_global_filter_func_exit"); \
} \
/* Protect us from emitting instructions to jump back to the filter function */ \
enum \
{ \
__seh2$$abnormal_termination__ = 0 \
}; \
__seh2$$begin_except__:
#define _SEH2_FINALLY \
__seh2$$leave_scope__: __MINGW_ATTRIB_UNUSED; \
} \
__seh2$$end_try__: \
/* Call our home-made pragma */ \
_Pragma("REACTOS seh(finally)") \
if (1) \
{ \
__label__ __seh2$$finally__; \
__label__ __seh2$$begin_finally__; \
__label__ __seh2$$leave_scope__; \
int __seh2$$abnormal_termination__; \
/* Add our handlers to the list */ \
__asm__ __volatile__ goto ("\n" \
"\t.seh_handlerdata\n" \
"\t.rva %l0\n" /* Begin of tried code */ \
"\t.rva %l1 + 1\n" /* End of tried code */ \
"\t.rva %l2\n" /* Filter function */ \
"\t.long 0\n" /* Nothing for unwind code */ \
"\t.seh_code\n" \
: /* No output */ \
: /* No input */ \
: /* No clobber */ \
: __seh2$$begin_try__, \
__seh2$$end_try__, \
__seh2$$finally__); \
if (0) \
{ \
/* Jump to the global trampoline. Tell it where the unwind code really lies */ \
__seh2$$finally__: \
__asm__ __volatile__ goto( \
"\tleaq %l0(%%rip), %%rax\n" \
"\tjmp __seh2_global_filter_func\n" \
: /* No output */ \
: /* No input */ \
: /* No clobber */ \
: __seh2$$begin_finally__); \
} \
\
/* Zero-out rcx to indicate normal termination */ \
__asm__ __volatile__("xor %%rcx, %%rcx" \
: /* No output */ \
: /* No input */ \
: /* Everything - We might come from __C_specific_handler here */ \
"%rax", "%rbx", "%rcx", "%rdx", "%rdi", "%rsi", \
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"); \
/* Actually declare our finally funclet */ \
__seh2$$begin_finally__: \
__asm__ __volatile__("" \
: "=c" (__seh2$$abnormal_termination__));
#define _SEH2_END \
__seh2$$leave_scope__: __MINGW_ATTRIB_UNUSED; \
if (__seh2$$abnormal_termination__) \
{ \
__asm__("jmp __seh2_global_filter_func_exit"); \
} \
} \
}
#define _SEH2_GetExceptionInformation() __seh2$$exception_ptr__
#define _SEH2_GetExceptionCode() __seh2$$exception_code__
#define _SEH2_AbnormalTermination() __seh2$$abnormal_termination__
#define _SEH2_LEAVE goto __seh2$$leave_scope__
#define _SEH2_YIELD(__stmt) __stmt
#define _SEH2_VOLATILE volatile

View file

@ -40,12 +40,13 @@ add_subdirectory(widl)
add_subdirectory(wpp)
add_subdirectory(xml2sdb)
if ((ARCH STREQUAL "amd64") AND (TARGET_COMPILER_ID STREQUAL "GNU"))
add_subdirectory(gcc_plugin_seh)
endif()
if(NOT MSVC)
add_subdirectory(log2lines)
add_subdirectory(rsym)
if (ARCH STREQUAL "amd64")
add_subdirectory(gcc_plugin_seh)
endif()
add_host_tool(pefixup pefixup.c)
if (ARCH STREQUAL "amd64")