OSDN Git Service

PR c++/43509
[pf3gnuchains/gcc-fork.git] / gcc / config / ia64 / unwind-ia64.c
index 99923aa..f935a0c 100644 (file)
@@ -1,48 +1,52 @@
 /* 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
-#define UNW_FLAG_EHANDLER(x)   ((x) & 0x0000000100000000L)
-#define UNW_FLAG_UHANDLER(x)   ((x) & 0x0000000200000000L)
-#define UNW_LENGTH(x)          ((x) & 0x00000000ffffffffL)
+
+
+/* By default, assume personality routine interface compatibility with
+   our expectations.  */
+#ifndef MD_UNW_COMPATIBLE_PERSONALITY_P
+#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) 1
+#endif
 
 enum unw_application_register
 {
@@ -121,14 +125,25 @@ struct unw_reg_info
   int when;                    /* when the register gets saved */
 };
 
+struct unw_reg_state {
+       struct unw_reg_state *next;     /* next (outer) element on state stack */
+       struct unw_reg_info reg[UNW_NUM_REGS];  /* register save locations */
+};
+
+struct unw_labeled_state {
+       struct unw_labeled_state *next;         /* next labeled state (or NULL) */
+       unsigned long label;                    /* label for this state */
+       struct unw_reg_state saved_state;
+};
+
 typedef struct unw_state_record
 {
   unsigned int first_region : 1;       /* is this the first region? */
   unsigned int done : 1;               /* are we done scanning descriptors? */
   unsigned int any_spills : 1;         /* got any register spills? */
   unsigned int in_body : 1;    /* are we inside a body? */
-
-  unsigned char *imask;                /* imask of of spill_mask record or NULL */
+  unsigned int no_reg_stack_frame : 1; /* Don't adjust bsp for i&l regs */
+  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 */
@@ -140,12 +155,10 @@ 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_reg_state {
-    struct unw_reg_state *next;
-    unsigned long label;       /* label of this state record */
-    struct unw_reg_info reg[UNW_NUM_REGS];
-  } curr, *stack, *reg_state_list;
+  struct unw_labeled_state *labeled_states;    /* list of all labeled states */
+  struct unw_reg_state curr;   /* current state */
 
   _Unwind_Personality_Fn personality;
   
@@ -169,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
@@ -184,9 +198,15 @@ struct _Unwind_Context
   void *lsda;                  /* language specific data area */
 
   /* Preserved state.  */
-  unsigned long *bsp_loc;      /* previous bsp save location */
+  unsigned long *bsp_loc;      /* previous bsp save location
+                                  Appears to be write-only?    */
   unsigned long *bspstore_loc;
-  unsigned long *pfs_loc;
+  unsigned long *pfs_loc;      /* Save location for pfs in current
+                                  (corr. to sp) frame.  Target
+                                  contains cfm for caller.     */
+  unsigned long *signal_pfs_loc;/* Save location for pfs in current
+                                  signal frame.  Target contains
+                                  pfs for caller.  */
   unsigned long *pri_unat_loc;
   unsigned long *unat_loc;
   unsigned long *lc_loc;
@@ -204,7 +224,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
@@ -226,35 +246,209 @@ static unsigned char const save_order[] =
 \f
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
 
-/* Unwind decoder routines */
+/* MASK is a bitmap describing the allocation state of emergency buffers,
+   with bit set indicating free. Return >= 0 if allocation is successful;
+   < 0 if failure.  */
 
-static void
-push (struct unw_state_record *sr)
+static inline int
+atomic_alloc (unsigned int *mask)
+{
+  unsigned int old = *mask, ret, new;
+
+  while (1)
+    {
+      if (old == 0)
+       return -1;
+      ret = old & -old;
+      new = old & ~ret;
+      new = __sync_val_compare_and_swap (mask, old, new);
+      if (old == new)
+       break;
+      old = new;
+    }
+
+  return __builtin_ffs (ret) - 1;
+}
+
+/* Similarly, free an emergency buffer.  */
+
+static inline void
+atomic_free (unsigned int *mask, int bit)
+{
+  __sync_xor_and_fetch (mask, 1 << bit);
+}
+
+
+#define SIZE(X)                (sizeof(X) / sizeof(*(X)))
+#define MASK_FOR(X)    ((2U << (SIZE (X) - 1)) - 1)
+#define PTR_IN(X, P)   ((P) >= (X) && (P) < (X) + SIZE (X))
+
+static struct unw_reg_state emergency_reg_state[32];
+static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
+
+static struct unw_labeled_state emergency_labeled_state[8];
+static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
+
+#ifdef ENABLE_MALLOC_CHECKING
+static int reg_state_alloced;
+static int labeled_state_alloced;
+#endif
+
+/* Allocation and deallocation of structures.  */
+
+static struct unw_reg_state *
+alloc_reg_state (void)
 {
   struct unw_reg_state *rs;
 
+#ifdef ENABLE_MALLOC_CHECKING
+  reg_state_alloced++;
+#endif
+
   rs = malloc (sizeof (struct unw_reg_state));
+  if (!rs)
+    {
+      int n = atomic_alloc (&emergency_reg_state_free);
+      if (n >= 0)
+       rs = &emergency_reg_state[n];
+    }
+
+  return rs;
+}
+
+static void
+free_reg_state (struct unw_reg_state *rs)
+{
+#ifdef ENABLE_MALLOC_CHECKING
+  reg_state_alloced--;
+#endif
+
+  if (PTR_IN (emergency_reg_state, rs))
+    atomic_free (&emergency_reg_state_free, rs - emergency_reg_state);
+  else
+    free (rs);
+}
+
+static struct unw_labeled_state *
+alloc_label_state (void)
+{
+  struct unw_labeled_state *ls;
+
+#ifdef ENABLE_MALLOC_CHECKING
+  labeled_state_alloced++;
+#endif
+
+  ls = malloc(sizeof(struct unw_labeled_state));
+  if (!ls)
+    {
+      int n = atomic_alloc (&emergency_labeled_state_free);
+      if (n >= 0)
+       ls = &emergency_labeled_state[n];
+    }
+
+  return ls;
+}
+
+static void
+free_label_state (struct unw_labeled_state *ls)
+{
+#ifdef ENABLE_MALLOC_CHECKING
+  labeled_state_alloced--;
+#endif
+
+  if (PTR_IN (emergency_labeled_state, ls))
+    atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls);
+  else
+    free (ls);
+}
+
+/* Routines to manipulate the state stack.  */
+
+static void
+push (struct unw_state_record *sr)
+{
+  struct unw_reg_state *rs = alloc_reg_state ();
   memcpy (rs, &sr->curr, sizeof (*rs));
-  rs->next = sr->stack;
-  sr->stack = rs;
+  sr->curr.next = rs;
 }
 
 static void
 pop (struct unw_state_record *sr)
 {
-  struct unw_reg_state *rs;
+  struct unw_reg_state *rs = sr->curr.next;
+
+  if (!rs)
+    abort ();
+  memcpy (&sr->curr, rs, sizeof(*rs));
+  free_reg_state (rs);
+}
+
+/* Make a copy of the state stack.  Non-recursive to avoid stack overflows.  */
+
+static struct unw_reg_state *
+dup_state_stack (struct unw_reg_state *rs)
+{
+  struct unw_reg_state *copy, *prev = NULL, *first = NULL;
+
+  while (rs)
+    {
+      copy = alloc_reg_state ();
+      memcpy (copy, rs, sizeof(*copy));
+      if (first)
+       prev->next = copy;
+      else
+       first = copy;
+      rs = rs->next;
+      prev = copy;
+    }
 
-  rs = sr->stack;
-  sr->stack = rs->next;
-  free (rs);
+  return first;
 }
 
