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 2


Here's the fixes on top of Nathan's patch.  Some of these you may want done
differently...

We needed the _Unwind_GetCFA interface on top of _Unwind_ForcedUnwind.  We
can't implement a true "get CFA", but it is only used for one thing in
glibc: make sure that any registered jmp_buf cleanups are called before the
stack frame the jmp_buf points to is unwound.  For this, we can arrange to
call the personality routine first; pass the pre-unwinding registers to
the unwind stop function; and return the new, unwound stack pointer value as
the "CFA".  This means that the order of cleanups in a frame with both
EH cleanups and jmp_buf cleanups has changed, but that's (A) rare and (B)
just a quirk, not a bug.

Fixing non-call exceptions turned out to be easier than I had expected.
The only problem was that faulting loads would get scheduled before the
stack adjustment, and the stack adjustment was recorded in the unwind
tables.  So if we want to support unwinding through non-call exceptions,
we must prevent the prologue from being scheduled into the rest of the
function.

The abort() deck chair shuffling is for the C++ tests, which otherwise fail
because this copy of the prototype is not marked throw().

Other than that I believe the other fixes are fairly self-explanatory.
Tested on arm-none-linux-gnueabi (with an updated NPTL port, of course).
All the GCC forced unwinding and cleanup tests pass, as do all but one of
the NPTL cancellation tests.  The only holdout is in a binary with mixed
EH-compiled and non-EH-compiled functions, and a bogus unwind entry is found
in .ARM.exidx; that's unfixable in this format, but not especially major.

OK for HEAD?  Paul, do we need these merged to csl-arm-branch also?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-11-14  Daniel Jacobowitz  <dan@codesourcery.com>

	* config/arm/unwind-arm.c (abort): Add prototype here.
	(UCB_FORCED_STOP_ARG): Correct typo in macro argument.
	(struct phase1_vrs): Add prev_sp.
	(unwind_phase2_forced): Save the original core registers instead of
	modifying entry_vrs.  Take a new flag argument for resuming unwinding
	and set action flags accordingly.  Always set _US_END_OF_STACK when
	get_eit_entry fails.  Unwind before calling the stop function.
	Restore non-core registers also.
	(_Unwind_GetCFA): New function.
	(__gnu_Unwind_ForcedUnwind): Update call to unwind_phase2_forced.
	(__gnu_Unwind_Resume_or_Rethrow): Likewise.
	(__gnu_Unwind_Resume): Do not unwind here for forced unwinding;
	just call unwind_phase2_forced.
	(_Unwind_GetDataRelBase, _Unwind_GetTextRelBase): Move to here.
	* config/arm/unwind-arm.h (abort): Remove prototype.
	(_Unwind_GetDataRelBase, _Unwind_GetTextRelBase): Change to
	prototypes.
	(_Unwind_GetCFA): New prototype.
	* config/arm/pr-support.c (abort): Add prototype here.
	* unwind-c.c (PERSONALITY_FUNCTION) [__ARM_EABI_UNWINDER__]: Handle
	forced unwinding.
	* config/arm/arm.c (arm_expand_prologue, thumb_expand_prologue): Do
	not schedule the prologue with non-call exceptions and EABI.

	* gcc.dg/cleanup-5.c, gcc.dg/cleanup-8.c, gcc.dg/cleanup-9.c,
	gcc.dg/cleanup-10.c, gcc.dg/cleanup-11.c: Update for ARM EABI.

Index: gcc/gcc/config/arm/unwind-arm.c
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.c	2005-11-10 16:08:11.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.c	2005-11-11 13:39:05.000000000 -0500
@@ -27,6 +27,10 @@
    Boston, MA 02110-1301, USA.  */
 #include "unwind.h"
 
+/* We add a prototype for abort here to avoid creating a dependency on
+   target headers.  */
+extern void abort (void);
+
 /* Definitions for C++ runtime support routines.  We make these weak
    declarations to avoid pulling in libsupc++ unnecessarily.  */
 typedef unsigned char bool;
@@ -54,7 +58,7 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, in
 #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)
