This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch/RFC] SEH exceptions for Win64


Hi,

this is a rebase of RTH's patch posted a few years ago.  It is almost unchanged, except that there is no SEH specific unwind.h header (there are 3 #if/#endif part in unwind-generic.h) and a minor cleanup in unwind-seh.c (indentation, unused variables).

This patch allows to propagate GCC exceptions through any code (including code produced by msvc), but to my knowledge propagation of msvc exceptions through gcc code doesn't work (because we cancel the exception to run cleanups).

We have tested it heavily in our infrastructure and found no issues in that part.  We had to write a specific personality routine for Ada to handle stack checking and access violation in user code; but as far as I know this is not needed by c++.

I did a manual build and testing for x86_64-pc-mingw32 and I will run a full bootstrap and regression run on GNU/Linux.

Tristan.

libstdc++-v3/
	* libsupc++/eh_personality.cc (__gxx_personality_seh0): New function.
	Adjust for SEH.
	* config/abi/pre/gnu.ver: Add __gxx_personality_seh0.

libobjc/
	* exception.c (__gnu_objc_personality_seh0): New function.

libjava/
	* libgcj.ver: Add __gcj_personality_seh0.
	* exception.cc (__gcj_personality_seh0): New function.
	Adjust for SEH.

libgcc/
	* unwind-seh.c: New file.
	* unwind-generic.h: Include windows.h for SEH.
	(_Unwind_Exception): Use 6 private fields for SEH.
	(_GCC_specific_handler): Declare.
	* unwind-c.c (__gcc_personality_seh0): New function.
	Adjust for SEH.
	* config/i386/libgcc-cygming.ver: New file.
	* config/i386/t-seh-eh: New file.
	* config.host (x86_64-*-mingw*): Default to seh.

gcc/
	* opts.c (finish_options): Handle UI_SEH.
	* expr.c (build_personality_function): Handle UI_SEH.
	* dwarf2out.c (dwarf2out_begin_prologue): Handle UI_SEH.
	* coretypes.h (unwind_info_type): Add UI_SEH.
	* config/i386/winnt.c (i386_pe_seh_emit_except_personality):
	New function.
	(i386_pe_seh_init_sections): Likewise.
	* config/i386/cygming.h (TARGET_ASM_EMIT_EXCEPT_PERSONALITY): Define.
	(TARGET_ASM_INIT_SECTIONS): Define.
	* common/config/i386/i386-common.c (TARGET_EXCEPT_UNWIND_INFO): Define.
	(i386_except_unwind_info): New function.

diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c
index 70b7eb7..1fe04a6 100644
--- a/gcc/common/config/i386/i386-common.c
+++ b/gcc/common/config/i386/i386-common.c
@@ -667,6 +667,30 @@ ix86_supports_split_stack (bool report ATTRIBUTE_UNUSED,
   return ret;
 }
 
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+static enum unwind_info_type
+i386_except_unwind_info (struct gcc_options *opts)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* On windows 64, prefer SEH exceptions over anything else.  */
+  if (TARGET_64BIT && DEFAULT_ABI == MS_ABI && opts->x_flag_unwind_tables)
+    return UI_SEH;
+
+  if (DWARF2_UNWIND_INFO)
+    return UI_DWARF2;
+
+  return UI_SJLJ;
+}
+
+#undef  TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  i386_except_unwind_info
+
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS	\
   (TARGET_DEFAULT			\
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index b5f89c4..8455a67 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -48,6 +48,10 @@ along with GCC; see the file COPYING3.  If not see
 #define TARGET_ASM_UNWIND_EMIT_BEFORE_INSN  false
 #undef  TARGET_ASM_FUNCTION_END_PROLOGUE
 #define TARGET_ASM_FUNCTION_END_PROLOGUE  i386_pe_seh_end_prologue
+#undef  TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY i386_pe_seh_emit_except_personality
+#undef  TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS  i386_pe_seh_init_sections
 #define SUBTARGET_ASM_UNWIND_INIT  i386_pe_seh_init
 
 #undef DEFAULT_ABI
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index fe733b0..49e6bbd 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -258,6 +258,8 @@ extern tree i386_pe_mangle_assembler_name (const char *);
 extern void i386_pe_seh_init (FILE *);
 extern void i386_pe_seh_end_prologue (FILE *);
 extern void i386_pe_seh_unwind_emit (FILE *, rtx);
+extern void i386_pe_seh_emit_except_personality (rtx);
+extern void i386_pe_seh_init_sections (void);
 
 /* In winnt-cxx.c and winnt-stubs.c  */
 extern void i386_pe_adjust_class_at_definition (tree);
diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c
index 5b71ccb..17ee137 100644
--- a/gcc/config/i386/winnt.c
+++ b/gcc/config/i386/winnt.c
@@ -1143,6 +1143,48 @@ i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
  found:
   seh_frame_related_expr (asm_out_file, seh, pat);
 }