+/* Free all stacked register states (but not RS itself).  */
+static void
+free_state_stack (struct unw_reg_state *rs)
+{
+  struct unw_reg_state *p, *next;
+
+  for (p = rs->next; p != NULL; p = next)
+    {
+      next = p->next;
+      free_reg_state (p);
+    }
+  rs->next = NULL;
+}
+
+/* Free all labeled states.  */
+
+static void
+free_label_states (struct unw_labeled_state *ls)
+{
+  struct unw_labeled_state *next;
+
+  for (; ls ; ls = next)
+    {
+      next = ls->next;
+
+      free_state_stack (&ls->saved_state);
+      free_label_state (ls);
+    }
+}
+\f
+/* Unwind decoder routines */
+
 static enum unw_register_index __attribute__((const))
 decode_abreg (unsigned char abreg, int memory)
 {
   switch (abreg)
     {
+#if TARGET_ABI_OPEN_VMS
+    /* OpenVMS Calling Standard specifies R3 - R31.  */
+    case 0x03 ... 0x1f: return UNW_REG_R2 + (abreg - 0x02);
+#else
+    /* Standard Intel ABI specifies GR 4 - 7.  */
     case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
+#endif
     case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
     case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
     case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
@@ -295,8 +489,8 @@ alloc_spill_area (unsigned long *offp, unsigned long regsize,
       if (reg->where == UNW_WHERE_SPILL_HOME)
        {
          reg->where = UNW_WHERE_PSPREL;
-         reg->val = 0x10 - *offp;
-         *offp += regsize;
+         *offp -= regsize;
+         reg->val = *offp;
        }
     }
 }
@@ -330,7 +524,7 @@ finish_prologue (struct unw_state_record *sr)
   /* First, resolve implicit register save locations
      (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3).  */
 
-  for (i = 0; i < (int) sizeof(save_order); ++i)
+  for (i = 0; i < (int) sizeof (save_order); ++i)
     {
       reg = sr->curr.reg + save_order[i];
       if (reg->where == UNW_WHERE_GR_SAVE)
@@ -363,8 +557,8 @@ finish_prologue (struct unw_state_record *sr)
            mask = *cp++;
          kind = (mask >> 2*(3-(t & 3))) & 3;
          if (kind > 0)
-           spill_next_when(&regs[kind - 1], sr->curr.reg + limit[kind - 1],
-                           sr->region_start + t);
+           spill_next_when (&regs[kind - 1], sr->curr.reg + limit[kind - 1],
+                            sr->region_start + t);
        }
     }
 
