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]

IA64 unwinder patch


Here's a patch that improves the correctness of the IA64 unwinder.  It
includes a modified version of some of Andrew Haley's earlier patch.
Together with a patch to flow.c that I previously posted (which Richard was
going to redo), this is sufficient for the exception handling tests in
SPECjbb.  Is it OK to commit this to the trunk?

Known issues:

- More testing, especially with C++, would be good.

- Nat bits are still not handled correctly.  Gcc-generated code doesn't use
them, so it's probably possible to tolerate this bug for a while longer.

- The conditional inclusion of linux.h in unwind-ia64.c looks ugly to me.
If someone can enlighten me as to how this was supposed to work (linux.h
does need to be included and it isn't), I'd be happy to change it.  If not,
I believe this is at least correct.

- In the long run it would be a lot nicer if the source to this could be
shared with the kernel and gdb, especially since it's obviously hard to get
this really correct.  (David Mosberger is looking into that.)

	config/ia64/linux.h:  Add MD_FALLBACK_FRAME_STATE_FOR to
		handle unwinding through signal handler frame.  If the
		process was executing in the gate area when the signal
		was generated, we still die.
	config/ia64/unwind-ia64.c:
		Include linux.h.  There should be a better way ...
		(uw_init_context_1): Redo sp, psp, bsp setup.
		Sp, psp are 16 bytes displaced from ...cfa().
		Remove psp adjustment hack which
		resulted in reversed (sp, psp).
		Set pri_unat_loc to something reasonable.  Nat bit
		restoration is still broken, but closer. 
		(uw_install_context): add missing cast (minor).
		(unw_access_gr): Fix off-by-1 indexing error.
	

Index: config/ia64/linux.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/linux.h,v
retrieving revision 1.12
diff -u -r1.12 linux.h
--- linux.h	2001/11/10 01:07:17	1.12
+++ linux.h	2001/11/29 21:50:40
@@ -45,4 +45,60 @@
 #undef PROFILE_BEFORE_PROLOGUE
 #define PROFILE_BEFORE_PROLOGUE 1
 
+#include <signal.h>
+#include <sys/ucontext.h>
+
+#define IA64_GATE_AREA_START 0xa000000000000100LL
+#define IA64_GATE_AREA_END   0xa000000000010000LL
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)		\
+  if ((CONTEXT)->rp >= IA64_GATE_AREA_START				\
+      && (CONTEXT)->rp < IA64_GATE_AREA_END)				\
+    {									\
+      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)->pr = sc_->sc_pr;					\
+      (CONTEXT)->psp = sc_->sc_gr[12];					\
+									\
+      /* Don't touch the branch registers.  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);
\
+      }
\
+									\
+      (FS)->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;		\
+      (FS)->curr.reg[UNW_REG_RP].val 					\
+	= (unsigned long)&(sc_->sc_ip) - (CONTEXT)->psp;		\
+      (FS)->curr.reg[UNW_REG_RP].when = -1;				\
+									\
+      goto SUCCESS;							\
+    }
+
 /* End of linux.h */
Index: config/ia64/unwind-ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/unwind-ia64.c,v
retrieving revision 1.2
diff -u -r1.2 unwind-ia64.c
--- unwind-ia64.c	2001/08/19 04:55:15	1.2
+++ unwind-ia64.c	2001/11/29 21:50:40
@@ -31,6 +31,14 @@
 
 
 #include "tconfig.h"
+/* FIXME: This should be included from tconfig.h.  But that was somehow
+ * broken, since IN_GCC is not defined when this is built, and the includes
+ * in tconfig.h are all conditioned on IN_GCC, except for a couple of
+ * hard-coded exceptions.  This whole setup doesn't feel quite right,
+ * but I don't understand enough of the code to fix it.	*/
+#ifdef __linux__
+#  include "linux.h"
+#endif
 #include "tsystem.h"
 #include "unwind.h"
 #include "unwind-ia64.h"
@@ -174,7 +182,8 @@
   unsigned long regstk_top;	/* bsp for first frame */
 
   /* Current frame info.  */