+
+void
+i386_pe_seh_emit_except_personality (rtx personality)
+{
+  int flags = 0;
+
+  if (!TARGET_SEH)
+    return;
+
+  fputs ("\t.seh_handler\t", asm_out_file);
+  output_addr_const (asm_out_file, personality);
+
+#if 0
+  /* ??? The current implementation of _GCC_specific_handler requires
+     both except and unwind handling, regardless of which sorts the
+     user-level function requires.  */
+  eh_region r;
+  FOR_ALL_EH_REGION(r)
+    {
+      if (r->type == ERT_CLEANUP)
+	flags |= 1;
+      else
+	flags |= 2;
+    }
+#else
+  flags = 3;
+#endif
+
+  if (flags & 1)
+    fputs (", @unwind", asm_out_file);
+  if (flags & 2)
+    fputs (", @except", asm_out_file);
+  fputc ('\n', asm_out_file);
+}
+
+void
+i386_pe_seh_init_sections (void)
+{
+  if (TARGET_SEH)
+    exception_section = get_unnamed_section (0, output_section_asm_op,
+					     "\t.seh_handlerdata");
+}
 

 void
 i386_pe_start_function (FILE *f, const char *name, tree decl)
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 7e5c048..02578f6 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -116,7 +116,8 @@ enum unwind_info_type
   UI_NONE,
   UI_SJLJ,
   UI_DWARF2,
-  UI_TARGET
+  UI_TARGET,
+  UI_SEH
 };
 
 /* Callgraph node profile representation.  */
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 1fc76fe..dcf8c90 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -977,7 +977,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
      call-site information.  We must emit this label if it might be used.  */
   if (!do_frame
       && (!flag_exceptions
-	  || targetm_common.except_unwind_info (&global_options) != UI_TARGET))
+	  || targetm_common.except_unwind_info (&global_options) == UI_SJLJ))
     return;
 
   fnsec = function_section (current_function_decl);
diff --git a/gcc/expr.c b/gcc/expr.c
index 916dee0..b2ab32a 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -11053,6 +11053,9 @@ build_personality_function (const char *lang)
     case UI_TARGET:
       unwind_and_version = "_v0";
       break;
