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]

ARM forced unwinding for HEAD part 1


This patch is a backport of Nathan's forced unwinding implementation, which
Paul already approved for csl-arm-branch, to HEAD.  I've now updated NPTL to
use the new implementation and found various problems with it; I'm going to
be posting those in a second so that they can be reviewed separately.

I realize this patch is very late, but it is the final part of the ARM EABI
GNU/Linux configuration, and I can see no way that I could have broken any
existing configuration.  Is this OK for mainline, assuming the followups are
approved?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-11-14  Nathan Sidwell  <nathan@codesourcery.com>

	* gcc/unwind-arm.h: Reorder interface function declarations.
	(_URC_END_OF_STACK): New enumeration value.
	(_US_UNWIND_ACTION_MASK, _US_FORCE_UNWIND, _US_END_OF_STACK): Likewise.
	(struct _Unwind_Control_Block): Document reserved field use.
	(_Unwind_Stop_Fn): New typedef.
	(_Unwind_ForcedUnwind): Declare.
	(_Unwind_Resume_or_Rethrow): Declare.
	* gcc/config/arm/libunwind.S (UNWIND_WRAPER): Add nargs
	argument.  Adjust.
	(_Unwind_Resume_or_Rethrow, _Unwind_ForcedUnwind): New.
	* gcc/config/arm/unwind-arm.c (UCB_FORCED_STOP_FN)
	(UCB_FORCED_STOP_ARG): New.
	(search_EIT_table): Update boundary condition checks.
	(get_eit_entry): Return _URC_END_OF_STACK when cannot unwind.
	(unwind_phase2): Replace for with do..while.
	(unwind_phase2_forced): New.
	(__gnu_Unwind_RaiseException): Replace for with do..while.
	(__gnu_Unwind_ForcedUnwind): New.
	(__gnu_Unwind_Resume): Set FORCE_UNWIND flag, if forced unwinding.
	Use appropriate phase2 unwinder.
	(__gnu_Unwind_Resume_or_Rethrow): New.
	(__gnu_unwind_pr_common): Cope with forced unwinding.

	* gcc/testsuite/g++.dg/eh/forced1.C: Adjust to cope with ARM EABI
	structures.
	* gcc/testsuite/g++.dg/eh/forced2.C: Likewise.
	* gcc/testsuite/g++.dg/eh/forced3.C: Likewise.
	* gcc/testsuite/g++.dg/eh/forced4.C: Likewise.

	* libstdc++-v3/libsupc++/eh_arm.cc (__cxa_begin_cleanup): Remember a
	foreign exception too.
	(__gnu_end_cleanup): Recover a foreign exception too.
	* libstdc++-v3/libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Cope
	with forced unwinding.
	* libstdc++-v3/libsupc++/eh_throw.cc (__cxxabiv1::__cxa_rethrow): Use
	_Unwind_Resume_or_Rethrow for ARM EABI.

Index: gcc/gcc/config/arm/unwind-arm.h
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.h	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.h	2005-11-14 10:51:09.000000000 -0500
@@ -1,5 +1,5 @@
 /* Header file for the ARM EABI unwinder
-   Copyright (C) 2003, 2004  Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
    Contributed by Paul Brook
 
    This file is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@ extern "C" {
 #endif
   /* We add a prototype for abort here to avoid creating a dependency on
      target headers.  */
-  extern void abort();
+  extern void abort ();
 
   typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
   typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
