]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/ia64/unwind-ia64.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / ia64 / unwind-ia64.c
index ca915397f5fe1ef2ab0db58a7f45eda1fd42116b..d69b7fc4d3078b1b327b91f7e066c515d50f43c1 100644 (file)
@@ -1,46 +1,46 @@
 /* Subroutines needed for unwinding IA-64 standard format stack frame
    info for exception handling.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
+   2009  Free Software Foundation, Inc.
    Contributed by Andrew MacLeod  <amacleod@cygnus.com>
                  Andrew Haley  <aph@cygnus.com>
                  David Mosberger-Tang <davidm@hpl.hp.com>
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
+   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 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
+   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 GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with other files,
-   some of which are compiled with GCC, to produce an executable,
-   this library does not by itself cause the resulting executable
-   to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
+   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"
 #include "unwind-ia64.h"
+#include "unwind-compat.h"
 #include "ia64intrin.h"
 
 /* This isn't thread safe, but nice for occasional tests.  */
 #undef ENABLE_MALLOC_CHECKING
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
+
 #define UNW_VER(x)             ((x) >> 48)
 #define UNW_FLAG_MASK          0x0000ffff00000000
 #define UNW_FLAG_OSMASK                0x0000f00000000000
@@ -143,7 +143,7 @@ typedef struct unw_state_record
   unsigned int any_spills : 1;         /* got any register spills? */
   unsigned int in_body : 1;    /* are we inside a body? */
   unsigned int no_reg_stack_frame : 1; /* Don't adjust bsp for i&l regs */
-  unsigned char *imask;                /* imask of of spill_mask record or NULL */
+  unsigned char *imask;                /* imask of spill_mask record or NULL */
   unsigned long pr_val;                /* predicate values */
   unsigned long pr_mask;       /* predicate mask */
   long spill_offset;           /* psp-relative offset for spill base */