@@ -372,12 +566,12 @@ finish_prologue (struct unw_state_record *sr)
   if (sr->any_spills)
     {
       off = sr->spill_offset;
-      alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2,
-                      sr->curr.reg + UNW_REG_F31); 
-      alloc_spill_area(&off,  8, sr->curr.reg + UNW_REG_B1,
-                      sr->curr.reg + UNW_REG_B5);
-      alloc_spill_area(&off,  8, sr->curr.reg + UNW_REG_R4,
-                      sr->curr.reg + UNW_REG_R7);
+      alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2,
+                       sr->curr.reg + UNW_REG_F31); 
+      alloc_spill_area (&off,  8, sr->curr.reg + UNW_REG_B1,
+                       sr->curr.reg + UNW_REG_B5);
+      alloc_spill_area (&off,  8, sr->curr.reg + UNW_REG_R4,
+                       sr->curr.reg + UNW_REG_R7);
     }
 }
 
@@ -392,23 +586,24 @@ desc_prologue (int body, unw_word rlen, unsigned char mask,
   int i;
 
   if (!(sr->in_body || sr->first_region))
-    finish_prologue(sr);
+    finish_prologue (sr);
   sr->first_region = 0;
 
   /* Check if we're done.  */
-  if (body && sr->when_target < sr->region_start + sr->region_len)
+  if (sr->when_target < sr->region_start + sr->region_len) 
     {
       sr->done = 1;
       return;
     }
 
   for (i = 0; i < sr->epilogue_count; ++i)
-    pop(sr);
+    pop (sr);
+
   sr->epilogue_count = 0;
   sr->epilogue_start = UNW_WHEN_NEVER;
 
   if (!body)
-    push(sr);
+    push (sr);
 
   sr->region_start += sr->region_len;
   sr->region_len = rlen;
@@ -435,11 +630,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
@@ -494,7 +689,8 @@ desc_frgr_mem (unsigned char grmask, unw_word frmask,
     {
       if ((frmask & 1) != 0)
        {
-         set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME,
+         enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4;
+         set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME,
                   sr->region_start + sr->region_len - 1, 0);
          sr->any_spills = 1;
        }
@@ -631,13 +827,15 @@ desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr)
 static inline void
 desc_copy_state (unw_word label, struct unw_state_record *sr)
 {
-  struct unw_reg_state *rs;
+  struct unw_labeled_state *ls;
 
-  for (rs = sr->reg_state_list; rs; rs = rs->next)
+  for (ls = sr->labeled_states; ls; ls = ls->next)
     {
-      if (rs->label == label)
-       {
-         memcpy (&sr->curr, rs, sizeof(sr->curr));
+      if (ls->label == label)
+        {
+         free_state_stack (&sr->curr);
+         memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
+         sr->curr.next = dup_state_stack (ls->saved_state.next);
          return;
        }
     }
@@ -647,13 +845,15 @@ desc_copy_state (unw_word label, struct unw_state_record *sr)
 static inline void
 desc_label_state (unw_word label, struct unw_state_record *sr)
 {
-  struct unw_reg_state *rs;
+  struct unw_labeled_state *ls = alloc_label_state ();
 
-  rs = malloc (sizeof (struct unw_reg_state));
-  memcpy (rs, &sr->curr, sizeof (*rs));
-  rs->label = label;
-  rs->next = sr->reg_state_list;
-  sr->reg_state_list = rs;
+  ls->label = label;
+  memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
+  ls->saved_state.next = dup_state_stack (sr->curr.next);
+
+  /* Insert into list of labeled states.  */
+  ls->next = sr->labeled_states;
+  sr->labeled_states = ls;
 }
 
 /*
@@ -1212,7 +1412,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: */
   {
@@ -1276,7 +1476,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
@@ -1300,6 +1500,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
@@ -1359,9 +1633,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;
            }
@@ -1371,9 +1646,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);
     }
 
@@ -1433,6 +1709,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
@@ -1453,60 +1736,110 @@ _Unwind_GetRegionStart (struct _Unwind_Context *context)
   return context->region_start;
 }
 
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+  struct unw_table_entry *entp, ent;
+  unsigned long segment_base, gp;
+
+  entp = _Unwind_FindTableEntry (pc, &segment_base, &gp, &ent);
+  if (entp == NULL)
+    return NULL;
+  else
+    return (void *)(segment_base + entp->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)
 {
-  struct unw_table_entry *ent;
+  struct unw_table_entry *entp, ent;
   unsigned long *unw, header, length;
   unsigned char *insn, *insn_end;
   unsigned long segment_base;
+  struct unw_reg_info *r;
 
   memset (fs, 0, sizeof (*fs));
+  for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r)
+    r->when = UNW_WHEN_NEVER;
   context->lsda = 0;
 