@@ -54,28 +54,41 @@ extern "C" {
     {
       _URC_OK = 0,       /* operation completed successfully */
       _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+      _URC_END_OF_STACK = 5,
       _URC_HANDLER_FOUND = 6,
       _URC_INSTALL_CONTEXT = 7,
       _URC_CONTINUE_UNWIND = 8,
       _URC_FAILURE = 9   /* unspecified failure of some kind */
     }
   _Unwind_Reason_Code;
-  
+
   typedef enum
     {
       _US_VIRTUAL_UNWIND_FRAME = 0,
       _US_UNWIND_FRAME_STARTING = 1,
-      _US_UNWIND_FRAME_RESUME = 2
+      _US_UNWIND_FRAME_RESUME = 2,
+      _US_ACTION_MASK = 3,
+      _US_FORCE_UNWIND = 8,
+      _US_END_OF_STACK = 16
     }
   _Unwind_State;
-  
+
+  /* Provided only for for compatibility with existing code.  */
+  typedef int _Unwind_Action;
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+#define _UA_END_OF_STACK	16
+#define _URC_NO_REASON 	_URC_OK
+
   typedef struct _Unwind_Control_Block _Unwind_Control_Block;
   typedef struct _Unwind_Context _Unwind_Context;
   typedef _uw _Unwind_EHT_Header;
-  
-  
+
+
   /* UCB: */
-  
+
   struct _Unwind_Control_Block
     {
       char exception_class[8];
@@ -83,10 +96,10 @@ extern "C" {
       /* Unwinder cache, private fields for the unwinder's use */
       struct
 	{
-	  _uw reserved1;	/* init reserved1 to 0, then don't touch */
-	  _uw reserved2;
-	  _uw reserved3;
-	  _uw reserved4;
+	  _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */
+	  _uw reserved2;  /* Personality routine address */
+	  _uw reserved3;  /* Saved callsite address */
+	  _uw reserved4;  /* Forced unwind stop arg */
 	  _uw reserved5;
 	}
       unwinder_cache;
@@ -114,14 +127,9 @@ extern "C" {
       pr_cache;
       long long int :0;	/* Force alignment to 8-byte boundary */
     };
-  
-  /* Interface functions: */
-  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
-  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
-  void _Unwind_Complete(_Unwind_Control_Block *ucbp);
 
   /* Virtual Register Set*/
-        
+
   typedef enum
     {
       _UVRSC_CORE = 0,      /* integer register */
@@ -131,7 +139,7 @@ extern "C" {
       _UVRSC_WMMXC = 4      /* Intel WMMX control register */
     }
   _Unwind_VRS_RegClass;
-  
+
   typedef enum
     {
       _UVRSD_UINT32 = 0,
@@ -142,13 +150,13 @@ extern "C" {
       _UVRSD_DOUBLE = 5
     }
   _Unwind_VRS_DataRepresentation;
-  
+
   typedef enum
     {
       _UVRSR_OK = 0,
       _UVRSR_NOT_IMPLEMENTED = 1,
       _UVRSR_FAILED = 2
-    } 
+    }
   _Unwind_VRS_Result;
 
   /* Frame unwinding state.  */
@@ -171,11 +179,11 @@ extern "C" {
   _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
                                      _uw, _Unwind_VRS_DataRepresentation,
                                      void *);
-  
+
   _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
                                      _uw, _Unwind_VRS_DataRepresentation,
                                      void *);
-  
+
   _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
                                      _uw, _Unwind_VRS_DataRepresentation);
 
@@ -200,6 +208,17 @@ extern "C" {
       abort ();
     }
 
+  /* Interface functions: */
+  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
+  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
+  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
+
+  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+       (int, _Unwind_Action, _Unwind_Exception_Class,
+	_Unwind_Control_Block *, struct _Unwind_Context *, void *);
+  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
+					    _Unwind_Stop_Fn, void *);
+  void _Unwind_Complete(_Unwind_Control_Block *ucbp);
   void _Unwind_DeleteException (_Unwind_Exception *);
 
   _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
@@ -254,16 +273,6 @@ extern "C" {
 #define _Unwind_SetIP(context, val) \
   _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
 
-  /* Provided only for for compatibility with existing code.  */
-  typedef int _Unwind_Action;
-#define _UA_SEARCH_PHASE	1
-#define _UA_CLEANUP_PHASE	2
-#define _UA_HANDLER_FRAME	4
-#define _UA_FORCE_UNWIND	8
-#define _UA_END_OF_STACK	16
-
-#define _URC_NO_REASON _URC_OK
-
 #ifdef __cplusplus
 }   /* extern "C" */
 #endif
Index: gcc/gcc/config/arm/libunwind.S
===================================================================
--- gcc.orig/gcc/config/arm/libunwind.S	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/libunwind.S	2005-11-14 10:51:09.000000000 -0500
@@ -78,7 +78,7 @@ ARM_FUNC_START gnu_Unwind_Save_VFP
 
 /* Wrappers to save core registers, then call the real routine.   */
 
-.macro  UNWIND_WRAPPER name
+.macro  UNWIND_WRAPPER name nargs
 	ARM_FUNC_START \name
 	/* Create a phase2_vrs structure.  */
 	/* Split reg push in two to ensure the correct value for sp.  */
@@ -89,8 +89,8 @@ ARM_FUNC_START gnu_Unwind_Save_VFP
 	mov r3, #0
 	stmfd sp!, {r2, r3}
 
-	/* Point r1 at the block.  Pass r0 unchanged.  */
-	add r1, sp, #4
+	/* Point r1 at the block.  Pass r[0..nargs) unchanged.  */
+	add r\nargs, sp, #4
 #if defined(__thumb__)
 	/* Switch back to thumb mode to avoid interworking hassle.  */
 	adr ip, .L1_\name
@@ -112,7 +112,9 @@ ARM_FUNC_START gnu_Unwind_Save_VFP
 	UNPREFIX \name
 .endm
 
-UNWIND_WRAPPER _Unwind_RaiseException
-UNWIND_WRAPPER _Unwind_Resume
+UNWIND_WRAPPER _Unwind_RaiseException 1
+UNWIND_WRAPPER _Unwind_Resume 1
+UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1
+UNWIND_WRAPPER _Unwind_ForcedUnwind 3
 
 #endif  /* __symbian__ */
Index: gcc/gcc/config/arm/unwind-arm.c
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.c	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.c	2005-11-14 10:51:09.000000000 -0500
@@ -51,8 +51,10 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, in
 #define EXIDX_CANTUNWIND 1
 #define uint32_highbit (((_uw) 1) << 31)
 
+#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1)
 #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2)
 #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3)
+#define UCB_FORCED_STOP_ARG(ucb) ((ucbp)->unwinder_cache.reserved4)
 
 struct core_regs
 {
@@ -356,9 +358,9 @@ search_EIT_table (const __EIT_entry * ta
       n = (left + right) / 2;
       this_fn = selfrel_offset31 (&table[n].fnoffset);
       if (n != nrec - 1)
-	next_fn = selfrel_offset31 (&table[n + 1].fnoffset);
+	next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1;
       else
-	next_fn = ~(_uw) 0;
+	next_fn = (_uw)0 - 1;
 
       if (return_address < this_fn)
 	{
@@ -366,7 +368,7 @@ search_EIT_table (const __EIT_entry * ta
 	    return (__EIT_entry *) 0;
 	  right = n - 1;
 	}
-      else if (return_address < next_fn)
+      else if (return_address <= next_fn)
 	return &table[n];
       else
 	left = n + 1;
@@ -419,7 +421,7 @@ get_eit_entry (_Unwind_Control_Block *uc
   if (eitp->content == EXIDX_CANTUNWIND)
     {
       UCB_PR_ADDR (ucbp) = 0;
-      return _URC_FAILURE;
+      return _URC_END_OF_STACK;
     }
 
   /* Obtain the address of the "real" __EHT_Header word.  */
@@ -472,21 +474,19 @@ unwind_phase2 (_Unwind_Control_Block * u
 {
   _Unwind_Reason_Code pr_result;
 
-  for(;;)
+  do
     {
       /* Find the entry for this routine.  */
       if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK)
 	abort ();
 
       UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC];
-      
+
       /* Call the pr to decide what to do.  */
       pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
 	(_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs);
-
-      if (pr_result != _URC_CONTINUE_UNWIND)
-	break;
     }
+  while (pr_result == _URC_CONTINUE_UNWIND);
   
   if (pr_result != _URC_INSTALL_CONTEXT)
     abort();
@@ -494,6 +494,57 @@ unwind_phase2 (_Unwind_Control_Block * u
   restore_core_regs (&vrs->core);
 }
 
+/* Perform phase2 forced unwinding.  */
+
+static _Unwind_Reason_Code
+unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs)
+{
+  _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp);
+  void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp);
+  _Unwind_Reason_Code pr_result;
+
+  /* Unwind until we reach a propagation barrier.  */
+  do
+    {
+      _Unwind_State action;
+      _Unwind_Reason_Code entry_code;
+      _Unwind_Reason_Code stop_code;
+
+      /* Find the entry for this routine.  */
+      entry_code = get_eit_entry (ucbp, entry_vrs->core.r[R_PC]);
+
+      action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND;
+      if (entry_code == _URC_END_OF_STACK)
+	action |= _US_END_OF_STACK;
+      else if (entry_code != _URC_OK)
+	return _URC_FAILURE;
+
+      stop_code = stop_fn (1, action, ucbp->exception_class, ucbp,
+			   (void *)entry_vrs, stop_arg);
+      if (stop_code != _URC_NO_REASON)
+	return _URC_FAILURE;
+
+      if (entry_code == _URC_END_OF_STACK)
+	return entry_code;
+
+      UCB_SAVED_CALLSITE_ADDR (ucbp) = entry_vrs->core.r[R_PC];
+
+      /* Call the pr to decide what to do.  */
+      pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	(action, ucbp, (void *) entry_vrs);
+    }
+  while (pr_result == _URC_CONTINUE_UNWIND);
+
+  if (pr_result != _URC_INSTALL_CONTEXT)
+    {
+      /* Some sort of failure has occurred in the pr and probably the
+	 pr returned _URC_FAILURE.  */
+      return _URC_FAILURE;
+    }
+
+  restore_core_regs (&entry_vrs->core);
+}
+
 /* Perform phase1 unwinding.  UCBP is the exception being thrown, and
    entry_VRS is the register state on entry to _Unwind_RaiseException.  */
 
@@ -516,7 +567,7 @@ __gnu_Unwind_RaiseException (_Unwind_Con
   saved_vrs.demand_save_flags = ~(_uw) 0;
   
   /* Unwind until we reach a propagation barrier.  */
-  for (;;)
+  do
     {
       /* Find the entry for this routine.  */
       if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK)
@@ -525,10 +576,8 @@ __gnu_Unwind_RaiseException (_Unwind_Con
       /* Call the pr to decide what to do.  */
       pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
 	(_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs);
-
-      if (pr_result != _URC_CONTINUE_UNWIND)
-	break;
     }
+  while (pr_result == _URC_CONTINUE_UNWIND);
 
   /* We've unwound as far as we want to go, so restore the original
      register state.  */
@@ -547,19 +596,42 @@ __gnu_Unwind_RaiseException (_Unwind_Con
    being thrown and ENTRY_VRS is the register state on entry to
    _Unwind_Resume.  */
 _Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *,
+			   _Unwind_Stop_Fn, void *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp,
+			   _Unwind_Stop_Fn stop_fn, void *stop_arg,
+			   phase2_vrs *entry_vrs)
+{
+  UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn;
+  UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg;
+
+  /* Set the pc to the call site.  */
+  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
+
+  return unwind_phase2_forced (ucbp, entry_vrs);
+}
+
+_Unwind_Reason_Code
 __gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *);
 
 _Unwind_Reason_Code
 __gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs)
 {
   _Unwind_Reason_Code pr_result;
+  _Unwind_State action;
 
   /* Recover the saved address.  */
   entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp);
-  
+
   /* Call the cached PR.  */
+  action = _US_UNWIND_FRAME_RESUME;
+  if (UCB_FORCED_STOP_FN (ucbp))
+    action |= _US_FORCE_UNWIND;
+
   pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs);
