2004-06-06 Randolph Chung <tausq@debian.org>
[deliverable/binutils-gdb.git] / gdb / ia64-tdep.c
index 79c645d2ced0d097c66c4d7ba9189521dbcffc6a..d53aec24794611e540d81111723bd9c927b45b12 100644 (file)
@@ -1,6 +1,7 @@
 /* Target-dependent code for the IA-64 for GDB, the GNU debugger.
 
-   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+   Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,7 +22,6 @@
 
 #include "defs.h"
 #include "inferior.h"
-#include "symfile.h"           /* for entry_point_address */
 #include "gdbcore.h"
 #include "arch-utils.h"
 #include "floatformat.h"
 #include "elf/common.h"                /* for DT_PLTGOT value */
 #include "elf-bfd.h"
 #include "dis-asm.h"
+#include "infcall.h"
+#include "ia64-tdep.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "elf/ia64.h"           /* for PT_IA_64_UNWIND value */
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
 
 /* Hook for determining the global pointer when calling functions in
    the inferior under AIX.  The initialization code in ia64-aix-nat.c
@@ -84,10 +92,6 @@ typedef enum instruction_type
 
 #define BUNDLE_LEN 16
 
-/* FIXME: These extern declarations should go in ia64-tdep.h.  */
-extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
-extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
-
 static gdbarch_init_ftype ia64_gdbarch_init;
 
 static gdbarch_register_name_ftype ia64_register_name;
@@ -95,7 +99,6 @@ static gdbarch_register_type_ftype ia64_register_type;
 static gdbarch_breakpoint_from_pc_ftype ia64_breakpoint_from_pc;
 static gdbarch_skip_prologue_ftype ia64_skip_prologue;
 static gdbarch_extract_return_value_ftype ia64_extract_return_value;
-static gdbarch_extract_struct_value_address_ftype ia64_extract_struct_value_address;
 static gdbarch_use_struct_convention_ftype ia64_use_struct_convention;
 static struct type *is_float_or_hfa_type (struct type *t);
 
@@ -108,7 +111,7 @@ static int fp_regnum = IA64_VFP_REGNUM;
 static int lr_regnum = IA64_VRAP_REGNUM;
 
 /* NOTE: we treat the register stack registers r32-r127 as pseudo-registers because
-   they are in memory and must be calculated via the bsp register.  */
+   they may not be accessible via the ptrace register get/set interfaces.  */
 enum pseudo_regs { FIRST_PSEUDO_REGNUM = NUM_IA64_RAW_REGS, VBOF_REGNUM = IA64_NAT127_REGNUM + 1, V32_REGNUM, 
                   V127_REGNUM = V32_REGNUM + 95, 
                   VP0_REGNUM, VP16_REGNUM = VP0_REGNUM + 16, VP63_REGNUM = VP0_REGNUM + 63, LAST_PSEUDO_REGNUM };
@@ -232,6 +235,7 @@ struct ia64_frame_cache
   CORE_ADDR saved_sp;  /* stack pointer for frame */
   CORE_ADDR bsp;       /* points at r32 for the current frame */
   CORE_ADDR cfm;       /* cfm value for current frame */
+  CORE_ADDR prev_cfm;   /* cfm value for previous frame */
   int   frameless;
   int   sof;           /* Size of frame  (decoded from cfm value) */
   int  sol;            /* Size of locals (decoded from cfm value) */
@@ -255,9 +259,6 @@ struct ia64_frame_cache
 
 struct gdbarch_tdep
   {
-    int os_ident;      /* From the ELF header, one of the ELFOSABI_
-                           constants: ELFOSABI_LINUX, ELFOSABI_AIX,
-                          etc. */
     CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
                        /* OS specific function which, given a frame address
                           and register number, returns the offset to the
@@ -316,39 +317,19 @@ ia64_dwarf_reg_to_regnum (int reg)
   return reg;
 }
 
+static int
+floatformat_valid (const struct floatformat *fmt, const char *from)
+{
+  return 1;
+}
+
 const struct floatformat floatformat_ia64_ext =
 {
   floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
-  floatformat_intbit_yes
+  floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
 };
 
 
-/* Read the given register from a sigcontext structure in the
-   specified frame.  */
-
-static CORE_ADDR
-read_sigcontext_register (struct frame_info *frame, int regnum)
-{
-  CORE_ADDR regaddr;
-
-  if (frame == NULL)
-    internal_error (__FILE__, __LINE__,
-                   "read_sigcontext_register: NULL frame");
-  if (!(get_frame_type (frame) == SIGTRAMP_FRAME))
-    internal_error (__FILE__, __LINE__,
-                   "read_sigcontext_register: frame not a signal trampoline");
-  if (SIGCONTEXT_REGISTER_ADDRESS == 0)
-    internal_error (__FILE__, __LINE__,
-                   "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0");
-
-  regaddr = SIGCONTEXT_REGISTER_ADDRESS (get_frame_base (frame), regnum);
-  if (regaddr)
-    return read_memory_integer (regaddr, REGISTER_RAW_SIZE (regnum));
-  else
-    internal_error (__FILE__, __LINE__,
-                   "read_sigcontext_register: Register %d not in struct sigcontext", regnum);
-}
-
 /* Extract ``len'' bits from an instruction bundle starting at
    bit ``from''.  */
 
@@ -638,18 +619,6 @@ ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
   return breakpoint;
 }
 
-static CORE_ADDR
-ia64_read_fp (void)
-{
-  /* We won't necessarily have a frame pointer and even if we do, it
-     winds up being extraordinarly messy when attempting to find the
-     frame chain.  So for the purposes of creating frames (which is
-     all deprecated_read_fp() is used for), simply use the stack
-     pointer value instead.  */
-  gdb_assert (SP_REGNUM >= 0);
-  return read_register (SP_REGNUM);
-}
-
 static CORE_ADDR
 ia64_read_pc (ptid_t ptid)
 {
@@ -660,7 +629,7 @@ ia64_read_pc (ptid_t ptid)
   return pc_value | (slot_num * SLOT_MULTIPLIER);
 }
 
-static void
+void
 ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
 {
   int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
@@ -716,10 +685,10 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
        {
          ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
          reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
-         store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), reg);
+         store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
        }
       else