-  ent = _Unwind_FindTableEntry ((void *) context->rp,
-                               &segment_base, &context->gp);
-  if (ent == NULL)
+  entp = _Unwind_FindTableEntry ((void *) context->rp,
+                               &segment_base, &context->gp, &ent);
+  if (entp == NULL)
     {
       /* Couldn't find unwind info for this function.  Try an
         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;
+#endif
 
       /* [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)
-       {
-         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;
-       }
+        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)
+       goto skip_unwind_info;
 
       return _URC_END_OF_STACK;
-    success:
-      return _URC_NO_REASON;
-#else
-      return _URC_END_OF_STACK;
-#endif
     }
 
-  context->region_start = ent->start_offset + segment_base;
-  fs->when_target = (context->rp - context->region_start) / 16 * 3;
+  context->region_start = entp->start_offset + segment_base;
+  fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3
+                   + (context->rp & 15);
 
-  unw = (unsigned long *) (ent->info_offset + segment_base);
+  unw = (unsigned long *) (entp->info_offset + segment_base);
   header = *unw;
   length = UNW_LENGTH (header);
 
-  /* ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK.  */
+  /* Some operating systems use the personality routine slot in way not
+     compatible with what we expect.  For instance, OpenVMS uses this slot to
+     designate "condition handlers" with very different arguments than what we
+     would be providing.  Such cases are typically identified from OS specific
+     bits in the unwind information block header, and checked by the target
+     MD_UNW_COMPATIBLE_PERSONALITY_P macro. 
+
+     We just pretend there is no personality from our standpoint in such
+     situations, and expect GCC not to set the identifying bits itself so that
+     compatible personalities for GCC compiled code are called.
+
+     Of course, this raises the question of what combinations of native/GCC
+     calls can be expected to behave properly exception handling-wise.  We are
+     not to provide a magic answer here, merely to prevent crashes assuming
+     users know what they are doing.
+
+     ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK as well.  */
 
-  if (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header))
+  if (MD_UNW_COMPATIBLE_PERSONALITY_P (header)
+      && (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header)))
     {
       fs->personality =
        *(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp);
@@ -1518,6 +1851,14 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   while (!fs->done && insn < insn_end)
     insn = unw_decode (insn, fs->in_body, fs);
 
+  free_label_states (fs->labeled_states);
+  free_state_stack (&fs->curr);
+
+#ifdef ENABLE_MALLOC_CHECKING
+  if (reg_state_alloced || labeled_state_alloced)
+    abort ();
+#endif
+
   /* If we're in the epilogue, sp has been restored and all values
      on the memory stack below psp also have been restored.  */
   if (fs->when_target > fs->epilogue_start)
@@ -1532,7 +1873,8 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
          r->where = UNW_WHERE_NONE;
     }
 