+    case UI_SEH:
+      unwind_and_version = "_seh0";
+      break;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/opts.c b/gcc/opts.c
index d189e90..e52db68 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -715,7 +715,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 
   if (opts->x_flag_exceptions
       && opts->x_flag_reorder_blocks_and_partition
-      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
+      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))
     {
       inform (loc,
 	      "-freorder-blocks-and-partition does not work "
@@ -730,7 +730,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_flag_unwind_tables
       && !targetm_common.unwind_tables_default
       && opts->x_flag_reorder_blocks_and_partition
-      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
+      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))
     {
       inform (loc,
 	      "-freorder-blocks-and-partition does not support "
@@ -747,7 +747,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
       && (!targetm_common.have_named_sections
 	  || (opts->x_flag_unwind_tables
 	      && targetm_common.unwind_tables_default
-	      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))))
+	      && (ui_except == UI_SJLJ || ui_except >= UI_TARGET))))
     {
       inform (loc,
 	      "-freorder-blocks-and-partition does not work "
diff --git a/libgcc/config.host b/libgcc/config.host
index d8ad48c..2615d87 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -618,7 +618,7 @@ x86_64-*-mingw*)
 	if test x$enable_sjlj_exceptions = xyes; then
 		tmake_eh_file="i386/t-sjlj-eh"
 	else
-		tmake_eh_file="i386/t-dw2-eh"
+		tmake_eh_file="i386/t-seh-eh"
 	fi
 	# Shared libgcc DLL install dir depends on cross/native build.
 	if test x${build} = x${host} ; then
diff --git a/libgcc/config/i386/libgcc-cygming.ver b/libgcc/config/i386/libgcc-cygming.ver
new file mode 100644
index 0000000..8966cfb
--- /dev/null
+++ b/libgcc/config/i386/libgcc-cygming.ver
@@ -0,0 +1,22 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+GCC_4.8 {
+  _GCC_specific_handler
+  __gcc_personality_seh0
+}
diff --git a/libgcc/config/i386/t-seh-eh b/libgcc/config/i386/t-seh-eh
new file mode 100644
index 0000000..066ca54
--- /dev/null
+++ b/libgcc/config/i386/t-seh-eh
@@ -0,0 +1,6 @@
+
+# We are using SEH EH.
+EH_MODEL = seh
+
+# Use SEH exception handling.
+LIB2ADDEH = $(srcdir)/unwind-seh.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
diff --git a/libgcc/config/i386/t-slibgcc-cygming b/libgcc/config/i386/t-slibgcc-cygming
index 3bee8b9..6236c78 100644
--- a/libgcc/config/i386/t-slibgcc-cygming
+++ b/libgcc/config/i386/t-slibgcc-cygming
@@ -55,4 +55,4 @@ SHLIB_MKMAP = $(srcdir)/mkmap-flat.awk
 # We'd like to use SHLIB_SONAME here too, but shlib_base_name
 # does not get substituted before mkmap-flat.awk is run.
 SHLIB_MKMAP_OPTS = -v pe_dll=libgcc_s_$(EH_MODEL)-$(SHLIB_SOVERSION)$(SHLIB_EXT)
-SHLIB_MAPFILES = libgcc-std.ver
+SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-cygming.ver
diff --git a/libgcc/unwind-c.c b/libgcc/unwind-c.c
index bd4941d..eb50ad8 100644
--- a/libgcc/unwind-c.c
+++ b/libgcc/unwind-c.c
@@ -93,6 +93,8 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
 #ifdef __USING_SJLJ_EXCEPTIONS__
 #define PERSONALITY_FUNCTION    __gcc_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gcc_personality_imp
 #else
 #define PERSONALITY_FUNCTION    __gcc_personality_v0
 #endif
@@ -107,6 +109,9 @@ PERSONALITY_FUNCTION (_Unwind_State state,
 		      struct _Unwind_Exception * ue_header,
 		      struct _Unwind_Context * context)
 #else
+#ifdef __SEH__
+static
+#endif
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
 		      struct _Unwind_Exception *, struct _Unwind_Context *);
@@ -227,3 +232,13 @@ PERSONALITY_FUNCTION (int version,
   _Unwind_SetIP (context, landing_pad);
   return _URC_INSTALL_CONTEXT;
 }
+
+#ifdef __SEH__
+EXCEPTION_DISPOSITION
+__gcc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gcc_personality_imp);
+}
+#endif /* SEH */
diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h
index 4ff9017..c9c993b 100644
--- a/libgcc/unwind-generic.h
+++ b/libgcc/unwind-generic.h
@@ -28,6 +28,11 @@
 #ifndef _UNWIND_H
 #define _UNWIND_H
 
+#ifdef __SEH__
+/* Only for _GCC_specific_handler.  */
+#include <windows.h>
+#endif
+
 #ifndef HIDE_EXPORTS
 #pragma GCC visibility push(default)
 #endif
