* NEWS: Mention pointer to member improvements.
[deliverable/binutils-gdb.git] / gdb / ia64-tdep.c
index 7f973b98bb9a75b8bb2b28d7c56eb6391eee2a37..00faa3b106bb72e11755e9f2b297363cac1e61df 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 (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #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 "osabi.h"
+#include "ia64-tdep.h"
+#include "cp-abi.h"
+
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "elf/ia64.h"           /* for PT_IA_64_UNWIND value */
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+
+/* Note: KERNEL_START is supposed to be an address which is not going
+         to ever contain any valid unwind info.  For ia64 linux, the choice
+         of 0xc000000000000000 is fairly safe since that's uncached space.
+         We use KERNEL_START as follows: after obtaining the kernel's
+         unwind table via getunwind(), we project its unwind data into
+         address-range KERNEL_START-(KERNEL_START+ktab_size) and then
+         when ia64_access_mem() sees a memory access to this
+         address-range, we redirect it to ktab instead.
 
-/* Hook for determining the global pointer when calling functions in
-   the inferior under AIX.  The initialization code in ia64-aix-nat.c
-   sets this hook to the address of a function which will find the
-   global pointer for a given address.  
-   
-   The generic code which uses the dynamic section in the inferior for
-   finding the global pointer is not of much use on AIX since the
-   values obtained from the inferior have not been relocated.  */
+         None of this hackery is needed with a modern kernel/libcs
+         which uses the kernel virtual DSO to provide access to the
+         kernel's unwind info.  In that case, ktab_size remains 0 and
+         hence the value of KERNEL_START doesn't matter.  */
+
+#define KERNEL_START 0xc000000000000000ULL
+
+static size_t ktab_size = 0;
+struct ia64_table_entry
+  {
+    uint64_t start_offset;
+    uint64_t end_offset;
+    uint64_t info_offset;
+  };
+
+static struct ia64_table_entry *ktab = NULL;
 
-CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0;
+#endif
 
 /* An enumeration of the different IA-64 instruction types.  */
 
@@ -84,20 +111,14 @@ 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;
 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);
+static CORE_ADDR ia64_find_global_pointer (CORE_ADDR faddr);
 
 static struct type *builtin_type_ia64_ext;
 
@@ -254,22 +275,8 @@ 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
-                          given register from the start of the frame. */
-    CORE_ADDR (*find_global_pointer) (CORE_ADDR);
-  };
-
 #define SIGCONTEXT_REGISTER_ADDRESS \
   (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
-#define FIND_GLOBAL_POINTER \
-  (gdbarch_tdep (current_gdbarch)->find_global_pointer)
 
 int
 ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
@@ -318,9 +325,7 @@ ia64_dwarf_reg_to_regnum (int reg)
 }
 
 static int
-floatformat_valid (fmt, from)
-     const struct floatformat *fmt;
-     const char *from;
+floatformat_valid (const struct floatformat *fmt, const void *from)
 {
   return 1;
 }
@@ -332,32 +337,6 @@ const struct floatformat floatformat_ia64_ext =
 };
 
 
-/* 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_size (current_gdbarch, 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''.  */
 
@@ -523,8 +502,8 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr)
      at the assembly language level.  */
   if (slotnum > 2)
     {
-      warning ("Can't fetch instructions for slot numbers greater than 2.\n"
-              "Using slot 0 instead");
+      warning (_("Can't fetch instructions for slot numbers greater than 2.\n"
+              "Using slot 0 instead"));
       slotnum = 0;
     }
 
@@ -572,8 +551,9 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr)
 #define IA64_BREAKPOINT 0x00003333300LL
 
 static int
-ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+ia64_memory_insert_breakpoint (struct bp_target_info *bp_tgt)
 {
+  CORE_ADDR addr = bp_tgt->placed_address;
   char bundle[BUNDLE_LEN];
   int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
   long long instr;
@@ -581,7 +561,7 @@ ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
   int template;
 
   if (slotnum > 2)
-    error("Can't insert breakpoint for slot numbers greater than 2.");
+    error (_("Can't insert breakpoint for slot numbers greater than 2."));
 
   addr &= ~0x0f;
 
@@ -596,7 +576,8 @@ ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
     }
 
   instr = slotN_contents (bundle, slotnum);
-  memcpy(contents_cache, &instr, sizeof(instr));
+  memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr));
+  bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr);
   replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum);
   if (val == 0)
     target_write_memory (addr, bundle, BUNDLE_LEN);