@@ -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 */
@@ -181,7 +182,8 @@ struct _Unwind_Context
 {
   /* Initial frame info.  */
   unsigned long rnat;          /* rse nat collection */
-  unsigned long regstk_top;    /* bsp for first frame */
+  unsigned long regstk_top;    /* lowest address of rbs stored register
+                                  which uses context->rnat collection */
 
   /* Current frame info.  */
   unsigned long bsp;           /* backing store pointer value
@@ -219,7 +221,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
@@ -279,10 +281,10 @@ atomic_free (unsigned int *mask, int bit)
 #define PTR_IN(X, P)   ((P) >= (X) && (P) < (X) + SIZE (X))
 
 static struct unw_reg_state emergency_reg_state[32];
-static int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
+static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
 
 static struct unw_labeled_state emergency_labeled_state[8];
-static int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
+static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
 
 #ifdef ENABLE_MALLOC_CHECKING
 static int reg_state_alloced;
@@ -619,11 +621,11 @@ desc_prologue (int body, unw_word rlen, unsigned char mask,
  */
 
 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
@@ -1401,7 +1403,7 @@ unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
 
 typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
 
-static unw_decoder unw_decode_table[2][8] =
+static const unw_decoder unw_decode_table[2][8] =
 {
   /* prologue table: */
   {
@@ -1465,7 +1467,7 @@ ia64_rse_rnat_addr (unsigned long *slot_addr)
   return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
 }
 
-/* Calcuate the number of registers in the dirty partition starting at
+/* Calculate the number of registers in the dirty partition starting at
    BSPSTORE with a size of DIRTY bytes.  This isn't simply DIRTY
    divided by eight because the 64th slot is used to store ar.rnat.  */
 static inline unsigned long
@@ -1489,6 +1491,80 @@ ia64_rse_skip_regs (unsigned long *addr, long num_regs)
 }
 
 \f
+/* Copy register backing store from SRC to DST, LEN words
+   (which include both saved registers and nat collections).
+   DST_RNAT is a partial nat collection for DST.  SRC and DST
+   don't have to be equal modulo 64 slots, so it cannot be
+   done with a simple memcpy as the nat collections will be
+   at different relative offsets and need to be combined together.  */
+static void
+ia64_copy_rbs (struct _Unwind_Context *info, unsigned long dst,
+               unsigned long src, long len, unsigned long dst_rnat)
+{
+  long count;
+  unsigned long src_rnat;
+  unsigned long shift1, shift2;
+
+  len <<= 3;
+  dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1;
+  src_rnat = src >= info->regstk_top
+            ? info->rnat : *(unsigned long *) (src | 0x1f8);
+  src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1);
+  /* Just to make sure.  */
+  src_rnat &= ~(1UL << 63);
+  shift1 = ((dst - src) >> 3) & 0x3f;
+  if ((dst & 0x1f8) < (src & 0x1f8))
+    shift1--;
+  shift2 = 0x3f - shift1;
+  if ((dst & 0x1f8) >= (src & 0x1f8))
+    {
+      count = ~dst & 0x1f8;
+      goto first;
+    }
+  count = ~src & 0x1f8;
+  goto second;
+  while (len > 0)
+    {
+      src_rnat = src >= info->regstk_top
+                ? info->rnat : *(unsigned long *) (src | 0x1f8);
+      /* Just to make sure.  */
+      src_rnat &= ~(1UL << 63);
+      count = shift2 << 3;
+first:
+      if (count > len)
+        count = len;
+      memcpy ((char *) dst, (char *) src, count);
+      dst += count;
+      src += count;
+      len -= count;
+      dst_rnat |= (src_rnat << shift1) & ~(1UL << 63);
+      if (len <= 0)
+        break;
+      *(long *) dst = dst_rnat;
+      dst += 8;
+      dst_rnat = 0;
+      count = shift1 << 3;
+second:
+      if (count > len)
+        count = len;
+      memcpy ((char *) dst, (char *) src, count);
+      dst += count;
+      src += count + 8;
+      len -= count + 8;
+      dst_rnat |= (src_rnat >> shift2);
+    }
+  if ((dst & 0x1f8) == 0x1f8)
+    {
+      *(long *) dst = dst_rnat;
+      dst += 8;
+      dst_rnat = 0;
+    }
+  /* Set info->regstk_top to lowest rbs address which will use
+     info->rnat collection.  */
+  info->regstk_top = dst & ~0x1ffUL;
+  info->rnat = dst_rnat;
+}
+
 /* Unwind accessors.  */
 
 static void
@@ -1548,9 +1624,10 @@ unw_access_gr (struct _Unwind_Context *info, int regnum,
              break;
 
            case UNW_NAT_REGSTK:
-             nat_addr = ia64_rse_rnat_addr (addr);
-             if ((unsigned long) nat_addr >= info->regstk_top)
+             if ((unsigned long) addr >= info->regstk_top)
                nat_addr = &info->rnat;
+             else
+               nat_addr = ia64_rse_rnat_addr (addr);
              nat_mask = 1UL << ia64_rse_slot_num (addr);
              break;
            }
@@ -1560,9 +1637,10 @@ unw_access_gr (struct _Unwind_Context *info, int regnum,
     {
       /* Access a stacked register.  */
       addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32);
-      nat_addr = ia64_rse_rnat_addr (addr);
-      if ((unsigned long) nat_addr >= info->regstk_top)
+      if ((unsigned long) addr >= info->regstk_top)
        nat_addr = &info->rnat;
+      else
+       nat_addr = ia64_rse_rnat_addr (addr);
       nat_mask = 1UL << ia64_rse_slot_num (addr);
     }
 
@@ -1622,6 +1700,13 @@ _Unwind_GetIP (struct _Unwind_Context *context)
   return context->rp;
 }
 
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+  *ip_before_insn = 0;
+  return context->rp;
+}
+
 /* Overwrite the return address for CONTEXT with VAL.  */
 
 inline void
