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] Fix a couple of IA-64 unwinder bugs


Hi!

1) current IA-64 kernels have signal trampoline between 0xa000000000020000
   and 0xa000000000030000.  Although David said he'll move it 64K down,
   the IA64_GATE_AREA_END change makes things work even with various
   2.5.* and 2.6.0-test* kernels
2) MD_FALLBACK_FRAME_STATE_FOR was not setting fpsr_loc
3) related to this, uw_install_context contained an invalid insn
   mov.i ar.fpsr = rXX (it should be mov.m ar.fpsr = rXX)
4) fixes a bug in b1..b5 restoring (it would restore b1 from br_loc[0]
   (i.e. b0), b2 from br_loc[1] (i.e. b1) etc.) plus a testcase for it
5) handles unwabi @linux,'s' and for compatibility also @svr4,'s'
6) current kernels save return addr when doing syscall via AT_SYSINFO
   in b6 register.  This handles b6 similar to b0 and handles b7 as well.

Ok to commit?
More to follow later.

2003-12-10  Jakub Jelinek  <jakub@redhat.com>

	* config/ia64/linux.h (IA64_GATE_AREA_END): Increase by 64K.
	(MD_FALLBACK_FRAME_STATE_FOR): Set fpsr_loc, br_loc[6] and
	br_loc[7].
	(MD_HANDLE_UNWABI): Define.
	* config/ia64/unwind-ia64.c (struct unw_state_record): Add
	unwabi field.
	(struct _Unwind_Context): Increase br_loc array size to 8 entries.
	(desc_abi): Set unwabi.
	(uw_update_reg_address): Allow br up to 7.
	(uw_update_context): Invoke MD_HANDLE_UNWABI if defined.
	(uw_install_context): Load b1..b5 from correct locations.
	Fix insn loading ar.fpsr.

	* g++.dg/eh/ia64-1.C: New test.
	