@@ -86,8 +91,13 @@ struct _Unwind_Exception
 {
   _Unwind_Exception_Class exception_class;
   _Unwind_Exception_Cleanup_Fn exception_cleanup;
+
+#if !defined (__USING_SJLJ_EXCEPTIONS__) && defined (__SEH__)
+  _Unwind_Word private_[6];
+#else
   _Unwind_Word private_1;
   _Unwind_Word private_2;
+#endif
 
   /* @@@ The IA-64 ABI says that this structure must be double-word aligned.
      Taking that literally does not make much sense generically.  Instead we
@@ -265,6 +275,13 @@ extern void * _Unwind_FindEnclosingFunction (void *pc);
 # error "What type shall we use for _sleb128_t?"
 #endif
 
+#ifdef __SEH__
+/* Handles the mapping from SEH to GCC interfaces.  */
+EXCEPTION_DISPOSITION _GCC_specific_handler (PEXCEPTION_RECORD, void *,
+					     PCONTEXT, PDISPATCHER_CONTEXT,
+					     _Unwind_Personality_Fn);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libgcc/unwind-seh.c b/libgcc/unwind-seh.c
new file mode 100644
index 0000000..e7fa886
--- /dev/null
+++ b/libgcc/unwind-seh.c
@@ -0,0 +1,482 @@
+/* Structured Exception Handling (SEH) runtime interface routines.
+   Copyright (C) 2010  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "unwind.h"
+
+#ifdef __SEH__
+
+/* At the moment everything is written for x64, but in theory this could
+   also be used for i386, arm, mips and other extant embedded Windows.  */
+#ifndef __x86_64__
+#error "Unsupported architecture."
+#endif
+

+/* Define GCC's exception codes.  See
+     http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx
+   In particular, MS defines bits:
+     [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
+     [29]    = 1 (user-defined)
+     [28]    = 0 (reserved)
+   We define bits:
+     [24:27] = type
+     [0:23]  = magic
+   We set "magic" to "GCC", which is similar to MVC++ which uses "msc"
+   as the low 3 bytes of its user-defined codes for C++ exceptions.
+
+   We define the ExceptionInformation entries as follows:
+     [0] = _Unwind_Exception pointer
+     [1] = target frame
+     [2] = target ip
+     [3] = target rdx
+*/
+
+#define STATUS_USER_DEFINED		(1U << 29)
+
+#define GCC_MAGIC			(('G' << 16) | ('C' << 8) | 'C')
+#define GCC_EXCEPTION(TYPE)		\
+       (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC)
+
+#define STATUS_GCC_THROW		GCC_EXCEPTION (0)
+#define STATUS_GCC_UNWIND		GCC_EXCEPTION (1)
+#define STATUS_GCC_FORCED		GCC_EXCEPTION (2)
+
+

+struct _Unwind_Context
+{
+  _Unwind_Word cfa;
+  _Unwind_Word ra;
+  _Unwind_Word reg[2];
+  PDISPATCHER_CONTEXT disp;
+};
+
+/* Get the value of register INDEX as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *c, int index)
+{
+  if (index < 0 || index > 2)
+    abort ();
+  return c->reg[index];
+}
+
+/* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
+
+void
+_Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val)
+{
+  if (index < 0 || index > 2)
+    abort ();
+  c->reg[index] = val;
+}
+
+/* Get the value of the CFA as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *c)
+{
+  return c->cfa;
+}
+
+/* Retrieve the return address for CONTEXT.  */
+
+_Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *c)
+{
+  return c->ra;
+}
+
+/* Retrieve the return address and flag whether that IP is before
+   or after first not yet fully executed instruction.  */
+
+_Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn)
+{
+  /* ??? Is there a concept of a signal context properly?  There's
+     obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might
+     have arranged for that not to matter, really.  */
+  *ip_before_insn = 0;
+  return c->ra;
+}
+
+/* Overwrite the return address for CONTEXT with VAL.  */
+
+void
+_Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val)
+{
+  c->ra = val;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *c)
+{
+  return c->disp->HandlerData;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *c)
+{
+  return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase;
+}
+
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+  PRUNTIME_FUNCTION entry;
+  ULONG64 ImageBase;
+
+  entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL);
+
+  return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL);
+}
+
+_Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *c)
+{
+  return c->disp->ImageBase;
+}
+
+