-       store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), 0);
+       store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
     }
   else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
     {
@@ -727,7 +696,7 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       ULONGEST unat;
       regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
       unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0;
-      store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), unatN_val);
+      store_unsigned_integer (buf, register_size (current_gdbarch, regnum), unatN_val);
     }
   else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
     {
@@ -762,7 +731,7 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
          natN_val = (nat_collection >> nat_bit) & 1;
        }
       
-      store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), natN_val);
+      store_unsigned_integer (buf, register_size (current_gdbarch, regnum), natN_val);
     }
   else if (regnum == VBOF_REGNUM)
     {
@@ -777,7 +746,7 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       /* The bsp points at the end of the register frame so we
         subtract the size of frame from it to get beginning of frame.  */
       vbsp = rse_address_add (bsp, -(cfm & 0x7f));
-      store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), vbsp);
+      store_unsigned_integer (buf, register_size (current_gdbarch, regnum), vbsp);
     }
   else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
     {
@@ -799,10 +768,10 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
                 + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
        }
       prN_val = (pr & (1LL << (regnum - VP0_REGNUM))) != 0;
-      store_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum), prN_val);
+      store_unsigned_integer (buf, register_size (current_gdbarch, regnum), prN_val);
     }
   else
-    memset (buf, 0, REGISTER_RAW_SIZE (regnum));
+    memset (buf, 0, register_size (current_gdbarch, regnum));
 }
 
 static void
@@ -829,7 +798,7 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
     {
       ULONGEST unatN_val, unat, unatN_mask;
       regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
-      unatN_val = extract_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum)); 
+      unatN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); 
       unatN_mask = (1LL << (regnum - IA64_NAT0_REGNUM));
       if (unatN_val == 0)
        unat &= ~unatN_mask;
@@ -853,7 +822,7 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
       if ((cfm & 0x7f) > regnum - V32_REGNUM) 
        gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
       
-      natN_val = extract_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum)); 
+      natN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); 
 
       if (gr_addr != 0 && (natN_val == 0 || natN_val == 1))
        {
@@ -882,7 +851,7 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
                nat_collection |= natN_mask;
              else
                nat_collection &= ~natN_mask;
-             store_unsigned_integer (nat_buf, REGISTER_RAW_SIZE (regnum), nat_collection);
+             store_unsigned_integer (nat_buf, register_size (current_gdbarch, regnum), nat_collection);
              write_memory (nat_addr, nat_buf, 8);
            }
        }
@@ -907,7 +876,7 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
          regnum = VP16_REGNUM 
                 + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
        }
-      prN_val = extract_unsigned_integer (buf, REGISTER_RAW_SIZE (regnum)); 
+      prN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); 
       prN_mask = (1LL << (regnum - VP0_REGNUM));
       if (prN_val == 0)
        pr &= ~prN_mask;
@@ -959,6 +928,9 @@ static int max_skip_non_prologue_insns = 40;
    used with no further scanning in the event that the function is
    frameless.  */
 
+/* FIXME: cagney/2004-02-14: This function and logic have largely been
+   superseded by skip_prologue_using_sal.  */
+
 static CORE_ADDR
 refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
 {
@@ -1030,6 +1002,7 @@ ia64_alloc_frame_cache (void)
   cache->base = 0;
   cache->pc = 0;
   cache->cfm = 0;
+  cache->prev_cfm = 0;
   cache->sof = 0;
   cache->sol = 0;
   cache->sor = 0;
@@ -1144,7 +1117,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame,
       if (next_pc == 0)
        break;
 
-      if (it == B && ((instr & 0x1e1f800003f) != 0x04000000000))
+      if (it == B && ((instr & 0x1e1f800003fLL) != 0x04000000000LL))
        {
          /* Exit loop upon hitting a non-nop branch instruction. */ 
          if (trust_limit)
@@ -1256,7 +1229,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame,
            {
              cache->saved_regs[IA64_FR0_REGNUM + fM] = spill_addr;
 
-              if ((instr & 0x1efc0000000) == 0x0eec0000000)
+              if ((instr & 0x1efc0000000LL) == 0x0eec0000000LL)
                spill_addr += imm;
              else
                spill_addr = 0;         /* last one; must be done */
@@ -1450,9 +1423,20 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame,
 
       /* For the previous argument registers we require the previous bof.  
         If we can't find the previous cfm, then we can do nothing.  */
+      cfm = 0;
       if (cache->saved_regs[IA64_CFM_REGNUM] != 0)
        {
          cfm = read_memory_integer (cache->saved_regs[IA64_CFM_REGNUM], 8);
+       }
+      else if (cfm_reg != 0)
+       {
+         frame_unwind_register (next_frame, cfm_reg, buf);
+         cfm = extract_unsigned_integer (buf, 8);
+       }
+      cache->prev_cfm = cfm;
+      
+      if (cfm != 0)
+       {
          sor = ((cfm >> 14) & 0xf) * 8;
          sof = (cfm & 0x7f);
          sol = (cfm >> 7) & 0x7f;
@@ -1564,7 +1548,13 @@ ia64_frame_this_id (struct frame_info *next_frame, void **this_cache,
   if (cache->base == 0)
     return;
 
-  (*this_id) = frame_id_build (cache->base, cache->pc);
+  (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "regular frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+                       paddr_nz (this_id->code_addr), 
+                       paddr_nz (this_id->stack_addr), 
+                       paddr_nz (cache->bsp), next_frame);
 }
 
 static void
@@ -1593,12 +1583,12 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
   if (!valuep)
     valuep = dummy_valp;
   
-  memset (valuep, 0, REGISTER_RAW_SIZE (regnum));
+  memset (valuep, 0, register_size (current_gdbarch, regnum));
  
   if (regnum == SP_REGNUM)
     {
       /* Handle SP values for all frames but the topmost. */
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (regnum),
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
                              cache->base);
     }
   else if (regnum == IA64_BSP_REGNUM)
@@ -1613,7 +1603,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
       /* We want to calculate the previous bsp as the end of the previous register stack frame.
         This corresponds to what the hardware bsp register will be if we pop the frame
         back which is why we might have been called.  We know the beginning of the current
-         frame is cache->bsp - cache->sof.  This value in the previous frame points to
+        frame is cache->bsp - cache->sof.  This value in the previous frame points to
         the start of the output registers.  We can calculate the end of that frame by adding
         the size of output (sof (size of frame) - sol (size of locals)).  */
       ia64_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
@@ -1623,23 +1613,25 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
       bsp = rse_address_add (cache->bsp, -(cache->sof));
       prev_bsp = rse_address_add (bsp, (prev_cfm & 0x7f) - ((prev_cfm >> 7) & 0x7f));
 
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (regnum), 
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), 
                              prev_bsp);
     }
   else if (regnum == IA64_CFM_REGNUM)
     {
-      CORE_ADDR addr = 0;
-
-      if (cache->frameless)
+      CORE_ADDR addr = cache->saved_regs[IA64_CFM_REGNUM];
+      
+      if (addr != 0)
        {
-         CORE_ADDR cfm = 0;
-         frame_unwind_register (next_frame, IA64_PFS_REGNUM, valuep);
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
        }
-      else
+      else if (cache->prev_cfm)
+       store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), cache->prev_cfm);
+      else if (cache->frameless)
        {
-         addr = cache->saved_regs[IA64_CFM_REGNUM];
-         if (addr != 0)
-           read_memory (addr, valuep, REGISTER_RAW_SIZE (regnum));
+         CORE_ADDR cfm = 0;
+         frame_unwind_register (next_frame, IA64_PFS_REGNUM, valuep);
        }
     }
   else if (regnum == IA64_VFP_REGNUM)
