/*
* excpt.h
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is a part of the mingw-runtime package.
- * No warranty is given; refer to the file DISCLAIMER within the package.
*
- * Support for operating system level structured exception handling.
+ * Experimental support for operating system level structured handling
+ * of exceptions.
*
- * NOTE: This is very preliminary stuff. I am also pretty sure it is
- * completely Intel specific.
+ * $Id$
+ *
+ * Written by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ * Revised by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 1997, 1999, 2001-2002, 2004, 2007, 2012, 2016,
+ * MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*
*/
+#ifndef _EXCPT_H
+#pragma GCC system_header
+#define _EXCPT_H
+
+/* FIXME: this utility macro, to allocate stack space for any aggregate
+ * data type, with an explicit type cast of a pointer to that data type,
+ * deserves a place in a more universally accessible header file. The
+ * type cast is not strictly necessary for C, (but is permitted); it is
+ * essential for C++.
+ */
+#define __typecast_alloca(type) (type *)(__builtin_alloca( sizeof(type) ))
-#ifndef _EXCPT_H_
-#define _EXCPT_H_
-
-/* All the headers include this file. */
+/* All MinGW CRT headers are required to include <_mingw.h>
+ */
#include <_mingw.h>
+/* Exception handler functions require definitions of _CONTEXT, and
+ * _EXCEPTION_RECORD structures, which are provided in <windef.h>
+ */
#include <windef.h>
-/*
- * NOTE: The constants structs and typedefs below should be defined in the
- * Win32 API headers.
+#ifndef _EXCPT_W32API_H
+/* FIXME: These constants, structs, and typedefs should be defined
+ * in the Win32 API headers; (we need to establish where -- perhaps
+ * this header itself should be redesignated as a W32API header).
*/
-#define EH_NONCONTINUABLE 0x01
-#define EH_UNWINDING 0x02
-#define EH_EXIT_UNWIND 0x04
-#define EH_STACK_INVALID 0x08
-#define EH_NESTED_CALL 0x10
-
-#ifndef RC_INVOKED
-
-typedef enum {
- ExceptionContinueExecution,
- ExceptionContinueSearch,
- ExceptionNestedException,
- ExceptionCollidedUnwind
+#define EH_NONCONTINUABLE 0x01
+#define EH_UNWINDING 0x02
+#define EH_EXIT_UNWIND 0x04
+#define EH_STACK_INVALID 0x08
+#define EH_NESTED_CALL 0x10
+
+#ifndef RC_INVOKED
+
+typedef enum
+{ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
+#endif /* ! RC_INVOKED */
+#endif /* !_EXCPT_W2API_H */
-/*
- * End of stuff that should be in the Win32 API files.
- */
+#ifndef RC_INVOKED
+_BEGIN_C_DECLS
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The type of function that is expected as an exception handler to be
- * installed with __try1.
+/* The type of function that is expected as an exception handler,
+ * to be installed by the __try1(__handler) primitive.
*/
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)
- (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
+(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
-/*
- * This is not entirely necessary, but it is the structure installed by
- * the __try1 primitive below.
- */
typedef struct _EXCEPTION_REGISTRATION
-{
- struct _EXCEPTION_REGISTRATION* prev;
- PEXCEPTION_HANDLER handler;
+{ /* Maps the structure of the exception handler registration
+ * block, as installed by the __try1(__handler) primitive.
+ */
+ struct _EXCEPTION_REGISTRATION *prev;
+ PEXCEPTION_HANDLER handler;
} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
+/* Aliases which may be preferred, when referring to the
+ * EXCEPTION_REGISTRATION structure.
+ */
typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD;
typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD;
-/*
- * A macro which installs the supplied exception handler.
- * Push the pointer to the new handler onto the stack,
- * then push the pointer to the old registration structure (at fs:0)
- * onto the stack, then put a pointer to the new registration
- * structure (i.e. the current stack pointer) at fs:0.
+/* Deployment of exception handlers is facilitated by the pair
+ * of macros, __try1(_handler) and __except1.
+ *
+ * CAUTION: __try1(__handler) and __except1 must be deployed as
+ * a complementary pair, within the scope of the stack frame of
+ * a single function, with __try1(__handler) preceding the use
+ * of __except1. Failure to invoke __except1 before release of
+ * any stack frame, in which __try1(__handler) has been invoked,
+ * will invalidate the EXCEPTION_REGISTRATION_RECORD, which has
+ * been installed by __try1(_handler), at the head of the active
+ * exception handler chain; this will cause undefined behaviour,
+ * which is sure to go badly.
+ *
+ * To accommodate implementation differences between _WIN32 and
+ * _WIN64 hosts, the actual implementations of __try1(__handler)
+ * and __except1 are expressed in terms of a pair of lower level
+ * internal macros, namely:
+ *
+ * Macro: __try1_setup(__handler,__wsize,__ts)
+ *
+ * Helper for implementation of macro __try1(__handler); allocate
+ * a block of memory, within the stack frame of the calling function,
+ * which is then initialized as an EXCEPTION_REGISTRATION_RECORD, and
+ * linked to the head of the installed exception handler chain.
+ *
+ * Inputs:
+ * __handler pointer to an EXCEPTION_HANDLER function.
+ * __wsize the Intel host word size pointer description.
+ * __ts thread information segment register name.
*/
-#ifdef _WIN64
-# define __try1(pHandler) \
- __asm__ __volatile__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : \
- "g" (pHandler));
-#else
-# define __try1(pHandler) \
- __asm__ __volatile__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : \
- "g" (pHandler));
-#endif
+#define __try1_setup(__handler,__wsize,__ts) \
+{ EXCEPTION_REGISTRATION *__hook; \
+ __hook = __typecast_alloca( EXCEPTION_REGISTRATION ); \
+ __hook->handler = __handler; \
+ __asm__ __volatile__ \
+ ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t" \
+ "mov{%z1}\t{%1, %%|"__wsize" }"__ts":{|[}0x0{|], %1}" \
+ :"=r"(__hook->prev):"r"(__hook):"memory" \
+ ); \
+}
-/*
- * A macro which (despite its name) *removes* an installed
- * exception handler. Should be used only in conjunction with the above
- * install routine __try1.
- * Move the pointer to the old reg. struct (at the current stack
- * position) to fs:0, replacing the pointer we installed above,
- * then add 8 to the stack pointer to get rid of the space we
- * used when we pushed on our new reg. struct above. Notice that
- * the stack must be in the exact state at this point that it was
- * after we did __try1 or this will smash things.
+/* Macro: __except1_teardown(__wsize,__ts)
+ *
+ * Helper which provides the implementation for the __except1
+ * complement to __try1(__handler) macro; it unlinks the first
+ * EXCEPTION_REGISTRATION_RECORD from the head of the exception
+ * handler chain. Arguments are as described for those of the
+ * same name, in the __try1_setup macro argument list.
+ */
+#define __except1_teardown(__wsize,__ts) \
+{ register EXCEPTION_REGISTRATION *__hook; \
+ __asm__ __volatile__ \
+ ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t" \
+ "mov{%z0}\t{(}%0{)}, {|"__wsize" [}%0{|]}\n\t" \
+ "mov{%z0}\t{%0, %%|"__wsize" }"__ts":{|[}0x0{|], %0}" \
+ :"+r"(__hook)::"memory" \
+ ); \
+}
+
+/* Specialization of the above primitives, creating __try1(__handler),
+ * and its complementary __except1 implementation, with the appropriate
+ * assignments of word size and TIB segment register, for each of...
*/
#ifdef _WIN64
-# define __except1 \
- __asm__ __volatile__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq \
- $16,%%rsp;" : : : "%rax");
-#else
-# define __except1 \
- __asm__ __volatile__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl \
- $8,%%esp;" : : : "%eax");
-#endif
+/* ...64-bit windows, for which the word size for representation of
+ * pointers, in Intel-syntax code, is "QWORD PTR", and the gs segment
+ * is used for access to the thread information block...
+ */
+# define __try1(__handler) __try1_setup(__handler,"QWORD PTR","gs")
+# define __except1 __except1_teardown("QWORD PTR","gs")
-#ifdef __cplusplus
-}
+#else /* _WIN32 */
+/* ...while in 32-bit windows, the corresponding pointer word size
+ * is "DWORD PTR", and the the thread information block is located
+ * in the fs segment.
+ */
+# define __try1(__handler) __try1_setup(__handler,"DWORD PTR","fs")
+# define __except1 __except1_teardown("DWORD PTR","fs")
#endif
-#endif /* Not RC_INVOKED */
+_END_C_DECLS
-#endif /* _EXCPT_H_ not defined */
+#endif /* ! RC_INVOKED */
+#endif /* !_EXCPT_H: $RCSfile$: end of file */