+#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4)
 
 struct core_regs
 {
@@ -107,6 +111,7 @@ typedef struct
   /* The first fields must be the same as a phase2_vrs.  */
   _uw demand_save_flags;
   struct core_regs core;
+  _uw prev_sp; /* Only valid during forced unwinding.  */
   struct vfp_regs vfp;
   struct fpa_regs fpa;
 } phase1_vrs;
@@ -497,11 +502,18 @@ unwind_phase2 (_Unwind_Control_Block * u
 /* Perform phase2 forced unwinding.  */
 
 static _Unwind_Reason_Code
-unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs)
+unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs,
+		      int resuming)
 {
+  phase1_vrs saved_vrs, next_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_Reason_Code pr_result = 0;
+
+  /* Save the core registers.  */
+  saved_vrs.core = entry_vrs->core;
+  /* Set demand-save flags.  */
+  saved_vrs.demand_save_flags = ~(_uw) 0;
 
   /* Unwind until we reach a propagation barrier.  */
   do
@@ -511,27 +523,51 @@ unwind_phase2_forced (_Unwind_Control_Bl
       _Unwind_Reason_Code stop_code;
 
       /* Find the entry for this routine.  */
-      entry_code = get_eit_entry (ucbp, entry_vrs->core.r[R_PC]);
+      entry_code = get_eit_entry (ucbp, saved_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;
+      if (resuming)
+	{
+	  action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND;
+	  resuming = 0;
+	}
+      else
+	action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND;
+
+      if (entry_code == _URC_OK)
+	{
+	  UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC];
+
+	  next_vrs = saved_vrs;
+
+	  /* Call the pr to decide what to do.  */
+	  pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
+	    (action, ucbp, (void *) &next_vrs);
+
+	  saved_vrs.prev_sp = next_vrs.core.r[R_SP];
+	}
+      else
+	{
+	  /* Treat any failure as the end of unwinding, to cope more
+	     gracefully with missing EH information.  Mixed EH and
+	     non-EH within one object will usually result in failure,
+	     because the .ARM.exidx tables do not indicate the end
+	     of the code to which they apply; but mixed EH and non-EH
+	     shared objects should return an unwind failure at the
+	     entry of a non-EH shared object.  */
+	  action |= _US_END_OF_STACK;
+
+	  saved_vrs.prev_sp = saved_vrs.core.r[R_SP];
+	}
 
       stop_code = stop_fn (1, action, ucbp->exception_class, ucbp,
-			   (void *)entry_vrs, stop_arg);
+			   (void *)&saved_vrs, stop_arg);
       if (stop_code != _URC_NO_REASON)
 	return _URC_FAILURE;
 
-      if (entry_code == _URC_END_OF_STACK)
+      if (entry_code != _URC_OK)
 	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);
+      saved_vrs = next_vrs;
     }
   while (pr_result == _URC_CONTINUE_UNWIND);
 
@@ -542,7 +578,21 @@ unwind_phase2_forced (_Unwind_Control_Bl
       return _URC_FAILURE;
     }
 
-  restore_core_regs (&entry_vrs->core);
+  restore_non_core_regs (&saved_vrs);
+  restore_core_regs (&saved_vrs.core);
+}
+
+/* This is a very limited implementation of _Unwind_GetCFA.  It returns
+   the stack pointer as it is about to be unwound, and is only valid
+   while calling the stop function during forced unwinding.  If the
+   current personality routine result is going to run a cleanup, this
+   will not be the CFA; but when the frame is really unwound, it will
+   be.  */
+
+_Unwind_Word
+_Unwind_GetCFA (_Unwind_Context *context)
+{
+  return ((phase1_vrs *) context)->prev_sp;
 }
 
 /* Perform phase1 unwinding.  UCBP is the exception being thrown, and
@@ -610,7 +660,7 @@ __gnu_Unwind_ForcedUnwind (_Unwind_Contr
   /* 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);
+  return unwind_phase2_forced (ucbp, entry_vrs, 0);
 }
 
 _Unwind_Reason_Code
@@ -620,18 +670,21 @@ _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;
+    {
+      unwind_phase2_forced (ucbp, entry_vrs, 1);
 
+      /* We can't return failure at this point.  */
+      abort ();
+    }
+
+  /* Call the cached PR.  */
   pr_result = ((personality_routine) UCB_PR_ADDR (ucbp))