+/* The two-phase unwind process that GCC uses is ordered differently
+   from the two-phase unwind process that SEH uses.  The mechansism
+   that GCC uses is to have the filter return _URC_HANDER_FOUND; the
+   mechanism that SEH uses is for the filter function call back into
+   the unwinder.
+
+   An Ideal port to SEH would have GCC emit handler functions that
+   can be called, given a pointer to the "EstablisherFrame" (i.e.
+   the frame pointer base of the user-level function) can manipulate
+   the user-level variables within the user-level function's stack
+   frame.  Once done manipulating the variables, it would return
+   a ExceptionContinueSearch, and the unwind process would continue.
+
+   GCC has always done things a bit differently.  We continue to
+   transfer control back into the user-level function which, once
+   done manipulating the user-level variables, re-throws the exception.  */
+
+/* The "real" language-specific personality handler forwards to here
+   where we handle the MS SEH state and transforms it into the GCC
+   unwind state as per GCC's <unwind.h>, at which point we defer to
+   the regular language-specfic exception handler, which is passed in.  */
+
+EXCEPTION_DISPOSITION
+_GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame,
+		       PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp,
+		       _Unwind_Personality_Fn gcc_per)
+{
+  DWORD ms_flags = ms_exc->ExceptionFlags;
+  DWORD ms_code = ms_exc->ExceptionCode;
+
+  struct _Unwind_Exception *gcc_exc
+    = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0];
+  struct _Unwind_Context gcc_context;
+  _Unwind_Action gcc_action;
+  _Unwind_Reason_Code gcc_reason;
+
+  if (ms_flags & EXCEPTION_TARGET_UNWIND)
+    {
+      /* This frame is known to be the target frame.  We've already
+         "installed" the target_ip and RAX value via the arguments
+         to RtlUnwindEx.  All that's left is to set the RDX value
+         and "continue" to have the context installed.  */
+      ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
+      return ExceptionContinueSearch;
+    }
+
+  if (ms_code == STATUS_GCC_UNWIND)
+    {
+      /* This is a colliding exception that we threw so that we could
+         cancel the already in-flight exception and stop in a frame
+	 that wanted to perform some unwind action.  The only relevant
+	 test is that we're the target frame.  */
+      if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame)
+	{
+	  RtlUnwindEx (this_frame, ms_exc->ExceptionInformation[2],
+		       ms_exc, gcc_exc, ms_orig_context,
+		       ms_disp->HistoryTable);
+	  abort ();
+	}
+      return ExceptionContinueSearch;
+    }
+
+  gcc_context.cfa = ms_disp->ContextRecord->Rsp;
+  gcc_context.ra = ms_disp->ControlPc;
+  gcc_context.reg[0] = 0xdeadbeef;	/* These are write-only.  */
+  gcc_context.reg[1] = 0xdeadbeef;
+  gcc_context.disp = ms_disp;
+
+  if (ms_code == STATUS_GCC_FORCED)
+    {
+       _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0];
+       void *stop_argument = (void *) gcc_exc->private_[4];
+
+       gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE;
+
+       stop (1, gcc_action, gcc_exc->exception_class, gcc_exc,
+             &gcc_context, stop_argument);
+
+       goto phase2;
+    }
+
+  /* ??? TODO: handling non-gcc user-defined exceptions as foreign.  */
+  if (ms_code != STATUS_GCC_THROW)
+    return ExceptionContinueSearch;
+
+  if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
+    {
+      /* This is Phase 2.  */
+      /* We know this isn't the target frame because we've already tested
+	 EXCEPTION_TARGET_UNWIND.  The remaining possibility is that the
+	 gcc personality has unwind code to run.  */
+
+      gcc_action = _UA_CLEANUP_PHASE;
+    phase2:
+      gcc_reason = gcc_per (1, gcc_action, gcc_exc->exception_class,
+			    gcc_exc, &gcc_context);
+
+      if (gcc_reason == _URC_CONTINUE_UNWIND)
+	return ExceptionContinueSearch;
+
+      if (gcc_reason == _URC_INSTALL_CONTEXT)
+	{
+	  /* Scratch space for the bits for the unwind catch.  */
+	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
+	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
+	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
+
+	  /* Cancel the current exception by raising another.  */
+	  RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE,
+			  4, ms_exc->ExceptionInformation);
+
+	  /* Is RaiseException declared noreturn?  */
+	}
+
+      /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */
+    }
+  else
+    {
+      /* This is Phase 1.  */
+      gcc_reason = gcc_per (1, _UA_SEARCH_PHASE, gcc_exc->exception_class,
+			    gcc_exc, &gcc_context);
+
+      if (gcc_reason == _URC_CONTINUE_UNWIND)
+	return ExceptionContinueSearch;
+
+      if (gcc_reason == _URC_HANDLER_FOUND)
+	{
+	  /* We really need some of the information that GCC's personality
+	     routines compute during phase 2 right now, like the target IP.
+	     Go ahead and ask for it now, and cache it.  */
+	  gcc_reason = gcc_per (1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME,
+				gcc_exc->exception_class, gcc_exc,
+				&gcc_context);
+	  if (gcc_reason != _URC_INSTALL_CONTEXT)
+	    abort ();
+
+	  gcc_exc->private_[1] = (_Unwind_Ptr) this_frame;
+	  gcc_exc->private_[2] = gcc_context.ra;
+	  gcc_exc->private_[3] = gcc_context.reg[1];
+
+	  ms_exc->NumberParameters = 4;
+	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
+	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
+	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
+
+	  /* Begin phase 2.  Perform the unwinding.  */
+	  RtlUnwindEx (this_frame, gcc_context.ra, ms_exc, gcc_exc,
+		       ms_orig_context, ms_disp->HistoryTable);
+	}
+
+      /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR.  */
+    }
+  abort ();
+}
+
+/* Raise an exception, passing along the given exception object.  */
+
+_Unwind_Reason_Code
+_Unwind_RaiseException (struct _Unwind_Exception *exc)
+{
+  memset (exc->private_, 0, sizeof (exc->private_));
+
+  RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc);
+
+  /* The exception handler installed in crt0 will continue any GCC
+     exception that reaches there (and isn't marked non-continuable).
+     Returning allows the C++ runtime to call std::terminate.  */
+  return _URC_END_OF_STACK;
+}
+
+/* Resume propagation of an existing exception.  This is used after
+   e.g. executing cleanup code, and not to implement rethrowing.  */
+
+void
+_Unwind_Resume (struct _Unwind_Exception *gcc_exc)
+{
+  UNWIND_HISTORY_TABLE ms_history;
+  EXCEPTION_RECORD ms_exc;
+  CONTEXT ms_context;
+
+  memset (&ms_exc, 0, sizeof(ms_exc));
+  memset (&ms_history, 0, sizeof(ms_history));
+
+  /* ??? Not 100% perfect, since we aren't passing on the *original*
+     exception context, but should be good enough.  */
+  ms_exc.ExceptionCode = STATUS_GCC_THROW;
+  ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
+  ms_exc.NumberParameters = 4;
+  ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc;
+  ms_exc.ExceptionInformation[1] = gcc_exc->private_[1];
+  ms_exc.ExceptionInformation[2] = gcc_exc->private_[2];
+  ms_exc.ExceptionInformation[3] = gcc_exc->private_[3];
+
+  ms_context.ContextFlags = CONTEXT_ALL;
+  RtlCaptureContext (&ms_context);
+
+  RtlUnwindEx ((void *) gcc_exc->private_[1], gcc_exc->private_[2],
+	       &ms_exc, gcc_exc, &ms_context, &ms_history);
+
+  /* Is RtlUnwindEx declared noreturn?  */
+  abort ();
+}
+
+static _Unwind_Reason_Code
+_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc)
+{
+  _Unwind_Stop_Fn stop;
+  void * stop_argument;
+
+  RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc);
+
+  /* If we get here, we got to top-of-stack.  */
+  /* ??? We no longer have a context pointer to pass in.  */
+
+  stop = (_Unwind_Stop_Fn) exc->private_[0];
+  stop_argument = (void *) exc->private_[4];
+  stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK,
+	exc->exception_class, exc, NULL, stop_argument);
+
+  return _UA_END_OF_STACK;
+}
+
+_Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc)
+{
+  if (exc->private_[0] == 0)
+    _Unwind_RaiseException (exc);
+  else
+    _Unwind_ForcedUnwind_Phase2 (exc);
+  abort ();
+}
+
+/* Raise an exception for forced unwinding.  */
+
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
+		      _Unwind_Stop_Fn stop, void * stop_argument)
+{
+  /* ??? This is a hack that only works with _GCC_specific_handler.
+     There's no way to invoke STOP within frames that use a different
+     exception handler.  This is essentially just good enough to run
+     the code within the gcc testsuite.  */
+
+  memset (exc->private_, 0, sizeof (exc->private_));
+  exc->private_[0] = (_Unwind_Ptr) stop;
+  exc->private_[4] = (_Unwind_Ptr) stop_argument;
+
+  return _Unwind_ForcedUnwind_Phase2 (exc);
+}
+
+/* A convenience function that calls the exception_cleanup field.  */
+
+void
+_Unwind_DeleteException (struct _Unwind_Exception *exc)
+{
+  if (exc->exception_cleanup)
+    (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+/* Perform stack backtrace through unwind data.  */
+
+_Unwind_Reason_Code
+_Unwind_Backtrace(_Unwind_Trace_Fn trace ATTRIBUTE_UNUSED,
+		  void *trace_argument ATTRIBUTE_UNUSED)
+{
+#if 0
+  UNWIND_HISTORY_TABLE ms_history;
+  CONTEXT ms_context;
+  struct _Unwind_Context gcc_context;
+
+  memset (&ms_history, 0, sizeof(ms_history));
+  memset (&gcc_context, 0, sizeof(gcc_context));
+
+  ms_context.ContextFlags = CONTEXT_ALL;
+  RtlCaptureContext (&ms_context);
+
+  gcc_context.disp.ContextRecord = &ms_context;
+  gcc_context.disp.HistoryTable = &ms_history;
+
+  while (1)
+    {
+      gcc_context.disp.ControlPc = ms_context.Rip;
+      gcc_context.disp.FunctionEntry
+	= RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp.ImageBase,
+				  &ms_history);
+
+      if (gcc_context.disp.FunctionEntry)
+	{
+	  gcc_context.disp.LanguageHandler
+	    = RtlVirtualUnwind (0, gcc_context.disp.ImageBase, ms_context.Rip,
+				gcc_context.disp.FunctionEntry, &ms_context,
+				&gcc_context.disp.HandlerData,
+				&gcc_context.disp.EstablisherFrame, NULL);
+	}
+      else
+	{
+	  ms_context.Rip = *(ULONG_PTR *)ms_context.Rsp;
+	  ms_context.Rsp += 8;
+	}
+
+      /* Call trace function.  */
+      if (trace (&gcc_context, trace_argument) != _URC_NO_REASON)
+	return _URC_FATAL_PHASE1_ERROR;
+
+      /* ??? Check for invalid stack pointer.  */
+      if (ms_context.Rip == 0)
+	return _URC_END_OF_STACK;
+    }
+#else
+  return _URC_END_OF_STACK;
+#endif
+}
+#endif /* __SEH__ */
diff --git a/libjava/exception.cc b/libjava/exception.cc
index 56f25ad..cc5ab7c 100644
--- a/libjava/exception.cc
+++ b/libjava/exception.cc
@@ -197,6 +197,8 @@ get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
 #ifdef SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gcj_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined (__SEH__)
+#define PERSONALITY_FUNCTION	__gcj_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gcj_personality_v0
 #endif
@@ -220,7 +222,12 @@ PERSONALITY_FUNCTION (_Unwind_State state,
 
 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
 
-extern "C" _Unwind_Reason_Code
+#ifdef __SEH__
+static
+#else
+extern "C"
+#endif
+_Unwind_Reason_Code
 PERSONALITY_FUNCTION (int version,
 		      _Unwind_Action actions,
 		      _Unwind_Exception_Class exception_class,
@@ -484,3 +491,14 @@ PERSONALITY_FUNCTION (int version,
 #endif
   return _URC_INSTALL_CONTEXT;
 }
+
+#ifdef __SEH__
+extern "C"
+EXCEPTION_DISPOSITION
+__gcj_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gcj_personality_imp);
+}
+#endif /* SEH */
diff --git a/libjava/libgcj.ver b/libjava/libgcj.ver
index 4e90d9d..142c6fb 100644
--- a/libjava/libgcj.ver
+++ b/libjava/libgcj.ver
@@ -7,6 +7,7 @@
     _Jv_*;
     __gcj_personality_v0;
     __gcj_personality_sj0;
+    __gcj_personality_seh0;
     _Z*;
   local:
     *;
diff --git a/libobjc/exception.c b/libobjc/exception.c
index 04308ce..1f802a8 100644
--- a/libobjc/exception.c
+++ b/libobjc/exception.c
@@ -202,6 +202,8 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
 #ifdef SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gnu_objc_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gnu_objc_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gnu_objc_personality_v0
 #endif
@@ -225,6 +227,9 @@ PERSONALITY_FUNCTION (_Unwind_State state,
 
 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
 
+#ifdef __SEH__
+static
+#endif
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (int version,
 		      _Unwind_Action actions,
@@ -519,3 +524,13 @@ objc_exception_throw (id exception)
   abort ();
 }
 
+#ifdef __SEH__
+EXCEPTION_DISPOSITION
+__gnu_objc_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			     PCONTEXT ms_orig_context,
+			     PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gnu_objc_personality_imp);
+}
+#endif /* SEH */
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index b99a812..cd0be4e 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1357,6 +1357,7 @@ CXXABI_1.3 {
     __cxa_vec_new3;
     __gxx_personality_v0;
     __gxx_personality_sj0;
+    __gxx_personality_seh0;
     __dynamic_cast;
 
     # *_type_info classes, ctor and dtor
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc
index 729d688..72f596e 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -332,11 +332,18 @@ namespace __cxxabiv1
 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
 #define PERSONALITY_FUNCTION	__gxx_personality_sj0
 #define __builtin_eh_return_data_regno(x) x
+#elif defined(__SEH__)
+#define PERSONALITY_FUNCTION	__gxx_personality_imp
 #else
 #define PERSONALITY_FUNCTION	__gxx_personality_v0
 #endif
 
-extern "C" _Unwind_Reason_Code
+#ifdef __SEH__
+static
+#else
+extern "C"
+#endif
+_Unwind_Reason_Code
 #ifdef __ARM_EABI_UNWINDER__
 PERSONALITY_FUNCTION (_Unwind_State state,
 		      struct _Unwind_Exception* ue_header,
@@ -778,4 +785,15 @@ __cxa_call_unexpected (void *exc_obj_in)
 }
 #endif
 
+#ifdef __SEH__
+extern "C"
+EXCEPTION_DISPOSITION
+__gxx_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+			PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+  return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
+				ms_disp, __gxx_personality_imp);
+}
+#endif /* SEH */
+
 } // namespace __cxxabiv1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]