-  /* If RP did't get saved, generate entry for the return link register.  */
+skip_unwind_info:
+  /* If RP didn't get saved, generate entry for the return link register.  */
   if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target)
     {
       fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
@@ -1540,6 +1882,27 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
       fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg;
     }
 
+  /* There is a subtlety for the frame after unwinding through a signal
+     handler: should we restore the cfm as usual or the pfs?  We can't
+     restore both because we use br.ret to resume execution of user code.
+     For other frames the procedure is by definition non-leaf so the pfs
+     is saved and restored and thus effectively dead in the body; only
+     the cfm need therefore be restored.
+     
+     Here we have 2 cases:
+       - either the pfs is saved and restored and thus effectively dead
+        like in regular frames; then we do nothing special and restore
+        the cfm.
+       - or the pfs is not saved and thus live; but in that case the
+        procedure is necessarily leaf so the cfm is effectively dead
+        and we restore the pfs.  */
+  if (context->signal_pfs_loc)
+    {
+      if (fs->curr.reg[UNW_REG_PFS].when >= fs->when_target)
+       context->pfs_loc = context->signal_pfs_loc;
+      context->signal_pfs_loc = NULL;
+    }
+
   return _URC_NO_REASON;
 }
 
@@ -1563,6 +1926,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;
@@ -1576,9 +1944,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 >= 0 && rval <= 5)
+      if (rval < 8)
        addr = context->br_loc[rval];
       else
        abort ();
@@ -1614,6 +1982,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;
@@ -1677,8 +2050,7 @@ uw_update_reg_address (struct _Unwind_Context *context,
       context->psp = *(unsigned long *)addr;
       break;
 
-    case UNW_REG_RNAT:
-    case UNW_NUM_REGS:
+    default:
       abort ();
     }
 }
@@ -1688,6 +2060,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.  */
@@ -1720,7 +2096,10 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
 
   /* Unwind BSP for the local registers allocated this frame.  */
   /* ??? What to do with stored BSP or BSPSTORE registers.  */
-  if (fs->when_target > fs->curr.reg[UNW_REG_PFS].when)
+  /* We assert that we are either at a call site, or we have
+     just unwound through a signal frame.  In either case
+     pfs_loc is valid. */
+  if (!(fs -> no_reg_stack_frame))
     {
       unsigned long pfs = *context->pfs_loc;
       unsigned long sol = (pfs >> 7) & 0x7f;
@@ -1729,6 +2108,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.  */
    
@@ -1741,25 +2126,38 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     uw_init_context_1 (CONTEXT, __builtin_ia64_bsp ());                        \
   } while (0)
 
-static void
+static void __attribute__((noinline))
 uw_init_context_1 (struct _Unwind_Context *context, void *bsp)
 {
   void *rp = __builtin_extract_return_addr (__builtin_return_address (0));
   /* 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 ();
@@ -1767,7 +2165,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)),
@@ -1800,6 +2198,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)));
@@ -1836,22 +2237,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"
@@ -1928,6 +2329,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"
@@ -1999,12 +2402,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
@@ -2015,7 +2418,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"
@@ -2036,4 +2438,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