-  unsigned long bsp;		/* backing store pointer value */
+  unsigned long bsp;		/* backing store pointer value	*/
+  				/* corresponding to psp.	*/
   unsigned long sp;		/* stack pointer value */
   unsigned long psp;		/* previous sp value */
   unsigned long rp;		/* return pointer */
@@ -203,10 +212,13 @@
       enum unw_nat_type type : 3;
       signed long off : 61;		/* NaT word is at loc+nat.off */
     } nat;
-  } ireg[32 - 2];
+  } ireg[32 - 2];	/* Indexed by <register number> - 2 */
 
   unsigned long *br_loc[7];
   void *fr_loc[32 - 2];
+  unsigned long initial_rnat;	/* FIXME - This is probably wrong.	*/
+  				/* This shouldn't be here.  The NAT bit	*/
+  				/* logic needs work.			*/
 };
 
 typedef unsigned long unw_word;
@@ -1317,7 +1329,7 @@
   else if (regnum < 32)
     {
       /* Access a non-stacked register.  */
-      ireg = &info->ireg[regnum - 1];
+      ireg = &info->ireg[regnum - 2];
       addr = ireg->loc;
       if (addr)
 	{
@@ -1468,7 +1480,7 @@
     {
       /* Couldn't find unwind info for this function.  Try an
 	 os-specific fallback mechanism.  This will necessarily
-	 not profide a personality routine or LSDA.  */
+	 not provide a personality routine or LSDA.  */
 #ifdef MD_FALLBACK_FRAME_STATE_FOR
       MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
 
@@ -1727,39 +1739,40 @@
 }
 
 /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
-   level will be the return address and the CFA.  */
+   level will be the return address and the CFA. 
+   Note that cfa() = sp + 16 			*/
    
 #define uw_init_context(CONTEXT) \
-  uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), __builtin_ia64_bsp
())
+  { \
+    __builtin_unwind_init(); \
+    uw_init_context_1 (CONTEXT, __builtin_ia64_bsp ()); \
+  }
 
 static void
-uw_init_context_1 (struct _Unwind_Context *context, void *psp, void *bsp)
+uw_init_context_1 (struct _Unwind_Context *context, void *bsp)
 {
   void *rp = __builtin_extract_return_addr (__builtin_return_address (0));
-  void *sp = __builtin_dwarf_cfa ();
+  /* Set psp to the caller's stack pointer. */
+  void *psp = __builtin_dwarf_cfa () - 16;
   _Unwind_FrameState fs;
 
   /* Flush the register stack to memory so that we can access it.  */
   __builtin_ia64_flushrs ();
 
   memset (context, 0, sizeof (struct _Unwind_Context));
-  context->bsp = (unsigned long) bsp;
-  context->sp = (unsigned long) sp;
+  context->bsp = context -> regstk_top = (unsigned long) bsp;
   context->psp = (unsigned long) psp;
   context->rp = (unsigned long) rp;
-
+  asm ("mov %0 = sp" : "=r" (context->sp));
   asm ("mov %0 = pr" : "=r" (context->pr));
+  context->pri_unat_loc = &(context -> initial_rnat);	/* FIXME */
   /* ??? Get rnat.  Don't we have to turn off the rse for that?  */
 
   if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
     abort ();
 
-  /* Force the frame state to use the known cfa value.  */
-  fs.curr.reg[UNW_REG_PSP].when = -1;
-  fs.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
-  fs.curr.reg[UNW_REG_PSP].val = sp - psp;
-
   uw_update_context (context, &fs);
+  
 }
 
 /* Install (ie longjmp to) the contents of TARGET.  */
@@ -1791,8 +1804,9 @@
      target function.  The value that we install below will be
      adjusted by the BR.RET instruction based on the contents
      of AR.PFS.  So we must unadjust that here.  */
-  target->bsp
-    = ia64_rse_skip_regs (target->bsp, (*target->pfs_loc >> 7) & 0x7f);
+  target->bsp = (unsigned long)
+	  		ia64_rse_skip_regs ((unsigned long *)target->bsp,
+				            (*target->pfs_loc >> 7) & 0x7f);
 
   /* Provide assembly with the offsets into the _Unwind_Context.  */
   asm volatile ("uc_rnat = %0"


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