--- gcc/config/ia64/linux.h.jj	2003-06-03 14:35:00.000000000 +0200
+++ gcc/config/ia64/linux.h	2003-12-10 20:22:45.000000000 +0100
@@ -72,7 +72,7 @@ do {						\
 #include <sys/ucontext.h>
 
 #define IA64_GATE_AREA_START 0xa000000000000100LL
-#define IA64_GATE_AREA_END   0xa000000000020000LL
+#define IA64_GATE_AREA_END   0xa000000000030000LL
 
 #define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)		\
   if ((CONTEXT)->rp >= IA64_GATE_AREA_START				\
@@ -99,10 +99,13 @@ do {						\
 	  (CONTEXT)->ireg[i_ - 2].loc = &sc_->sc_gr[i_];		\
       }									\
 	  								\
+      (CONTEXT)->fpsr_loc = &(sc_->sc_ar_fpsr);				\
       (CONTEXT)->pfs_loc = &(sc_->sc_ar_pfs);				\
       (CONTEXT)->lc_loc = &(sc_->sc_ar_lc);				\
       (CONTEXT)->unat_loc = &(sc_->sc_ar_unat);				\
       (CONTEXT)->br_loc[0] = &(sc_->sc_br[0]);				\
+      (CONTEXT)->br_loc[6] = &(sc_->sc_br[6]);				\
+      (CONTEXT)->br_loc[7] = &(sc_->sc_br[7]);				\
       (CONTEXT)->bsp = sc_->sc_ar_bsp;					\
       (CONTEXT)->pr = sc_->sc_pr;					\
       (CONTEXT)->psp = sc_->sc_gr[12];					\
@@ -129,4 +132,59 @@ do {						\
 									\
       goto SUCCESS;							\
     }
+
+#define MD_HANDLE_UNWABI(CONTEXT, FS)					\
+  if ((FS)->unwabi == ((3 << 8) | 's')					\
+      || (FS)->unwabi == ((0 << 8) | 's'))				\
+    {									\
+      struct sigframe {							\
+	char scratch[16];						\
+	unsigned long sig_number;					\
+	struct siginfo *info;						\
+	struct sigcontext *sc;						\
+      } *frame_ = (struct sigframe *)(CONTEXT)->psp;			\
+      struct sigcontext *sc_ = frame_->sc;				\
+									\
+      /* Restore scratch registers in case the unwinder needs to	\
+	 refer to a value stored in one of them.  */			\
+      {									\
+	int i_;								\
+									\
+	for (i_ = 2; i_ < 4; i_++)					\
+	  (CONTEXT)->ireg[i_ - 2].loc = &sc_->sc_gr[i_];		\
+	for (i_ = 8; i_ < 12; i_++)					\
+	  (CONTEXT)->ireg[i_ - 2].loc = &sc_->sc_gr[i_];		\
+	for (i_ = 14; i_ < 32; i_++)					\
+	  (CONTEXT)->ireg[i_ - 2].loc = &sc_->sc_gr[i_];		\
+      }									\
+	  								\
+      (CONTEXT)->pfs_loc = &(sc_->sc_ar_pfs);				\
+      (CONTEXT)->lc_loc = &(sc_->sc_ar_lc);				\
+      (CONTEXT)->unat_loc = &(sc_->sc_ar_unat);				\
+      (CONTEXT)->br_loc[0] = &(sc_->sc_br[0]);				\
+      (CONTEXT)->br_loc[6] = &(sc_->sc_br[6]);				\
+      (CONTEXT)->br_loc[7] = &(sc_->sc_br[7]);				\
+      (CONTEXT)->bsp = sc_->sc_ar_bsp;					\
+      (CONTEXT)->pr = sc_->sc_pr;					\
+      (CONTEXT)->gp = sc_->sc_gr[1];					\
+      /* Signal frame doesn't have an associated reg. stack frame 	\
+         other than what we adjust for below.	  */			\
+      (FS) -> no_reg_stack_frame = 1;					\
+									\
+      /* Don't touch the branch registers o.t. b0.  The kernel doesn't	\
+	 pass the preserved branch registers in the sigcontext but	\
+	 leaves them intact, so there's no need to do anything		\
+	 with them here.  */						\
+									\
+      {									\
+	unsigned long sof = sc_->sc_cfm & 0x7f;				\
+	(CONTEXT)->bsp = (unsigned long)				\
+	  ia64_rse_skip_regs ((unsigned long *)(sc_->sc_ar_bsp), -sof); \
+      }									\
+									\
+      /* pfs_loc already set above.  Without this pfs_loc would point	\
+	 incorrectly to sc_cfm instead of sc_ar_pfs.  */		\
+      (FS)->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;		\
+    }
+
 #endif /* IN_LIBGCC2 */
--- gcc/config/ia64/unwind-ia64.c.jj	2003-10-23 17:43:59.000000000 +0200
+++ gcc/config/ia64/unwind-ia64.c	2003-12-10 21:05:09.000000000 +0100
@@ -155,6 +155,7 @@ typedef struct unw_state_record
 
   unsigned char gr_save_loc;	/* next general register to use for saving */
   unsigned char return_link_reg; /* branch register for return link */
+  unsigned short unwabi;
 
   struct unw_labeled_state *labeled_states;	/* list of all labeled states */
   struct unw_reg_state curr;	/* current state */
@@ -219,7 +220,7 @@ struct _Unwind_Context
     } nat;
   } ireg[32 - 2];	/* Indexed by <register number> - 2 */
 
-  unsigned long *br_loc[7];
+  unsigned long *br_loc[8];
   void *fr_loc[32 - 2];
 
   /* ??? We initially point pri_unat_loc here.  The entire NAT bit
@@ -619,11 +620,11 @@ desc_prologue (int body, unw_word rlen, 
  */
 
 static inline void
-desc_abi (unsigned char abi __attribute__((unused)),
-	  unsigned char context __attribute__((unused)),
-	  struct unw_state_record *sr __attribute__((unused)))
+desc_abi (unsigned char abi,
+	  unsigned char context,
+	  struct unw_state_record *sr)
 {
-  /* Anything to do?  */
+  sr->unwabi = (abi << 8) | context;
 }
 
 static inline void