-	(action, ucbp, (_Unwind_Context *) entry_vrs);
+	(_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs);
 
   switch (pr_result)
     {
@@ -641,10 +694,7 @@ __gnu_Unwind_Resume (_Unwind_Control_Blo
 
     case _URC_CONTINUE_UNWIND:
       /* Continue unwinding the next frame.  */
-      if (UCB_FORCED_STOP_FN (ucbp))
-	return unwind_phase2_forced (ucbp, entry_vrs);
-      else
-	unwind_phase2 (ucbp, entry_vrs);
+      unwind_phase2 (ucbp, entry_vrs);
 
     default:
       abort ();
@@ -664,7 +714,7 @@ __gnu_Unwind_Resume_or_Rethrow (_Unwind_
   /* 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);
+  return unwind_phase2_forced (ucbp, entry_vrs, 0);
 }
 
 /* Clean up an exception object when unwinding is complete.  */
@@ -947,3 +997,16 @@ __aeabi_unwind_cpp_pr2 (_Unwind_State st
 {
   return __gnu_unwind_pr_common (state, ucbp, context, 2);
 }
+
+/* These two should never be used.  */
+_Unwind_Ptr
+_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused)))
+{
+  abort ();
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused)))
+{
+  abort ();
+}
Index: gcc/gcc/config/arm/unwind-arm.h
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.h	2005-11-10 16:08:11.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.h	2005-11-11 08:41:39.000000000 -0500
@@ -37,10 +37,6 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-  /* We add a prototype for abort here to avoid creating a dependency on
-     target headers.  */
-  extern void abort ();
-
   typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
   typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
   typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
@@ -195,18 +191,9 @@ extern "C" {
   void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
   _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
 
-  /* These two should never be used */
-  static inline _Unwind_Ptr
-  _Unwind_GetDataRelBase (_Unwind_Context * context __attribute__ ((unused)))
-    {
-      abort ();
-    }
-
-  static inline _Unwind_Ptr
-  _Unwind_GetTextRelBase (_Unwind_Context * context __attribute__ ((unused)))
-    {
-      abort ();
-    }
+  /* These two should never be used.  */
+  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
+  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
 
   /* Interface functions: */
   _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
@@ -218,6 +205,7 @@ extern "C" {
 	_Unwind_Control_Block *, struct _Unwind_Context *, void *);
   _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
 					    _Unwind_Stop_Fn, void *);
+  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
   void _Unwind_Complete(_Unwind_Control_Block *ucbp);
   void _Unwind_DeleteException (_Unwind_Exception *);
 