@@ -1649,7 +1641,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
         above.  If the function lacks one of these frame pointers, we can
         still provide a value since we know the size of the frame.  */
       CORE_ADDR vfp = cache->base;
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (IA64_VFP_REGNUM), vfp);
+      store_unsigned_integer (valuep, register_size (current_gdbarch, IA64_VFP_REGNUM), vfp);
     }
   else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
     {
@@ -1673,7 +1665,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
        }
       prN_val = extract_bit_field ((unsigned char *) pr_valuep,
                                    regnum - VP0_REGNUM, 1);
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (regnum), prN_val);
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
     }
   else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
     {
@@ -1687,7 +1679,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
                                &unat_optim, &unat_lval, &unat_addr, &unat_realnum, unat_valuep);
       unatN_val = extract_bit_field ((unsigned char *) unat_valuep,
                                    regnum - IA64_NAT0_REGNUM, 1);
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (regnum), 
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), 
                               unatN_val);
     }
   else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
@@ -1722,58 +1714,73 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
          natval = (nat_collection >> nat_bit) & 1;
        }
 
-      store_unsigned_integer (valuep, REGISTER_RAW_SIZE (regnum), natval);
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), natval);
     }
   else if (regnum == IA64_IP_REGNUM)
     {
       CORE_ADDR pc = 0;
+      CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
 
-      if (cache->frameless)
+      if (addr != 0)
        {
-         frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
          pc = extract_unsigned_integer (buf, 8);
        }
-      else
+      else if (cache->frameless)
        {
-         CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
-         if (addr != 0)
-           {
-             read_memory (addr, buf, REGISTER_RAW_SIZE (IA64_IP_REGNUM));
-             pc = extract_unsigned_integer (buf, 8);
-           }
+         frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+         pc = extract_unsigned_integer (buf, 8);
        }
       pc &= ~0xf;
       store_unsigned_integer (valuep, 8, pc);
     }
   else if (regnum == IA64_PSR_REGNUM)
     {
+      /* We don't know how to get the complete previous PSR, but we need it for
+        the slot information when we unwind the pc (pc is formed of IP register
+        plus slot information from PSR).  To get the previous slot information, 
+        we mask it off the return address.  */
       ULONGEST slot_num = 0;
       CORE_ADDR pc= 0;
       CORE_ADDR psr = 0;
+      CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
 
       frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
       psr = extract_unsigned_integer (buf, 8);
 
-      if (cache->frameless)
+      if (addr != 0)
        {
-         CORE_ADDR pc;
-         frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
          pc = extract_unsigned_integer (buf, 8);
        }
-      else
+      else if (cache->frameless)
        {
-         CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
-         if (addr != 0)
-           {
-             read_memory (addr, buf, REGISTER_RAW_SIZE (IA64_IP_REGNUM));
-             pc = extract_unsigned_integer (buf, 8);
-           }
+         CORE_ADDR pc;
+         frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf);
+         pc = extract_unsigned_integer (buf, 8);
        }
       psr &= ~(3LL << 41);
       slot_num = pc & 0x3LL;
       psr |= (CORE_ADDR)slot_num << 41;
       store_unsigned_integer (valuep, 8, psr);
     }
+  else if (regnum == IA64_BR0_REGNUM)
+    {
+      CORE_ADDR br0 = 0;
+      CORE_ADDR addr = cache->saved_regs[IA64_BR0_REGNUM];
+      if (addr != 0)
+       {
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, buf, register_size (current_gdbarch, IA64_BR0_REGNUM));
+         br0 = extract_unsigned_integer (buf, 8);
+       }
+      store_unsigned_integer (valuep, 8, br0);
+    }
  else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) ||
           (regnum >= V32_REGNUM && regnum <= V127_REGNUM))
     {
@@ -1785,7 +1792,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
        {
          *lvalp = lval_memory;
          *addrp = addr;
-         read_memory (addr, valuep, REGISTER_RAW_SIZE (regnum));
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
        }
       else if (cache->frameless)
         {
@@ -1809,7 +1816,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
          addr = rse_address_add (prev_bof, (regnum - IA64_GR32_REGNUM));
          *lvalp = lval_memory;
          *addrp = addr;
-         read_memory (addr, valuep, REGISTER_RAW_SIZE (regnum));
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
         }
     }
   else
@@ -1833,12 +1840,19 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
        {
          *lvalp = lval_memory;
          *addrp = addr;
-         read_memory (addr, valuep, REGISTER_RAW_SIZE (regnum));
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
        }
       /* Otherwise, punt and get the current value of the register.  */
       else 
        frame_unwind_register (next_frame, regnum, valuep);
     }
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "regular prev register <%d> <%s> is 0x%s\n", regnum, 
+                       (((unsigned) regnum <= IA64_NAT127_REGNUM)
+                        ? ia64_register_names[regnum] : "r??"), 
+                       paddr_nz (extract_unsigned_integer (valuep, 8)));
 }
  
 static const struct frame_unwind ia64_frame_unwind =