+	(action, ucbp, (_Unwind_Context *) entry_vrs);
 
   switch (pr_result)
     {
@@ -569,13 +641,32 @@ __gnu_Unwind_Resume (_Unwind_Control_Blo
 
     case _URC_CONTINUE_UNWIND:
       /* Continue unwinding the next frame.  */
-      unwind_phase2 (ucbp, entry_vrs);
+      if (UCB_FORCED_STOP_FN (ucbp))
+	return unwind_phase2_forced (ucbp, entry_vrs);
+      else
+	unwind_phase2 (ucbp, entry_vrs);
 
     default:
       abort ();
     }
 }
 
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *);
+
+_Unwind_Reason_Code
+__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp,
+				phase2_vrs * entry_vrs)
+{
+  if (!UCB_FORCED_STOP_FN (ucbp))
+    return __gnu_Unwind_RaiseException (ucbp, entry_vrs);
+
+  /* Set the pc to the call site.  */
+  entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR];
+  /* Continue unwinding the next frame.  */
+  return unwind_phase2_forced (ucbp, entry_vrs);
+}
+
 /* Clean up an exception object when unwinding is complete.  */
 void
 _Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused)))
@@ -619,6 +710,9 @@ __gnu_unwind_pr_common (_Unwind_State st
   _uw rtti_count;
   int phase2_call_unexpected_after_unwind = 0;
   int in_range = 0;
+  int forced_unwind = state & _US_FORCE_UNWIND;
+
+  state &= _US_ACTION_MASK;
 
   data = (_uw *) ucbp->pr_cache.ehtp;
   uws.data = *(data++);
@@ -748,9 +842,9 @@ __gnu_unwind_pr_common (_Unwind_State st
 	      /* Exception specification.  */
 	      if (state == _US_VIRTUAL_UNWIND_FRAME)
 		{
-		  if (in_range)
+		  if (in_range && (!forced_unwind || !rtti_count))
 		    {
-		      /* Match against teh exception specification.  */
+		      /* Match against the exception specification.  */
 		      _uw i;
 		      _uw rtti;
 		      void *matched;
Index: gcc/gcc/testsuite/g++.dg/eh/forced1.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced1.C	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced1.C	2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
 
 #include <unwind.h>
 #include <stdlib.h>
+#include <string.h>
 
 static int test = 0;
 
@@ -35,7 +36,8 @@ force_unwind_cleanup (_Unwind_Reason_Cod
 static void force_unwind ()
 {
   _Unwind_Exception *exc = new _Unwind_Exception;
-  exc->exception_class = 0;
+  // exception_class might not be a scalar.
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = force_unwind_cleanup;
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
@@ -54,7 +56,7 @@ struct S
   ~S() { test |= bit; }
 };
   
-static void doit ()
+static __attribute__ ((noinline)) void doit ()
 {
   try {
     S four(4);
@@ -62,7 +64,6 @@ static void doit ()
     try {
       S one(1);
       force_unwind ();
-  
     } catch(...) { 
       test |= 2;
       throw;
Index: gcc/gcc/testsuite/g++.dg/eh/forced2.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced2.C	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced2.C	2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
 
 #include <unwind.h>
 #include <stdlib.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -29,7 +30,8 @@ static void
 force_unwind ()
 {
   _Unwind_Exception *exc = new _Unwind_Exception;
-  exc->exception_class = 0;
+  // exception_class might not be a scalar.
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = force_unwind_cleanup;
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/g++.dg/eh/forced3.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced3.C	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced3.C	2005-11-14 10:51:09.000000000 -0500
@@ -7,6 +7,7 @@
 #include <unwind.h>
 #include <stdlib.h>
 #include <exception>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -24,7 +25,8 @@ static void __attribute__((noreturn))
 force_unwind ()
 {
   _Unwind_Exception *exc = new _Unwind_Exception;
-  exc->exception_class = 0;
+  // exception_class might not be a scalar.
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/g++.dg/eh/forced4.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced4.C	2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced4.C	2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
 
 #include <unwind.h>
 #include <stdlib.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -23,7 +24,8 @@ static void __attribute__((noreturn))
 force_unwind ()
 {
   _Unwind_Exception *exc = new _Unwind_Exception;
-  exc->exception_class = 0;
+  // exception_class might not be a scalar.
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/libstdc++-v3/libsupc++/eh_arm.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_arm.cc	2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_arm.cc	2005-11-14 10:51:09.000000000 -0500
@@ -89,20 +89,31 @@ __cxa_begin_cleanup(_Unwind_Exception* u
 {
   __cxa_eh_globals *globals = __cxa_get_globals();
   __cxa_exception *header = __get_exception_header_from_ue(ue_header);
+  bool native = __is_gxx_exception_class(header->unwindHeader.exception_class);
 
-  if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
+
+  if (native)
     {
-      // TODO: cleanups with foreign exceptions.
-      return false;
+      header->propagationCount++;
+      // Add it to the chain if this is the first time we've seen this
+      // exception.
+      if (header->propagationCount == 1)
+	{
+	  header->nextPropagatingException = globals->propagatingExceptions;
+	  globals->propagatingExceptions = header;
+	}
     }
-  header->propagationCount++;
-  // Add it to the chain if this is the first time we've seen this exception.
-  if (header->propagationCount == 1)
+  else
     {
-      header->nextPropagatingException = globals->propagatingExceptions;
+      // Remember the exception object, so end_cleanup can return it.
+      // These cannot be stacked, so we must abort if we already have
+      // a propagating exception.
+      if (globals->propagatingExceptions)
+	std::terminate ();
       globals->propagatingExceptions = header;
     }
-  return true;
+
+  return !native;
 }
 
 // Do the work for __cxa_end_cleanup.  Returns the currently propagating
@@ -119,13 +130,19 @@ __gnu_end_cleanup(void)
   if (!header)
     std::terminate();
 
-  header->propagationCount--;
-  if (header->propagationCount == 0)
+  if (__is_gxx_exception_class(header->unwindHeader.exception_class))
     {
-      // Remove exception from chain.
-      globals->propagatingExceptions = header->nextPropagatingException;
-      header->nextPropagatingException = NULL;
+      header->propagationCount--;
+      if (header->propagationCount == 0)
+	{
+	  // Remove exception from chain.
+	  globals->propagatingExceptions = header->nextPropagatingException;
+	  header->nextPropagatingException = NULL;
+	}
     }
+  else
+    globals->propagatingExceptions = NULL;
+
   return &header->unwindHeader;
 }
 
Index: gcc/libstdc++-v3/libsupc++/eh_personality.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_personality.cc	2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_personality.cc	2005-11-14 10:51:09.000000000 -0500
@@ -369,7 +369,7 @@ PERSONALITY_FUNCTION (int version,
 #ifdef __ARM_EABI_UNWINDER__
   _Unwind_Action actions;
 
-  switch (state)
+  switch (state & _US_ACTION_MASK)
     {
     case _US_VIRTUAL_UNWIND_FRAME:
       actions = _UA_SEARCH_PHASE;
@@ -377,7 +377,8 @@ PERSONALITY_FUNCTION (int version,
 
     case _US_UNWIND_FRAME_STARTING:
       actions = _UA_CLEANUP_PHASE;
-      if (ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+      if (!(state & _US_FORCE_UNWIND)
+	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
 	actions |= _UA_HANDLER_FRAME;
       break;
 
@@ -388,6 +389,7 @@ PERSONALITY_FUNCTION (int version,
     default:
       abort();
     }
+  actions |= state & _US_FORCE_UNWIND;
 
   // We don't know which runtime we're working with, so can't check this.
   // However the ABI routines hide this from us, and we don't actually need
@@ -523,13 +525,13 @@ PERSONALITY_FUNCTION (int version,
       // exception class, there's no exception type.
       // ??? What to do about GNU Java and GNU Ada exceptions.
 
-#ifdef __ARM_EABI_UNWINDER__
-      throw_type = ue_header;
-#else
       if ((actions & _UA_FORCE_UNWIND)
 	  || foreign_exception)
 	throw_type = 0;
       else
+#ifdef __ARM_EABI_UNWINDER__
+	throw_type = ue_header;
+#else
 	throw_type = xh->exceptionType;
 #endif
 
@@ -613,7 +615,6 @@ PERSONALITY_FUNCTION (int version,
 
  install_context:
   
-#ifndef __ARM_EABI_UNWINDER__
   // We can't use any of the cxa routines with foreign exceptions,
   // because they all expect ue_header to be a struct __cxa_exception.
   // So in that case, call terminate or unexpected directly.
@@ -631,7 +632,6 @@ PERSONALITY_FUNCTION (int version,
 	}
     }
   else
-#endif
     {
       if (found_type == found_terminate)
 	__cxa_call_terminate(ue_header);
Index: gcc/libstdc++-v3/libsupc++/eh_throw.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_throw.cc	2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_throw.cc	2005-11-14 10:51:09.000000000 -0500
@@ -97,7 +97,7 @@ __cxxabiv1::__cxa_rethrow ()
 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
       _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
 #else
-#if defined(_LIBUNWIND_STD_ABI) || defined (__ARM_EABI_UNWINDER__)
+#if defined(_LIBUNWIND_STD_ABI)
       _Unwind_RaiseException (&header->unwindHeader);
 #else
       _Unwind_Resume_or_Rethrow (&header->unwindHeader);


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