@@ -1642,6 +1727,40 @@ _Unwind_GetRegionStart (struct _Unwind_Context *context)
   return context->region_start;
 }
 
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+  struct unw_table_entry *ent;
+  unsigned long segment_base, gp;
+
+  ent = _Unwind_FindTableEntry (pc, &segment_base, &gp);
+  if (ent == NULL)
+    return NULL;
+  else
+    return (void *)(segment_base + ent->start_offset);
+}
+
+/* Get the value of the CFA as saved in CONTEXT.  In GCC/Dwarf2 parlance,
+   the CFA is the value of the stack pointer on entry; In IA-64 unwind
+   parlance, this is the PSP.  */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->psp;
+}
+
+/* Get the value of the Backing Store Pointer as saved in CONTEXT.  */
+
+_Unwind_Word
+_Unwind_GetBSP (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->bsp;
+}
+
+#ifdef MD_UNWIND_SUPPORT
+#include MD_UNWIND_SUPPORT
+#endif
 \f
 static _Unwind_Reason_Code
 uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
@@ -1665,32 +1784,31 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
         os-specific fallback mechanism.  This will necessarily
         not provide a personality routine or LSDA.  */
 #ifdef MD_FALLBACK_FRAME_STATE_FOR
-      MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
+      if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON)
+       return _URC_NO_REASON;
 
       /* [SCRA 11.4.1] A leaf function with no memory stack, no exception
         handlers, and which keeps the return value in B0 does not need
         an unwind table entry.
 
         This can only happen in the frame after unwinding through a signal
-        handler.  Avoid infinite looping by requiring that B0 != RP.  */
-      if (context->br_loc[0] && *context->br_loc[0] != context->rp)
+        handler.  Avoid infinite looping by requiring that B0 != RP.
+        RP == 0 terminates the chain.  */
+      if (context->br_loc[0] && *context->br_loc[0] != context->rp
+         && context->rp != 0)
        {
          fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
          fs->curr.reg[UNW_REG_RP].when = -1;
          fs->curr.reg[UNW_REG_RP].val = 0;
-         goto success;
+         return _URC_NO_REASON;
        }
-
-      return _URC_END_OF_STACK;
-    success:
-      return _URC_NO_REASON;
-#else
-      return _URC_END_OF_STACK;
 #endif
+      return _URC_END_OF_STACK;
     }
 
   context->region_start = ent->start_offset + segment_base;
-  fs->when_target = (context->rp - context->region_start) / 16 * 3;
+  fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3
+                   + (context->rp & 15);
 
   unw = (unsigned long *) (ent->info_offset + segment_base);
   header = *unw;
@@ -1763,6 +1881,11 @@ uw_update_reg_address (struct _Unwind_Context *context,
        addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32);
       else if (rval >= 2)
        addr = context->ireg[rval - 2].loc;
+      else if (rval == 0)
+       {
+         static const unsigned long dummy;
+         addr = (void *) &dummy;
+       }
       else
        abort ();
       break;
@@ -1776,9 +1899,9 @@ uw_update_reg_address (struct _Unwind_Context *context,
 
     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 ();
@@ -1814,6 +1937,11 @@ uw_update_reg_address (struct _Unwind_Context *context,
            context->ireg[regno - UNW_REG_R2].nat
              = context->ireg[rval - 2].nat;
          }
+       else if (rval == 0)
+         {
+           context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE;
+           context->ireg[regno - UNW_REG_R2].nat.off = 0;
+         }
        else
          abort ();
        break;
@@ -1887,6 +2015,10 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 {
   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.  */
@@ -1931,6 +2063,12 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     }
 }
 
+static void
+uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  uw_update_context (context, fs);
+}
+
 /* Fill in CONTEXT for top-of-stack.  The only valid registers at this
    level will be the return address and the CFA.  Note that CFA = SP+16.  */
    
@@ -1950,18 +2088,31 @@ uw_init_context_1 (struct _Unwind_Context *context, void *bsp)
   /* 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 ();
+  unsigned long rnat, tmp1, tmp2;
+
+  /* Flush the register stack to memory so that we can access it.
+     Get rse nat collection for the last incomplete rbs chunk of
+     registers at the same time.  For this RSE needs to be turned
+     into the mandatory only mode.  */
+  asm ("mov.m %1 = ar.rsc;;\n\t"
+       "and %2 = 0x1c, %1;;\n\t"
+       "mov.m ar.rsc = %2;;\n\t"
+       "flushrs;;\n\t"
+       "mov.m %0 = ar.rnat;;\n\t"
+       "mov.m ar.rsc = %1\n\t"
+       : "=r" (rnat), "=r" (tmp1), "=r" (tmp2));
 
   memset (context, 0, sizeof (struct _Unwind_Context));