@@ -1869,10 +1883,8 @@ ia64_sigtramp_frame_init_saved_regs (struct ia64_frame_cache *cache)
        SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CFM_REGNUM);
       cache->saved_regs[IA64_PSR_REGNUM] = 
        SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PSR_REGNUM);
-#if 0
       cache->saved_regs[IA64_BSP_REGNUM] = 
-       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_BSP_REGNUM);
-#endif
+       SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_BSP_REGNUM);
       cache->saved_regs[IA64_RNAT_REGNUM] = 
        SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_RNAT_REGNUM);
       cache->saved_regs[IA64_CCV_REGNUM] = 
@@ -1886,9 +1898,8 @@ ia64_sigtramp_frame_init_saved_regs (struct ia64_frame_cache *cache)
       cache->saved_regs[IA64_LC_REGNUM] = 
        SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_LC_REGNUM);
       for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
-       if (regno != sp_regnum)
-         cache->saved_regs[regno] =
-           SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+       cache->saved_regs[regno] =
+         SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
       for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
        cache->saved_regs[regno] =
          SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
@@ -1912,7 +1923,16 @@ ia64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
   cache = ia64_alloc_frame_cache ();
 
   frame_unwind_register (next_frame, sp_regnum, buf);
-  cache->base = extract_unsigned_integer (buf, 8) + cache->mem_stack_frame_size;
+  /* Note that frame size is hard-coded below.  We cannot calculate it
+     via prologue examination.  */
+  cache->base = extract_unsigned_integer (buf, 8) + 16;
+
+  frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+  cache->bsp = extract_unsigned_integer (buf, 8);
+
+  frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+  cache->cfm = extract_unsigned_integer (buf, 8);
+  cache->sof = cache->cfm & 0x7f;
 
   ia64_sigtramp_frame_init_saved_regs (cache);
 
@@ -1927,7 +1947,13 @@ ia64_sigtramp_frame_this_id (struct frame_info *next_frame,
   struct ia64_frame_cache *cache =
     ia64_sigtramp_frame_cache (next_frame, this_cache);
 
-  (*this_id) = frame_id_build (cache->base, frame_pc_unwind (next_frame));
+  (*this_id) = frame_id_build_special (cache->base, frame_pc_unwind (next_frame), cache->bsp);
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "sigtramp frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+                       paddr_nz (this_id->code_addr), 
+                       paddr_nz (this_id->stack_addr), 
+                       paddr_nz (cache->bsp), next_frame);
 }
 
 static void
@@ -1937,11 +1963,76 @@ ia64_sigtramp_frame_prev_register (struct frame_info *next_frame,
                                   enum lval_type *lvalp, CORE_ADDR *addrp,
                                   int *realnump, void *valuep)
 {
-  /* Make sure we've initialized the cache.  */
-  ia64_sigtramp_frame_cache (next_frame, this_cache);
+  char dummy_valp[MAX_REGISTER_SIZE];
+  char buf[MAX_REGISTER_SIZE];
+
+  struct ia64_frame_cache *cache =
+    ia64_sigtramp_frame_cache (next_frame, this_cache);
+
+  gdb_assert (regnum >= 0);
+
+  if (!target_has_registers)
+    error ("No registers.");
+
+  *optimizedp = 0;
+  *addrp = 0;
+  *lvalp = not_lval;
+  *realnump = -1;
+
+  /* Rather than check each time if valuep is non-null, supply a dummy buffer
+     when valuep is not supplied.  */
+  if (!valuep)
+    valuep = dummy_valp;
+  
+  memset (valuep, 0, register_size (current_gdbarch, regnum));
+  if (regnum == IA64_IP_REGNUM)
+    {
+      CORE_ADDR pc = 0;
+      CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM];
 
-  ia64_frame_prev_register (next_frame, this_cache, regnum,
-                           optimizedp, lvalp, addrp, realnump, valuep);
+      if (addr != 0)
+       {
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+         pc = extract_unsigned_integer (buf, 8);
+       }
+      pc &= ~0xf;
+      store_unsigned_integer (valuep, 8, pc);
+    }
+ else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) ||
+          (regnum >= V32_REGNUM && regnum <= V127_REGNUM))
+    {
+      CORE_ADDR addr = 0;
+      if (regnum >= V32_REGNUM)
+       regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM);
+      addr = cache->saved_regs[regnum];
+      if (addr != 0)
+       {
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+       }
+    }
+  else
+    {
+      /* All other registers not listed above.  */
+      CORE_ADDR addr = cache->saved_regs[regnum];
+      if (addr != 0)
+       {
+         *lvalp = lval_memory;
+         *addrp = addr;
+         read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+       }
+    }
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "sigtramp prev register <%s> is 0x%s\n",
+                       (((unsigned) regnum <= IA64_NAT127_REGNUM)
+                        ? ia64_register_names[regnum] : "r??"), 
+                       paddr_nz (extract_unsigned_integer (valuep, 8)));
 }
 
 static const struct frame_unwind ia64_sigtramp_frame_unwind =
@@ -1958,7 +2049,7 @@ ia64_sigtramp_frame_sniffer (struct frame_info *next_frame)
   CORE_ADDR pc = frame_pc_unwind (next_frame);
 
   find_pc_partial_function (pc, &name, NULL, NULL);
-  if (PC_IN_SIGTRAMP (pc, name))
+  if (legacy_pc_in_sigtramp (pc, name))
     return &ia64_sigtramp_frame_unwind;
 
   return NULL;
@@ -1982,9 +2073,628 @@ static const struct frame_base ia64_frame_base =
   ia64_frame_base_address
 };
 