@@ -605,8 +586,9 @@ ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
 }
 
 static int
-ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+ia64_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
 {
+  CORE_ADDR addr = bp_tgt->placed_address;
   char bundle[BUNDLE_LEN];
   int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
   long long instr;
@@ -625,7 +607,7 @@ ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
       slotnum = 2;
     }
 
-  memcpy (&instr, contents_cache, sizeof instr);
+  memcpy (&instr, bp_tgt->shadow_contents, sizeof instr);
   replace_slotN_contents (bundle, instr, slotnum);
   if (val == 0)
     target_write_memory (addr, bundle, BUNDLE_LEN);
@@ -647,18 +629,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)
 {
@@ -669,7 +639,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;
@@ -707,28 +677,39 @@ rse_address_add(CORE_ADDR addr, int nslots)
 
 static void
 ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
-                           int regnum, void *buf)
+                           int regnum, gdb_byte *buf)
 {
   if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
     {
-      ULONGEST bsp;
-      ULONGEST cfm;
-      CORE_ADDR reg;
-      regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
-      regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-
-      /* The bsp points at the end of the register frame so we
-        subtract the size of frame from it to get start of register frame.  */
-      bsp = rse_address_add (bsp, -(cfm & 0x7f));
-      if ((cfm & 0x7f) > regnum - V32_REGNUM) 
+#ifdef HAVE_LIBUNWIND_IA64_H
+      /* First try and use the libunwind special reg accessor, otherwise fallback to
+        standard logic.  */
+      if (!libunwind_is_initialized ()
+         || libunwind_get_reg_special (gdbarch, regnum, buf) != 0)
+#endif
        {
-         ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
-         reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
-         store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
+         /* The fallback position is to assume that r32-r127 are found sequentially
+            in memory starting at $bof.  This isn't always true, but without libunwind,
+            this is the best we can do.  */
+         ULONGEST cfm;
+         ULONGEST bsp;
+         CORE_ADDR reg;
+         regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+         regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+         
+         /* The bsp points at the end of the register frame so we
+            subtract the size of frame from it to get start of register frame.  */
+         bsp = rse_address_add (bsp, -(cfm & 0x7f));
+         
+         if ((cfm & 0x7f) > regnum - V32_REGNUM) 
+           {
+             ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
+             reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
+             store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
+           }
+         else
+           store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
        }
-      else
-       store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
     }
   else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
     {
@@ -816,7 +797,7 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
 
 static void
 ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
-                           int regnum, const void *buf)
+                           int regnum, const gdb_byte *buf)
 {
   if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
     {
@@ -937,7 +918,7 @@ ia64_convert_register_p (int regno, struct type *type)
 
 static void
 ia64_register_to_value (struct frame_info *frame, int regnum,
-                         struct type *valtype, void *out)
+                         struct type *valtype, gdb_byte *out)
 {
   char in[MAX_REGISTER_SIZE];
   frame_register_read (frame, regnum, in);
@@ -946,7 +927,7 @@ ia64_register_to_value (struct frame_info *frame, int regnum,
 
 static void
 ia64_value_to_register (struct frame_info *frame, int regnum,
-                         struct type *valtype, const void *in)
+                         struct type *valtype, const gdb_byte *in)
 {
   char out[MAX_REGISTER_SIZE];
   convert_typed_floating (in, valtype, out, builtin_type_ia64_ext);
@@ -968,6 +949,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)
 {
@@ -1154,7 +1138,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)
@@ -1266,7 +1250,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 */
@@ -1581,22 +1565,24 @@ ia64_frame_this_id (struct frame_info *next_frame, void **this_cache,
   struct ia64_frame_cache *cache =
     ia64_frame_cache (next_frame, this_cache);
 
-  /* This marks the outermost frame.  */
+  /* If outermost frame, mark with null frame id.  */
   if (cache->base == 0)
-    return;
-
-  (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
+    (*this_id) = null_frame_id;
+  else
+    (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
   if (gdbarch_debug >= 1)
     fprintf_unfiltered (gdb_stdlog,
-                       "regular frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
-                       this_id->code_addr, this_id->stack_addr, cache->bsp, next_frame);
+                       "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
 ia64_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 *realnump, gdb_byte *valuep)
 {
   struct ia64_frame_cache *cache =
     ia64_frame_cache (next_frame, this_cache);
@@ -1606,7 +1592,7 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
   gdb_assert (regnum >= 0);
 
   if (!target_has_registers)
-    error ("No registers.");
+    error (_("No registers."));
 
   *optimizedp = 0;
   *addrp = 0;
@@ -1884,9 +1870,10 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
 
   if (gdbarch_debug >= 1)
     fprintf_unfiltered (gdb_stdlog,
-                       "regular prev register <%d> <%s> is %lx\n", regnum, 
+                       "regular prev register <%d> <%s> is 0x%s\n", regnum, 
                        (((unsigned) regnum <= IA64_NAT127_REGNUM)
-                        ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+                        ? ia64_register_names[regnum] : "r??"), 
+                       paddr_nz (extract_unsigned_integer (valuep, 8)));
 }
  
 static const struct frame_unwind ia64_frame_unwind =
@@ -1984,8 +1971,10 @@ ia64_sigtramp_frame_this_id (struct frame_info *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 %lx, stack %lx, special %lx, next_frame %p\n",
-                       this_id->code_addr, this_id->stack_addr, cache->bsp, next_frame);
+                       "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
@@ -1993,7 +1982,7 @@ ia64_sigtramp_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 *realnump, gdb_byte *valuep)
 {
   char dummy_valp[MAX_REGISTER_SIZE];
   char buf[MAX_REGISTER_SIZE];
@@ -2004,7 +1993,7 @@ ia64_sigtramp_frame_prev_register (struct frame_info *next_frame,
   gdb_assert (regnum >= 0);
 
   if (!target_has_registers)
-    error ("No registers.");
+    error (_("No registers."));
 
   *optimizedp = 0;
   *addrp = 0;
@@ -2061,9 +2050,15 @@ ia64_sigtramp_frame_prev_register (struct frame_info *next_frame,
 
   if (gdbarch_debug >= 1)
     fprintf_unfiltered (gdb_stdlog,
-                       "sigtramp prev register <%s> is %lx\n",
-                       (((unsigned) regnum <= IA64_NAT127_REGNUM)
-                        ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+                       "sigtramp prev register <%s> is 0x%s\n",
+                       (regnum < IA64_GR32_REGNUM
+                        || (regnum > IA64_GR127_REGNUM
+                            && regnum < LAST_PSEUDO_REGNUM))
+                        ? ia64_register_names[regnum]
+                        : (regnum < LAST_PSEUDO_REGNUM
+                           ? ia64_register_names[regnum-IA64_GR32_REGNUM+V32_REGNUM]
+                           : "OUT_OF_RANGE"),
+                       paddr_nz (extract_unsigned_integer (valuep, 8)));
 }
 
 static const struct frame_unwind ia64_sigtramp_frame_unwind =
@@ -2080,7 +2075,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;
@@ -2104,9 +2099,894 @@ 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 top-level rse registers.  */
+static int
+ia64_access_rse_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;
+  long new_sof, old_sof;
+  
+  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_rse_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.  */
+         ip = read_register (IA64_IP_REGNUM); 
+         psr = read_register (IA64_PSR_REGNUM);
+         *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.  */
+         bsp = read_register (IA64_BSP_REGNUM);
+         cfm = read_register (IA64_CFM_REGNUM);
+         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.  */
+         *val = read_register (IA64_BSP_REGNUM);
+         break;
+
+       default:
+         /* For all other registers, just read the value directly.  */
+         *val = read_register (regnum);
+         break;
+       }
+    }
+      
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog, 
+                       "  access_rse_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 accessing memory.  */
+static int
+ia64_access_mem (unw_addr_space_t as,
+                unw_word_t addr, unw_word_t *val,
+                int write, void *arg)
+{
+  if (addr - KERNEL_START < ktab_size)
+    {
+      unw_word_t *laddr = (unw_word_t*) ((char *) ktab
+                          + (addr - KERNEL_START));
+               
+      if (write)
+        *laddr = *val; 
+      else 
+        *val = *laddr;
+      return 0;
+    }
+
+  /* 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 LONGEST
+getunwind_table (gdb_byte **buf_p)
+{
+  LONGEST x;
+
+  /* FIXME drow/2005-09-10: This code used to call
+     ia64_linux_xfer_unwind_table directly to fetch the unwind table
+     for the currently running ia64-linux kernel.  That data should
+     come from the core file and be accessed via the auxv vector; if
+     we want to preserve fall back to the running kernel's table, then
+     we should find a way to override the corefile layer's
+     xfer_partial method.  */
+
+  x = target_read_alloc (&current_target, TARGET_OBJECT_UNWIND_TABLE,
+                        NULL, buf_p);
+
+  return x;
+}
+
+/* Get the kernel unwind table.  */                             
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+  static struct ia64_table_entry *etab;
+
+  if (!ktab) 
+    {
+      gdb_byte *ktab_buf;
+      LONGEST size;
+
+      size = getunwind_table (&ktab_buf);
+      if (size <= 0)
+       return -UNW_ENOINFO;
+
+      ktab = (struct ia64_table_entry *) ktab_buf;
+      ktab_size = size;
+
+      for (etab = ktab; etab->start_offset; ++etab)
+        etab->info_offset += KERNEL_START;
+    }
+  
+  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)
+    return -UNW_ENOINFO;
+
+  /* Verify that the segment that contains the IP also contains
+     the static unwind table.  If not, we may be in the Linux kernel's
+     DSO gate page in which case the unwind table is another segment. 
+     Otherwise, we are dealing with runtime-generated code, for which we 
+     have no info here.  */
+  segbase = p_text->p_vaddr + load_base;
+
+  if ((p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+    {
+      int ok = 0;
+      for (i = 0; i < ehdr->e_phnum; ++i)
+        {
+          if (phdr[i].p_type == PT_LOAD
+             && (p_unwind->p_vaddr - phdr[i].p_vaddr) < phdr[i].p_memsz)
+           {
+              ok = 1;
+             /* Get the segbase from the section containing the
+                libunwind table.  */
+             segbase = phdr[i].p_vaddr + load_base;
+           }
+       }
+      if (!ok)
+        return -UNW_ENOINFO;
+    }
+
+  dip->start_ip = p_text->p_vaddr + load_base;
+  dip->end_ip = dip->start_ip + p_text->p_memsz;
+  dip->gp = ia64_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;
+  CORE_ADDR prev_ip, addr;
+  int realnum, optimized;
+  enum lval_type lval;
+
+
+  libunwind_frame_this_id (next_frame, this_cache, &id);
+  if (frame_id_eq (id, null_frame_id))
+    {
+      (*this_id) = null_frame_id;
+      return;
+    }
+
+  /* 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);
+
+  /* If the previous frame pc value is 0, then we are at the end of the stack
+     and don't want to unwind past this frame.  We return a null frame_id to
+     indicate this.  */
+  libunwind_frame_prev_register (next_frame, this_cache, IA64_IP_REGNUM, 
+                                &optimized, &lval, &addr, &realnum, buf);
+  prev_ip = extract_unsigned_integer (buf, 8);
+
+  if (prev_ip != 0)
+    (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+  else
+    (*this_id) = null_frame_id;
+
+  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, gdb_byte *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",
+                       (regnum < IA64_GR32_REGNUM
+                        || (regnum > IA64_GR127_REGNUM
+                            && regnum < LAST_PSEUDO_REGNUM))
+                        ? ia64_register_names[regnum]
+                        : (regnum < LAST_PSEUDO_REGNUM
+                           ? ia64_register_names[regnum-IA64_GR32_REGNUM+V32_REGNUM]
+                           : "OUT_OF_RANGE"),
+                       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;
+}
+
+static void
+ia64_libunwind_sigtramp_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;
+  CORE_ADDR prev_ip;
+
+  libunwind_frame_this_id (next_frame, this_cache, &id);
+  if (frame_id_eq (id, null_frame_id))
+    {
+      (*this_id) = null_frame_id;
+      return;
+    }
+
+  /* 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);
+
+  /* For a sigtramp frame, we don't make the check for previous ip being 0.  */
+  (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+  if (gdbarch_debug >= 1)
+    fprintf_unfiltered (gdb_stdlog,
+                       "libunwind sigtramp 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_sigtramp_frame_prev_register (struct frame_info *next_frame,
+                                            void **this_cache,
+                                            int regnum, int *optimizedp,
+                                            enum lval_type *lvalp, CORE_ADDR *addrp,
+                                            int *realnump, gdb_byte *valuep)
+
+{
+  gdb_byte buf[8];
+  CORE_ADDR prev_ip, addr;
+  int realnum, optimized;
+  enum lval_type lval;
+
+
+  /* If the previous frame pc value is 0, then we want to use the SIGCONTEXT
+     method of getting previous registers.  */
+  libunwind_frame_prev_register (next_frame, this_cache, IA64_IP_REGNUM, 
+                                &optimized, &lval, &addr, &realnum, buf);
+  prev_ip = extract_unsigned_integer (buf, 8);
+
+  if (prev_ip == 0)
+    {
+      void *tmp_cache = NULL;
+      ia64_sigtramp_frame_prev_register (next_frame, &tmp_cache, regnum, optimizedp, lvalp,
+                                        addrp, realnump, valuep);
+    }
+  else
+    ia64_libunwind_frame_prev_register (next_frame, this_cache, regnum, optimizedp, lvalp,
+                                       addrp, realnump, valuep);
+}
+
+static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
+{
+  SIGTRAMP_FRAME,
+  ia64_libunwind_sigtramp_frame_this_id,
+  ia64_libunwind_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+  if (libunwind_is_initialized ())
+    {
+      if (libunwind_sigtramp_frame_sniffer (next_frame))
+        return &ia64_libunwind_sigtramp_frame_unwind;
+      return NULL;
+    }
+  else
+    return ia64_sigtramp_frame_sniffer (next_frame);
+}
+
+/* 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 special libunwind callback acccessor functions specific for accessing
+   the rse registers.  At the top of the stack, we want libunwind to figure out
+   how to read r32 - r127.  Though usually they are found sequentially in memory
+   starting from $bof, this is not always true.  */
+static unw_accessors_t ia64_unw_rse_accessors =
+{
+  ia64_find_proc_info_x,
+  ia64_put_unwind_info,
+  ia64_get_dyn_info_list,
+  ia64_access_mem,
+  ia64_access_rse_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,
+  &ia64_unw_rse_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)
 {
@@ -2127,7 +3007,8 @@ ia64_use_struct_convention (int gcc_p, struct type *type)
 }
 
 void
-ia64_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf)
+ia64_extract_return_value (struct type *type, struct regcache *regcache,
+                          gdb_byte *valbuf)
 {
   struct type *float_elt_type;
 
@@ -2177,7 +3058,7 @@ ia64_extract_return_value (struct type *type, struct regcache *regcache, void *v
 CORE_ADDR
 ia64_extract_struct_value_address (struct regcache *regcache)
 {
-  error ("ia64_extract_struct_value_address called and cannot get struct value address");
+  error (_("ia64_extract_struct_value_address called and cannot get struct value address"));
   return 0;
 }
 
@@ -2276,7 +3157,7 @@ slot_alignment_is_next_even (struct type *t)
    d_un.d_ptr value is the global pointer.  */
 
 static CORE_ADDR
-generic_elf_find_global_pointer (CORE_ADDR faddr)
+ia64_find_global_pointer (CORE_ADDR faddr)
 {
   struct obj_section *faddr_sect;
      
@@ -2397,7 +3278,7 @@ find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
       fdesc = *fdaptr;
       *fdaptr += 16;
 
-      global_pointer = FIND_GLOBAL_POINTER (faddr);
+      global_pointer = ia64_find_global_pointer (faddr);
 
       if (global_pointer == 0)
        global_pointer = read_register (IA64_GR1_REGNUM);
@@ -2426,6 +3307,17 @@ ia64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
   if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
     return read_memory_unsigned_integer (addr, 8);
 
+  /* There are also descriptors embedded in vtables.  */
+  if (s)
+    {
+      struct minimal_symbol *minsym;
+
+      minsym = lookup_minimal_symbol_by_pc (addr);
+
+      if (minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym)))
+       return read_memory_unsigned_integer (addr, 8);
+    }
+
   return addr;
 }
 
@@ -2436,7 +3328,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)
@@ -2448,6 +3340,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;
@@ -2455,7 +3348,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   for (argno = 0; argno < nargs; argno++)
     {
       arg = args[argno];
-      type = check_typedef (VALUE_TYPE (arg));
+      type = check_typedef (value_type (arg));
       len = TYPE_LENGTH (type);
 
       if ((nslots & 1) && slot_alignment_is_next_even (type))
@@ -2510,7 +3403,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
       struct type *float_elt_type;
 
       arg = args[argno];
-      type = check_typedef (VALUE_TYPE (arg));
+      type = check_typedef (value_type (arg));
       len = TYPE_LENGTH (type);
 
       /* Special handling for function parameters.  */
@@ -2521,7 +3414,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
          char val_buf[8];
 
          store_unsigned_integer (val_buf, 8,
-                                 find_func_descr (extract_unsigned_integer (VALUE_CONTENTS (arg), 8),
+                                 find_func_descr (extract_unsigned_integer (value_contents (arg), 8),
                                                   &funcdescaddr));
          if (slotnum < rseslots)
            write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
@@ -2543,7 +3436,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
          char val_buf[8];
 
          memset (val_buf, 0, 8);
-         memcpy (val_buf, VALUE_CONTENTS (arg) + argoffset, (len > 8) ? 8 : len);
+         memcpy (val_buf, value_contents (arg) + argoffset, (len > 8) ? 8 : len);
 
          if (slotnum < rseslots)
            write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
@@ -2564,7 +3457,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
          while (len > 0 && floatreg < IA64_FR16_REGNUM)
            {
              char to[MAX_REGISTER_SIZE];
-             convert_typed_floating (VALUE_CONTENTS (arg) + argoffset, float_elt_type,
+             convert_typed_floating (value_contents (arg) + argoffset, float_elt_type,
                                      to, builtin_type_ia64_ext);
              regcache_cooked_write (regcache, floatreg, (void *)to);
              floatreg++;
@@ -2580,7 +3473,7 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
       regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM, (ULONGEST)struct_addr);
     }
 
-  global_pointer = FIND_GLOBAL_POINTER (func_addr);
+  global_pointer = ia64_find_global_pointer (func_addr);
 
   if (global_pointer != 0)
     write_register (IA64_GR1_REGNUM, global_pointer);
@@ -2606,8 +3499,9 @@ ia64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 
   if (gdbarch_debug >= 1)
     fprintf_unfiltered (gdb_stdlog,
-                       "dummy frame id: code %lx, stack %lx, special %lx\n",
-                       frame_pc_unwind (next_frame), sp, bsp);
+                       "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);
 }
@@ -2628,7 +3522,8 @@ ia64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 }
 
 static void
-ia64_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf)
+ia64_store_return_value (struct type *type, struct regcache *regcache, 
+                       const gdb_byte *valbuf)
 {
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
@@ -2651,53 +3546,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)
 {
@@ -2710,66 +3558,16 @@ 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)
-    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;
-  else
-    tdep->sigcontext_register_address = 0;
-
-  /* We know that GNU/Linux won't have to resort to the
-     native_find_global_pointer hackery.  But that's the only one we
-     know about so far, so if native_find_global_pointer is set to
-     something non-zero, then use it.  Otherwise fall back to using
-     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)
-    tdep->find_global_pointer = generic_elf_find_global_pointer;
-  else if (native_find_global_pointer != 0)
-    tdep->find_global_pointer = native_find_global_pointer;
-  else
-    tdep->find_global_pointer = generic_elf_find_global_pointer;
+
+  tdep->sigcontext_register_address = 0;
 
   /* Define the ia64 floating-point format to gdb.  */
   builtin_type_ia64_ext =
@@ -2777,6 +3575,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);
@@ -2807,11 +3615,11 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_skip_prologue (gdbarch, ia64_skip_prologue);
 
-  set_gdbarch_use_struct_convention (gdbarch, ia64_use_struct_convention);
+  set_gdbarch_deprecated_use_struct_convention (gdbarch, ia64_use_struct_convention);
   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);
@@ -2825,23 +3633,32 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_unwind_dummy_id (gdbarch, ia64_unwind_dummy_id);
 
   set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
+#ifdef HAVE_LIBUNWIND_IA64_H
+  frame_unwind_append_sniffer (gdbarch, ia64_libunwind_sigtramp_frame_sniffer);
+  frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+  libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#else
   frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#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);
 
   set_gdbarch_print_insn (gdbarch, ia64_print_insn);
   set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);
 
+  /* The virtual table contains 16-byte descriptors, not pointers to
+     descriptors.  */
+  set_gdbarch_vtable_function_descriptors (gdbarch, 1);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
   return gdbarch;
 }
 
@@ -2850,5 +3667,5 @@ extern initialize_file_ftype _initialize_ia64_tdep; /* -Wmissing-prototypes */
 void
 _initialize_ia64_tdep (void)
 {
-  register_gdbarch_init (bfd_arch_ia64, ia64_gdbarch_init);
+  gdbarch_register (bfd_arch_ia64, ia64_gdbarch_init, NULL);
 }
This page took 0.063571 seconds and 4 git commands to generate.