@@ -1812,9 +1813,9 @@ uw_update_reg_address (struct _Unwind_Co
 
     case UNW_WHERE_BR:
       /* Note that while RVAL can only be 1-5 from normal descriptors,
-	 we can want to look at B0 due to having manually unwound a
+	 we can want to look at B0, B6 and B7 due to having manually unwound a
 	 signal frame.  */
-      if (rval <= 5)
+      if (rval < 8)
 	addr = context->br_loc[rval];
       else
 	abort ();
@@ -1928,6 +1929,10 @@ uw_update_context (struct _Unwind_Contex
 {
   long i;
 
+#ifdef MD_HANDLE_UNWABI
+  MD_HANDLE_UNWABI (context, fs);
+#endif
+
   context->sp = context->psp;
 
   /* First, set PSP.  Subsequent instructions may depend on this value.  */
@@ -2079,22 +2084,22 @@ uw_install_context (struct _Unwind_Conte
 	";;					\n\t"
 	"(p6) ld8.fill r4 = [%1]		\n\t"
 	"(p7) ld8.fill r5 = [r20]		\n\t"
-	"add r21 = uc_br_loc + 8, %0		\n\t"
+	"add r21 = uc_br_loc + 16, %0		\n\t"
 	"adds %1 = 16, %1			\n\t"
 	"adds r20 = 16, r20			\n\t"
 	";;					\n\t"
 	"(p8) ld8.fill r6 = [%1]		\n\t"
 	"(p9) ld8.fill r7 = [r20]		\n\t"
-	"add r20 = uc_br_loc, %0		\n\t"
+	"add r20 = uc_br_loc + 8, %0		\n\t"
 	";;					\n\t"
 	/* Load up call-saved branch registers.  */
 	"ld8 r22 = [r20], 16			\n\t"
 	"ld8 r23 = [r21], 16			\n\t"
 	";;					\n\t"
 	"ld8 r24 = [r20], 16			\n\t"
-	"ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 24)\n\t"
+	"ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 32)\n\t"
 	";;					\n\t"
-	"ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 32)\n\t"
+	"ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 40)\n\t"
 	"ld8 r27 = [r21], 24			\n\t"
 	"cmp.ne p6, p0 = r0, r22		\n\t"
 	";;					\n\t"
@@ -2242,7 +2247,7 @@ uw_install_context (struct _Unwind_Conte
 	"(p9) mov.i ar.lc = r29			\n\t"
 	";;					\n\t"
 	"mov.m r25 = ar.rsc			\n\t"
-	"(p6) mov.i ar.fpsr = r30		\n\t"
+	"(p6) mov.m ar.fpsr = r30		\n\t"
 	";;					\n\t"
 	"and r25 = 0x1c, r25			\n\t"
 	"mov b0 = r26				\n\t"
--- gcc/testsuite/g++.dg/eh/ia64-1.C.jj	2003-09-15 15:40:47.000000000 +0200
+++ gcc/testsuite/g++.dg/eh/ia64-1.C	2003-12-10 21:23:00.000000000 +0100
@@ -0,0 +1,50 @@
+// Test whether call saved float and branch regs are restored properly
+// { dg-do run { target ia64-*-* } }
+// { dg-options "-O2" }
+
+extern "C" void abort (void);
+
+char buf[128];
+
+void __attribute__((noinline))
+bar (void)
+{
+  throw 1;
+}
+
+void __attribute__((noinline))
+foo (void)
+{
+  bar ();
+  bar ();
+}
+
+int
+main (void)
+{
+  register double f2 __asm ("f2");
+  register double f3 __asm ("f3");
+  register double f4 __asm ("f4");
+  register double f5 __asm ("f5");
+  register double f16 __asm ("f16");
+  register double f17 __asm ("f17");
+  register void *b1 __asm ("b1");
+  register void *b2 __asm ("b2");
+  register void *b3 __asm ("b3");
+  register void *b4 __asm ("b4");
+  register void *b5 __asm ("b5");
+  f2 = 12.0; f3 = 13.0; f4 = 14.0; f5 = 15.0; f16 = 16.0; f17 = 17.0;
+  b1 = &buf[1]; b2 = &buf[2]; b3 = &buf[3]; b4 = &buf[4]; b5 = &buf[5];
+  try
+    {
+      foo ();
+    }
+  catch (...) {}
+  if (f2 != 12.0 || f3 != 13.0 || f4 != 14.0
+      || f5 != 15.0 || f16 != 16.0 || f17 != 17.0)
+    abort ();
+  if (b1 != &buf[1] || b2 != &buf[2] || b3 != &buf[3]
+      || b4 != &buf[4] || b5 != &buf[5])
+    abort ();
+  return 0;
+}

	Jakub


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