-/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
-   EXTRACT_RETURN_VALUE?  GCC_P is true if compiled with gcc
-   and TYPE is the type (which is known to be struct, union or array).  */
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+struct ia64_unwind_table_entry
+  {
+    unw_word_t start_offset;
+    unw_word_t end_offset;
+    unw_word_t info_offset;
+  };
+
+static __inline__ uint64_t
+ia64_rse_slot_num (uint64_t addr)
+{
+  return (addr >> 3) & 0x3f;
+}
+
+/* Skip over a designated number of registers in the backing
+   store, remembering every 64th position is for NAT.  */
+static __inline__ uint64_t
+ia64_rse_skip_regs (uint64_t addr, long num_regs)
+{
+  long delta = ia64_rse_slot_num(addr) + num_regs;
+
+  if (num_regs < 0)
+    delta -= 0x3e;
+  return addr + ((num_regs + delta/0x3f) << 3);
+}
+  
+/* Gdb libunwind-frame callback function to convert from an ia64 gdb register 
+   number to a libunwind register number.  */
+static int
+ia64_gdb2uw_regnum (int regnum)
+{
+  if (regnum == sp_regnum)
+    return UNW_IA64_SP;
+  else if (regnum == IA64_BSP_REGNUM)
+    return UNW_IA64_BSP;
+  else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
+    return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
+  else if ((unsigned) (regnum - V32_REGNUM) < 95)
+    return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
+  else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
+    return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
+  else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
+    return -1;
+  else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
+    return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
+  else if (regnum == IA64_PR_REGNUM)
+    return UNW_IA64_PR;
+  else if (regnum == IA64_IP_REGNUM)
+    return UNW_REG_IP;
+  else if (regnum == IA64_CFM_REGNUM)
+    return UNW_IA64_CFM;
+  else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
+    return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
+  else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
+    return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
+  else
+    return -1;
+}
+  
+/* Gdb libunwind-frame callback function to convert from a libunwind register 
+   number to a ia64 gdb register number.  */
+static int
+ia64_uw2gdb_regnum (int uw_regnum)
+{
+  if (uw_regnum == UNW_IA64_SP)
+    return sp_regnum;
+  else if (uw_regnum == UNW_IA64_BSP)
+    return IA64_BSP_REGNUM;
+  else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
+    return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
+  else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
+    return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
+  else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
+    return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
+  else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
+    return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
+  else if (uw_regnum == UNW_IA64_PR)
+    return IA64_PR_REGNUM;
+  else if (uw_regnum == UNW_REG_IP)
+    return IA64_IP_REGNUM;
+  else if (uw_regnum == UNW_IA64_CFM)
+    return IA64_CFM_REGNUM;
+  else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
+    return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
+  else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
+    return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
+  else
+    return -1;
+}
+
+/* Gdb libunwind-frame callback function to reveal if register is a float 
+   register or not.  */
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+  return unw_is_fpreg (uw_regnum);
+}
+  
+/* Libunwind callback accessor function for general registers.  */
+static int
+ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val, 
+                int write, void *arg)
+{
+  int regnum = ia64_uw2gdb_regnum (uw_regnum);
+  unw_word_t bsp, sof, sol, cfm, psr, ip;
+  struct frame_info *next_frame = arg;
+  long new_sof, old_sof;
+  char buf[MAX_REGISTER_SIZE];
+  
+  if (write)
+    {
+      if (regnum < 0)
+       /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI.  */
+       return 0;
+  
+      switch (uw_regnum)
+       {
+       case UNW_REG_IP:
+         ia64_write_pc (*val, inferior_ptid);
+         break;
+
+       case UNW_IA64_AR_BSPSTORE:
+         write_register (IA64_BSP_REGNUM, *val);
+         break;
+         
+       case UNW_IA64_AR_BSP:
+       case UNW_IA64_BSP:
+         /* Account for the fact that ptrace() expects bsp to point
+            after the current register frame.  */
+         cfm = read_register (IA64_CFM_REGNUM);
+         sof = (cfm & 0x7f);
+         bsp = ia64_rse_skip_regs (*val, sof);
+         write_register (IA64_BSP_REGNUM, bsp);
+         break;
+         
+       case UNW_IA64_CFM:
+         /* If we change CFM, we need to adjust ptrace's notion of
+            bsp accordingly, so that the real bsp remains
+            unchanged.  */
+         bsp = read_register (IA64_BSP_REGNUM);
+         cfm = read_register (IA64_CFM_REGNUM);
+         old_sof = (cfm & 0x7f);
+         new_sof = (*val & 0x7f);
+         if (old_sof != new_sof)
+           {
+             bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
+             write_register (IA64_BSP_REGNUM, bsp);
+           }
+         write_register (IA64_CFM_REGNUM, *val);
+         break;
+         
+       default:
+         write_register (regnum, *val);
+         break;
+       }
+      if (gdbarch_debug >= 1)
+       fprintf_unfiltered (gdb_stdlog, 
+                           "  access_reg: to cache: %4s=0x%s\n",
+                           (((unsigned) regnum <= IA64_NAT127_REGNUM)
+                            ? ia64_register_names[regnum] : "r??"), 
+                           paddr_nz (*val));
+    }
+  else
+    {
+      switch (uw_regnum)
+       {
+       case UNW_REG_IP:
+         /* Libunwind expects to see the pc value which means the slot number
+            from the psr must be merged with the ip word address.  */
+         frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+         ip = extract_unsigned_integer (buf, 8); 
+         frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+         psr = extract_unsigned_integer (buf, 8); 
+         *val = ip | ((psr >> 41) & 0x3);
+         break;
+         
+       case UNW_IA64_AR_BSP:
+         /* Libunwind expects to see the beginning of the current register
+            frame so we must account for the fact that ptrace() will return a value
+            for bsp that points *after* the current register frame.  */
+         frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+         bsp = extract_unsigned_integer (buf, 8);
+         frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+         cfm = extract_unsigned_integer (buf, 8); 
+         sof = (cfm & 0x7f);
+         *val = ia64_rse_skip_regs (bsp, -sof);
+         break;
+         
+       case UNW_IA64_AR_BSPSTORE:
+         /* Libunwind wants bspstore to be after the current register frame.
+            This is what ptrace() and gdb treats as the regular bsp value.  */
+         frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+         *val = extract_unsigned_integer (buf, 8);
+         break;
+
+       default:
+         /* For all other registers, just unwind the value directly.  */
+         frame_unwind_register (next_frame, regnum, buf);
+         *val = extract_unsigned_integer (buf, 8); 
+         break;
+       }
+      
+      if (gdbarch_debug >= 1)
+       fprintf_unfiltered (gdb_stdlog, 
+                           "  access_reg: from cache: %4s=0x%s\n",
+                           (((unsigned) regnum <= IA64_NAT127_REGNUM)
+                            ? ia64_register_names[regnum] : "r??"), 
+                           paddr_nz (*val));
+    }
+  return 0;
+}
+
+/* Libunwind callback accessor function for floating-point registers.  */
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val, 
+                  int write, void *arg)
+{
+  int regnum = ia64_uw2gdb_regnum (uw_regnum);
+  
+  if (write)
+    regcache_cooked_write (current_regcache, regnum, (char *) val);
+  else
+    regcache_cooked_read (current_regcache, regnum, (char *) val);
+  return 0;
+}
+
+/* Libunwind callback accessor function for accessing memory.  */
+static int
+ia64_access_mem (unw_addr_space_t as,
+                unw_word_t addr, unw_word_t *val,
+                int write, void *arg)
+{
+  /* XXX do we need to normalize byte-order here?  */
+  if (write)
+    return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+  else
+    return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+/* Call low-level function to access the kernel unwind table.  */
+static int
+getunwind_table (void *buf, size_t len)
+{
+  LONGEST x;
+  x = target_read_partial (&current_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
+                          buf, 0, len);
+
+  return (int)x;
+}
+       
+/* Get the kernel unwind table.  */                             
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+  size_t size;
+  struct ia64_table_entry
+  {
+    uint64_t start_offset;
+    uint64_t end_offset;
+    uint64_t info_offset;
+  };
+  static struct ia64_table_entry *ktab = NULL, *etab;
+
+  if (!ktab)
+    {
+      size = getunwind_table (NULL, 0);
+      if ((int)size < 0)
+       return -UNW_ENOINFO;
+      ktab = xmalloc (size);
+      getunwind_table (ktab, size);
+  
+      /* Determine length of kernel's unwind table and relocate
+        it's entries.  */
+      for (etab = ktab; etab->start_offset; ++etab)
+       etab->info_offset += (uint64_t) ktab;
+    }
+  
+  if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+    return -UNW_ENOINFO;
+  
+  di->format = UNW_INFO_FORMAT_TABLE;
+  di->gp = 0;
+  di->start_ip = ktab[0].start_offset;
+  di->end_ip = etab[-1].end_offset;
+  di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+  di->u.ti.segbase = 0;
+  di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+  di->u.ti.table_data = (unw_word_t *) ktab;
+  
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+                       "segbase=0x%s, length=%s, gp=0x%s\n",
+                       (char *) di->u.ti.name_ptr, 
+                       paddr_nz (di->u.ti.segbase), 
+                       paddr_u (di->u.ti.table_len), 
+                       paddr_nz (di->gp));
+  return 0;
+}
+
+/* Find the unwind table entry for a specified address.  */
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+                       unw_dyn_info_t *dip, void **buf)
+{
+  Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+  Elf_Internal_Ehdr *ehdr;
+  unw_word_t segbase = 0;
+  CORE_ADDR load_base;
+  bfd *bfd;
+  int i;
+
+  bfd = objfile->obfd;
+  
+  ehdr = elf_tdata (bfd)->elf_header;
+  phdr = elf_tdata (bfd)->phdr;
+
+  load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+  for (i = 0; i < ehdr->e_phnum; ++i)
+    {
+      switch (phdr[i].p_type)
+       {
+       case PT_LOAD:
+         if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+             < phdr[i].p_memsz)
+           p_text = phdr + i;
+         break;
+
+       case PT_IA_64_UNWIND:
+         p_unwind = phdr + i;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (!p_text || !p_unwind
+      /* Verify that the segment that contains the IP also contains
+        the static unwind table.  If not, we are dealing with
+        runtime-generated code, for which we have no info here.  */
+      || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+    return -UNW_ENOINFO;
+
+  segbase = p_text->p_vaddr + load_base;
+
+  dip->start_ip = segbase;
+  dip->end_ip = dip->start_ip + p_text->p_memsz;
+  dip->gp = FIND_GLOBAL_POINTER (ip);
+  dip->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+  dip->u.rti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+  dip->u.rti.segbase = segbase;
+  dip->u.rti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+  dip->u.rti.table_data = p_unwind->p_vaddr + load_base;
+
+  return 0;
+}
+
+/* Libunwind callback accessor function to acquire procedure unwind-info.  */
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+                      int need_unwind_info, void *arg)
+{
+  struct obj_section *sec = find_pc_section (ip);
+  unw_dyn_info_t di;
+  int ret;
+  void *buf = NULL;
+
+  if (!sec)
+    {
+      /* XXX This only works if the host and the target architecture are
+        both ia64 and if the have (more or less) the same kernel
+        version.  */
+      if (get_kernel_table (ip, &di) < 0)
+       return -UNW_ENOINFO;
+
+      if (gdbarch_debug >= 1)
+       fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: 0x%s -> "
+                           "(name=`%s',segbase=0x%s,start=0x%s,end=0x%s,gp=0x%s,"
+                           "length=%s,data=0x%s)\n",
+                           paddr_nz (ip), (char *)di.u.ti.name_ptr,
+                           paddr_nz (di.u.ti.segbase), 
+                           paddr_nz (di.start_ip), paddr_nz (di.end_ip),
+                           paddr_nz (di.gp), 
+                           paddr_u (di.u.ti.table_len), 
+                           paddr_nz ((CORE_ADDR)di.u.ti.table_data));
+    }
+  else
+    {
+      ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
+      if (ret < 0)
+       return ret;
+
+      if (gdbarch_debug >= 1)
+       fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: 0x%s -> "
+                           "(name=`%s',segbase=0x%s,start=0x%s,end=0x%s,gp=0x%s,"
+                           "length=%s,data=0x%s)\n",
+                           paddr_nz (ip), (char *)di.u.rti.name_ptr,
+                           paddr_nz (di.u.rti.segbase), 
+                           paddr_nz (di.start_ip), paddr_nz (di.end_ip),
+                           paddr_nz (di.gp), 
+                           paddr_u (di.u.rti.table_len), 
+                           paddr_nz (di.u.rti.table_data));
+    }
+
+  ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info,
+                                      arg);
+
+  /* We no longer need the dyn info storage so free it.  */
+  xfree (buf);
+
+  return ret;
+}
+
+/* Libunwind callback accessor function for cleanup.  */
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+                     unw_proc_info_t *pip, void *arg)
+{
+  /* Nothing required for now.  */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic 
+   unwind-info registration list.  */ 
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+                       unw_word_t *dilap, void *arg)
+{
+  struct obj_section *text_sec;
+  struct objfile *objfile;
+  unw_word_t ip, addr;
+  unw_dyn_info_t di;
+  int ret;
+
+  if (!libunwind_is_initialized ())
+    return -UNW_ENOINFO;
+
+  for (objfile = object_files; objfile; objfile = objfile->next)
+    {
+      void *buf = NULL;
+
+      text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+      ip = text_sec->addr;
+      ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
+      if (ret >= 0)
+       {
+         addr = libunwind_find_dyn_list (as, &di, arg);
+         /* We no longer need the dyn info storage so free it.  */
+         xfree (buf);
+
+         if (addr)
+           {
+             if (gdbarch_debug >= 1)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "dynamic unwind table in objfile %s "
+                                   "at 0x%s (gp=0x%s)\n",
+                                   bfd_get_filename (objfile->obfd),
+                                   paddr_nz (addr), paddr_nz (di.gp));
+             *dilap = addr;
+             return 0;
+           }
+       }
+    }
+  return -UNW_ENOINFO;
+}
+
+
+/* Frame interface functions for libunwind.  */
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                     struct frame_id *this_id)
+{
+  char buf[8];
+  CORE_ADDR bsp;
+  struct frame_id id;
+
+  libunwind_frame_this_id (next_frame, this_cache, &id);
+
+  /* We must add the bsp as the special address for frame comparison purposes.  */
+  frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+  bsp = extract_unsigned_integer (buf, 8);
+
+  (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "libunwind frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
+                       paddr_nz (id.code_addr), paddr_nz (id.stack_addr), 
+                       paddr_nz (bsp), next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+                                   void **this_cache,
+                                   int regnum, int *optimizedp,
+                                   enum lval_type *lvalp, CORE_ADDR *addrp,
+                                   int *realnump, void *valuep)
+{
+  int reg = regnum;
+
+  if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+    reg = IA64_PR_REGNUM;
+  else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+    reg = IA64_UNAT_REGNUM;
+
+  /* Let libunwind do most of the work.  */
+  libunwind_frame_prev_register (next_frame, this_cache, reg,
+                                optimizedp, lvalp, addrp, realnump, valuep);
+
+  /* No more to do if the value is not supposed to be supplied.  */
+  if (!valuep)
+    return;
+
+  if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+    {
+      ULONGEST prN_val;
+
+      if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+       {
+         int rrb_pr = 0;
+         ULONGEST cfm;
+         unsigned char buf[MAX_REGISTER_SIZE];
+
+         /* Fetch predicate register rename base from current frame
+            marker for this frame.  */
+         frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+         cfm = extract_unsigned_integer (buf, 8); 
+         rrb_pr = (cfm >> 32) & 0x3f;
+         
+         /* Adjust the register number to account for register rotation.  */
+         regnum = VP16_REGNUM 
+           + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+       }
+      prN_val = extract_bit_field ((unsigned char *) valuep,
+                                  regnum - VP0_REGNUM, 1);
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+    }
+  else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+    {
+      ULONGEST unatN_val;
+
+      unatN_val = extract_bit_field ((unsigned char *) valuep,
+                                   regnum - IA64_NAT0_REGNUM, 1);
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), 
+                              unatN_val);
+    }
+  else if (regnum == IA64_BSP_REGNUM)
+    {
+      char cfm_valuep[MAX_REGISTER_SIZE];
+      int  cfm_optim;
+      int  cfm_realnum;
+      enum lval_type cfm_lval;
+      CORE_ADDR cfm_addr;
+      CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+      /* We want to calculate the previous bsp as the end of the previous register stack frame.
+        This corresponds to what the hardware bsp register will be if we pop the frame
+        back which is why we might have been called.  We know that libunwind will pass us back
+        the beginning of the current frame so we should just add sof to it. */
+      prev_bsp = extract_unsigned_integer (valuep, 8);
+      libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+                                    &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+      prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+      prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+      store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), 
+                             prev_bsp);
+    }
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "libunwind prev register <%s> is 0x%s\n",
+                       (((unsigned) regnum <= IA64_NAT127_REGNUM)
+                        ? ia64_register_names[regnum] : "r??"), 
+                       paddr_nz (extract_unsigned_integer (valuep, 8)));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+  NORMAL_FRAME,
+  ia64_libunwind_frame_this_id,
+  ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+  if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+    return &ia64_libunwind_frame_unwind;
+
+  return NULL;
+}
+
+/* Set of libunwind callback acccessor functions.  */
+static unw_accessors_t ia64_unw_accessors =
+{
+  ia64_find_proc_info_x,
+  ia64_put_unwind_info,
+  ia64_get_dyn_info_list,
+  ia64_access_mem,
+  ia64_access_reg,
+  ia64_access_fpreg,
+  /* resume */
+  /* get_proc_name */
+};
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use.  */
+static struct libunwind_descr ia64_libunwind_descr =
+{
+  ia64_gdb2uw_regnum, 
+  ia64_uw2gdb_regnum, 
+  ia64_is_fpreg, 
+  &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H  */
+
+/* Should we use DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS instead of
+   EXTRACT_RETURN_VALUE?  GCC_P is true if compiled with gcc and TYPE
+   is the type (which is known to be struct, union or array).  */
 int
 ia64_use_struct_convention (int gcc_p, struct type *type)
 {
@@ -2293,7 +3003,8 @@ find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
    so the user can see the function address rather than just the
    function descriptor.  */
 static CORE_ADDR
-ia64_convert_from_func_ptr_addr (CORE_ADDR addr)
+ia64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+                                struct target_ops *targ)
 {
   struct obj_section *s;
 
@@ -2313,7 +3024,7 @@ ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 }
 
 static CORE_ADDR
-ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, 
+ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
                      int struct_return, CORE_ADDR struct_addr)