Index: gcc/gcc/unwind-c.c
===================================================================
--- gcc.orig/gcc/unwind-c.c	2005-11-10 12:35:20.000000000 -0500
+++ gcc/gcc/unwind-c.c	2005-11-10 16:08:11.000000000 -0500
@@ -129,7 +129,7 @@ PERSONALITY_FUNCTION (int version,
   _Unwind_Ptr landing_pad, ip;
 
 #ifdef __ARM_EABI_UNWINDER__
-  if (state != _US_UNWIND_FRAME_STARTING)
+  if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
     CONTINUE_UNWINDING;
 
   /* The dwarf unwinder assumes the context structure holds things like the
Index: gcc/gcc/config/arm/pr-support.c
===================================================================
--- gcc.orig/gcc/config/arm/pr-support.c	2005-11-03 15:08:18.000000000 -0500
+++ gcc/gcc/config/arm/pr-support.c	2005-11-11 08:37:29.000000000 -0500
@@ -27,6 +27,10 @@
    Boston, MA 02110-1301, USA.  */
 #include "unwind.h"
 
+/* We add a prototype for abort here to avoid creating a dependency on
+   target headers.  */
+extern void abort (void);
+
 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
 
 /* Misc constants.  */
Index: gcc/gcc/config/arm/arm.c
===================================================================
--- gcc.orig/gcc/config/arm/arm.c	2005-11-10 16:08:11.000000000 -0500
+++ gcc/gcc/config/arm/arm.c	2005-11-11 11:24:16.000000000 -0500
@@ -10850,8 +10850,11 @@ arm_expand_prologue (void)
 
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  Similarly if the user has requested no
-     scheduling in the prolog.  */
-  if (current_function_profile || !TARGET_SCHED_PROLOG)
+     scheduling in the prolog.  Similarly if we want non-call exceptions
+     using the EABI unwinder, to prevent faulting instructions from being
+     swapped with a stack adjustment.  */
+  if (current_function_profile || !TARGET_SCHED_PROLOG
+      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   /* If the link register is being kept alive, with the return address in it,
@@ -13714,7 +13717,13 @@ thumb_expand_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  if (current_function_profile || !TARGET_SCHED_PROLOG)
+  /* If we are profiling, make sure no instructions are scheduled before
+     the call to mcount.  Similarly if the user has requested no
+     scheduling in the prolog.  Similarly if we want non-call exceptions
+     using the EABI unwinder, to prevent faulting instructions from being
+     swapped with a stack adjustment.  */
+  if (current_function_profile || !TARGET_SCHED_PROLOG
+      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
Index: gcc/gcc/testsuite/gcc.dg/cleanup-10.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cleanup-10.c	2005-11-03 15:04:20.000000000 -0500
+++ gcc/gcc/testsuite/gcc.dg/cleanup-10.c	2005-11-11 09:26:46.000000000 -0500
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <signal.h>
 #include <unistd.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -23,7 +24,7 @@ force_unwind_stop (int version, _Unwind_
 static void force_unwind ()
 {
   struct _Unwind_Exception *exc = malloc (sizeof (*exc));
-  exc->exception_class = 0;
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
                    
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/gcc.dg/cleanup-11.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cleanup-11.c	2005-11-03 15:04:20.000000000 -0500
+++ gcc/gcc/testsuite/gcc.dg/cleanup-11.c	2005-11-11 09:26:48.000000000 -0500
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <signal.h>
 #include <unistd.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -23,7 +24,7 @@ force_unwind_stop (int version, _Unwind_
 static void force_unwind ()
 {
   struct _Unwind_Exception *exc = malloc (sizeof (*exc));
-  exc->exception_class = 0;
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
                    
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/gcc.dg/cleanup-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cleanup-5.c	2005-11-03 15:04:20.000000000 -0500
+++ gcc/gcc/testsuite/gcc.dg/cleanup-5.c	2005-11-11 09:26:39.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,
@@ -22,7 +23,7 @@ force_unwind_stop (int version, _Unwind_
 static void force_unwind ()
 {
   struct _Unwind_Exception *exc = malloc (sizeof (*exc));
-  exc->exception_class = 0;
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
                    
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/gcc.dg/cleanup-8.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cleanup-8.c	2005-11-03 15:04:21.000000000 -0500
+++ gcc/gcc/testsuite/gcc.dg/cleanup-8.c	2005-11-11 09:26:41.000000000 -0500
@@ -6,6 +6,7 @@
 #include <unwind.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -22,7 +23,7 @@ force_unwind_stop (int version, _Unwind_
 static void force_unwind ()
 {
   struct _Unwind_Exception *exc = malloc (sizeof (*exc));
-  exc->exception_class = 0;
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
                    
 #ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/gcc.dg/cleanup-9.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cleanup-9.c	2005-11-03 15:04:20.000000000 -0500
+++ gcc/gcc/testsuite/gcc.dg/cleanup-9.c	2005-11-11 09:26:43.000000000 -0500
@@ -6,6 +6,7 @@
 #include <unwind.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <string.h>
 
 static _Unwind_Reason_Code
 force_unwind_stop (int version, _Unwind_Action actions,
@@ -22,7 +23,7 @@ force_unwind_stop (int version, _Unwind_
 static void force_unwind ()
 {
   struct _Unwind_Exception *exc = malloc (sizeof (*exc));
-  exc->exception_class = 0;
+  memset (&exc->exception_class, 0, sizeof (exc->exception_class));
   exc->exception_cleanup = 0;
                    
 #ifndef __USING_SJLJ_EXCEPTIONS__


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