-  context->bsp = context->regstk_top = (unsigned long) bsp;
+  context->bsp = (unsigned long) bsp;
+  /* Set context->regstk_top to lowest rbs address which will use
+     context->rnat collection.  */
+  context->regstk_top = context->bsp & ~0x1ffULL;
+  context->rnat = rnat;
   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_unat;      /* ??? */
-  /* ??? Get rnat.  Don't we have to turn off the rse for that?  */
 
   if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
     abort ();
@@ -1969,7 +2120,7 @@ uw_init_context_1 (struct _Unwind_Context *context, void *bsp)
   uw_update_context (context, &fs);
 }
 
-/* Install (ie longjmp to) the contents of TARGET.  */
+/* Install (i.e. longjmp to) the contents of TARGET.  */
 
 static void __attribute__((noreturn))
 uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
@@ -2002,6 +2153,9 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
     ia64_rse_skip_regs ((unsigned long *)target->bsp,
                        (*target->pfs_loc >> 7) & 0x7f);
 
+  if (target->bsp < target->regstk_top)
+    target->rnat = *ia64_rse_rnat_addr ((unsigned long *) target->bsp);
+
   /* Provide assembly with the offsets into the _Unwind_Context.  */
   asm volatile ("uc_rnat = %0"
                : : "i"(offsetof (struct _Unwind_Context, rnat)));
@@ -2038,22 +2192,22 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
        ";;                                     \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"
@@ -2130,6 +2284,8 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
        "(p6) ldf.fill f22 = [r28]              \n\t"
        "cmp.ne p7, p0 = r0, r29                \n\t"
        ";;                                     \n\t"
+       "ld8 r27 = [r20], 8                     \n\t"
+       ";;                                     \n\t"
        "ld8 r28 = [r20], 8                     \n\t"
        "(p7) ldf.fill f23 = [r29]              \n\t"
        "cmp.ne p6, p0 = r0, r22                \n\t"
@@ -2201,12 +2357,12 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
        "(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"
+       "and r29 = 0x1c, r25                    \n\t"
        "mov b0 = r26                           \n\t"
        ";;                                     \n\t"
-       "mov.m ar.rsc = r25                     \n\t"
+       "mov.m ar.rsc = r29                     \n\t"
        ";;                                     \n\t"
        /* This must be done before setting AR.BSPSTORE, otherwise 
           AR.BSP will be initialized with a random displacement
@@ -2217,7 +2373,6 @@ uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
        ";;                                     \n\t"
        "mov.m ar.bspstore = r23                \n\t"
        ";;                                     \n\t"
-       "or r25 = 0x3, r25                      \n\t"
        "mov.m ar.rnat = r22                    \n\t"
        ";;                                     \n\t"
        "mov.m ar.rsc = r25                     \n\t"
@@ -2238,4 +2393,23 @@ uw_identify_context (struct _Unwind_Context *context)
 }
 
 #include "unwind.inc"
+
+#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
+alias (_Unwind_Backtrace);
+alias (_Unwind_DeleteException);
+alias (_Unwind_FindEnclosingFunction);
+alias (_Unwind_ForcedUnwind);
+alias (_Unwind_GetBSP);
+alias (_Unwind_GetCFA);
+alias (_Unwind_GetGR);
+alias (_Unwind_GetIP);
+alias (_Unwind_GetLanguageSpecificData);
+alias (_Unwind_GetRegionStart);
+alias (_Unwind_RaiseException);
+alias (_Unwind_Resume);
+alias (_Unwind_Resume_or_Rethrow);
+alias (_Unwind_SetGR);
+alias (_Unwind_SetIP);
+#endif
+
 #endif