@@ -2325,6 +3036,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   int nslots, rseslots, memslots, slotnum, nfuncargs;
   int floatreg;
   CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr, pc, global_pointer;
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
 
   nslots = 0;
   nfuncargs = 0;
@@ -2473,12 +3185,21 @@ static struct frame_id
 ia64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   char buf[8];
-  CORE_ADDR sp;
+  CORE_ADDR sp, bsp;
 
   frame_unwind_register (next_frame, sp_regnum, buf);
   sp = extract_unsigned_integer (buf, 8);
 
-  return frame_id_build (sp, frame_pc_unwind (next_frame));
+  frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+  bsp = extract_unsigned_integer (buf, 8);
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "dummy frame id: code 0x%s, stack 0x%s, special 0x%s\n",
+                       paddr_nz (frame_pc_unwind (next_frame)), 
+                       paddr_nz (sp), paddr_nz (bsp));
+
+  return frame_id_build_special (sp, frame_pc_unwind (next_frame), bsp);
 }
 
 static CORE_ADDR 
@@ -2520,53 +3241,6 @@ ia64_remote_translate_xfer_address (struct gdbarch *gdbarch,
   *targ_len  = nr_bytes;
 }
 
-static void
-process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
-{
-  int *os_ident_ptr = obj;
-  const char *name;
-  unsigned int sectsize;
-
-  name = bfd_get_section_name (abfd, sect);
-  sectsize = bfd_section_size (abfd, sect);
-  if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
-    {
-      unsigned int name_length, data_length, note_type;
-      char *note = alloca (sectsize);
-
-      bfd_get_section_contents (abfd, sect, note,
-                                (file_ptr) 0, (bfd_size_type) sectsize);
-
-      name_length = bfd_h_get_32 (abfd, note);
-      data_length = bfd_h_get_32 (abfd, note + 4);
-      note_type   = bfd_h_get_32 (abfd, note + 8);
-
-      if (name_length == 4 && data_length == 16 && note_type == 1
-          && strcmp (note + 12, "GNU") == 0)
-       {
-         int os_number = bfd_h_get_32 (abfd, note + 16);
-
-         /* The case numbers are from abi-tags in glibc.  */
-         switch (os_number)
-           {
-           case 0 :
-             *os_ident_ptr = ELFOSABI_LINUX;
-             break;
-           case 1 :
-             *os_ident_ptr = ELFOSABI_HURD;
-             break;
-           case 2 :
-             *os_ident_ptr = ELFOSABI_SOLARIS;
-             break;
-           default :
-             internal_error (__FILE__, __LINE__,
-                             "process_note_abi_sections: unknown OS number %d", os_number);
-             break;
-           }
-       }
-    }
-}
-
 static int
 ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
 {
@@ -2579,47 +3253,21 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
-  int os_ident;
 
-  if (info.abfd != NULL
-      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
-    {
-      os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
-
-      /* If os_ident is 0, it is not necessarily the case that we're
-         on a SYSV system.  (ELFOSABI_NONE is defined to be 0.)
-         GNU/Linux uses a note section to record OS/ABI info, but
-         leaves e_ident[EI_OSABI] zero.  So we have to check for note
-         sections too.  */
-      if (os_ident == 0)
-       {
-         bfd_map_over_sections (info.abfd,
-                                process_note_abi_tag_sections,
-                                &os_ident);
-       }
-    }
-  else
-    os_ident = -1;
-
-  for (arches = gdbarch_list_lookup_by_info (arches, &info);
-       arches != NULL;
-       arches = gdbarch_list_lookup_by_info (arches->next, &info))
-    {
-      tdep = gdbarch_tdep (arches->gdbarch);
-      if (tdep &&tdep->os_ident == os_ident)
-       return arches->gdbarch;
-    }
+  /* If there is already a candidate, use it.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
 
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
-  tdep->os_ident = os_ident;
 
   /* Set the method of obtaining the sigcontext addresses at which
      registers are saved.  The method of checking to see if
      native_find_global_pointer is nonzero to indicate that we're
      on AIX is kind of hokey, but I can't think of a better way
      to do it.  */
-  if (os_ident == ELFOSABI_LINUX)
+  if (info.osabi == GDB_OSABI_LINUX)
     tdep->sigcontext_register_address = ia64_linux_sigcontext_register_address;
   else if (native_find_global_pointer != 0)
     tdep->sigcontext_register_address = ia64_aix_sigcontext_register_address;
@@ -2633,7 +3281,7 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      generic_elf_find_global_pointer.  This arrangement should (in
      theory) allow us to cross debug GNU/Linux binaries from an AIX
      machine.  */
-  if (os_ident == ELFOSABI_LINUX)
+  if (info.osabi == GDB_OSABI_LINUX)
     tdep->find_global_pointer = generic_elf_find_global_pointer;
   else if (native_find_global_pointer != 0)
     tdep->find_global_pointer = native_find_global_pointer;
@@ -2646,6 +3294,16 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                0, "builtin_type_ia64_ext", NULL);
   TYPE_FLOATFORMAT (builtin_type_ia64_ext) = &floatformat_ia64_ext;
 
+  /* According to the ia64 specs, instructions that store long double
+     floats in memory use a long-double format different than that
+     used in the floating registers.  The memory format matches the
+     x86 extended float format which is 80 bits.  An OS may choose to
+     use this format (e.g. GNU/Linux) or choose to use a different
+     format for storing long doubles (e.g. HPUX).  In the latter case,
+     the setting of the format may be moved/overridden in an
+     OS-specific tdep file.  */
+  set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+
   set_gdbarch_short_bit (gdbarch, 16);
   set_gdbarch_int_bit (gdbarch, 32);
   set_gdbarch_long_bit (gdbarch, 64);
@@ -2680,13 +3338,16 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_extract_return_value (gdbarch, ia64_extract_return_value);
 
   set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
-  set_gdbarch_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
 
   set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
   set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
   set_gdbarch_breakpoint_from_pc (gdbarch, ia64_breakpoint_from_pc);
   set_gdbarch_read_pc (gdbarch, ia64_read_pc);
-  set_gdbarch_write_pc (gdbarch, ia64_write_pc);
+  if (info.osabi == GDB_OSABI_LINUX)
+    set_gdbarch_write_pc (gdbarch, ia64_linux_write_pc);
+  else
+    set_gdbarch_write_pc (gdbarch, ia64_write_pc);
 
   /* Settings for calling functions in the inferior.  */
   set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
@@ -2695,16 +3356,16 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
   frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+  frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+  libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
   frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
   frame_base_set_default (gdbarch, &ia64_frame_base);
 
   /* Settings that should be unnecessary.  */
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
 
-  set_gdbarch_decr_pc_after_break (gdbarch, 0);
-  set_gdbarch_function_start_offset (gdbarch, 0);
-  set_gdbarch_frame_args_skip (gdbarch, 0);
-
   set_gdbarch_remote_translate_xfer_address (
     gdbarch, ia64_remote_translate_xfer_address);
 
This page took 0.041106 seconds and 4 git commands to generate.