+ long delta = ia64_rse_slot_num(addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + ((num_regs + delta/0x3f) << 3);
+}
+
+/* Gdb ia64-libunwind-tdep 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 ia64-libunwind-tdep 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 ia64-libunwind-tdep 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, cfm, psr, ip;
+ struct frame_info *this_frame = (struct frame_info *) arg;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ 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 = get_frame_register_unsigned (this_frame, IA64_IP_REGNUM);
+ psr = get_frame_register_unsigned (this_frame, 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 = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
+ cfm = get_frame_register_unsigned (this_frame, IA64_CFM_REGNUM);
+ sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm);
+ *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 = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM);
+ break;
+
+ default:
+ /* For all other registers, just unwind the value directly. */
+ *val = get_frame_register_unsigned (this_frame, regnum);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: from cache: %4s=%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddress (gdbarch, *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);
+ struct frame_info *this_frame = (struct frame_info *) arg;
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ get_frame_register (this_frame, regnum, (gdb_byte *) 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, cfm, psr, ip;
+ struct regcache *regcache = (struct regcache *) arg;
+ struct gdbarch *gdbarch = regcache->arch ();
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ 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. */
+ regcache_cooked_read_unsigned (regcache, IA64_IP_REGNUM, &ip);
+ regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
+ *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. */
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ 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. */
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, val);
+ break;
+
+ default:
+ /* For all other registers, just unwind the value directly. */
+ regcache_cooked_read_unsigned (regcache, regnum, val);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_rse_reg: from cache: %4s=%s\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"),
+ paddress (gdbarch, *val));
+
+ return 0;
+}
+
+/* Libunwind callback accessor function for top-level fp registers. */
+static int
+ia64_access_rse_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);
+ struct regcache *regcache = (struct regcache *) arg;
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ regcache->cooked_read (regnum, (gdb_byte *) 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, (gdb_byte *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (gdb_byte *) val, sizeof (unw_word_t));
+}
+
+/* Call low-level function to access the kernel unwind table. */
+static gdb::optional<gdb::byte_vector>
+getunwind_table ()
+{
+ /* 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. */
+
+ return target_read_alloc (current_top_target (), TARGET_OBJECT_UNWIND_TABLE,
+ NULL);
+}
+
+/* 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)
+ {
+ ktab_buf = getunwind_table ();
+ if (!ktab_buf)
+ return -UNW_ENOINFO;
+
+ ktab = (struct ia64_table_entry *) ktab_buf->data ();
+ ktab_size = ktab_buf->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=%s, length=%s, gp=%s\n",
+ (char *) di->u.ti.name_ptr,
+ hex_string (di->u.ti.segbase),
+ pulongest (di->u.ti.table_len),
+ hex_string (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 = objfile->text_section_offset ();
+
+ 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 (objfile->arch (), 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: %s -> "
+ "(name=`%s',segbase=%s,start=%s,end=%s,gp=%s,"
+ "length=%s,data=%s)\n",
+ hex_string (ip), (char *)di.u.ti.name_ptr,
+ hex_string (di.u.ti.segbase),
+ hex_string (di.start_ip), hex_string (di.end_ip),
+ hex_string (di.gp),
+ pulongest (di.u.ti.table_len),
+ hex_string ((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: %s -> "
+ "(name=`%s',segbase=%s,start=%s,end=%s,gp=%s,"
+ "length=%s,data=%s)\n",
+ hex_string (ip), (char *)di.u.rti.name_ptr,
+ hex_string (di.u.rti.segbase),
+ hex_string (di.start_ip), hex_string (di.end_ip),
+ hex_string (di.gp),
+ pulongest (di.u.rti.table_len),
+ hex_string (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;
+ unw_word_t ip, addr;
+ unw_dyn_info_t di;
+ int ret;
+
+ if (!libunwind_is_initialized ())
+ return -UNW_ENOINFO;
+
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ void *buf = NULL;
+
+ text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+ ip = obj_section_addr (text_sec);
+ 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 %s (gp=%s)\n",
+ bfd_get_filename (objfile->obfd),
+ hex_string (addr), hex_string (di.gp));
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+
+/* Frame interface functions for libunwind. */
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct frame_id id = outer_frame_id;
+ gdb_byte buf[8];
+ CORE_ADDR bsp;
+
+ libunwind_frame_this_id (this_frame, this_cache, &id);
+ if (frame_id_eq (id, outer_frame_id))
+ {
+ (*this_id) = outer_frame_id;
+ return;
+ }
+
+ /* We must add the bsp as the special address for frame comparison
+ purposes. */
+ get_frame_register (this_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8, byte_order);
+
+ (*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 %s, stack %s, "
+ "special %s, this_frame %s\n",
+ paddress (gdbarch, id.code_addr),
+ paddress (gdbarch, id.stack_addr),
+ paddress (gdbarch, bsp),
+ host_address_to_string (this_frame));
+}
+
+static struct value *
+ia64_libunwind_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ int reg = regnum;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct value *val;
+
+ 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. */
+ val = libunwind_frame_prev_register (this_frame, this_cache, reg);
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST prN_val;
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ int rrb_pr = 0;
+ ULONGEST cfm;
+
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ cfm = get_frame_register_unsigned (this_frame, IA64_CFM_REGNUM);
+ 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 (value_contents_all (val),
+ regnum - VP0_REGNUM, 1);
+ return frame_unwind_got_constant (this_frame, regnum, prN_val);
+ }
+
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST unatN_val;
+
+ unatN_val = extract_bit_field (value_contents_all (val),
+ regnum - IA64_NAT0_REGNUM, 1);
+ return frame_unwind_got_constant (this_frame, regnum, unatN_val);
+ }
+
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ struct value *cfm_val;
+ CORE_ADDR prev_bsp, prev_cfm;
+
+ /* 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 (value_contents_all (val),
+ 8, byte_order);
+ cfm_val = libunwind_frame_prev_register (this_frame, this_cache,
+ IA64_CFM_REGNUM);
+ prev_cfm = extract_unsigned_integer (value_contents_all (cfm_val),
+ 8, byte_order);
+ prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+ return frame_unwind_got_constant (this_frame, regnum, prev_bsp);
+ }
+ else
+ return val;
+}
+
+static int
+ia64_libunwind_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ if (libunwind_is_initialized ()
+ && libunwind_frame_sniffer (self, this_frame, this_cache))
+ return 1;
+
+ return 0;
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register,
+ NULL,
+ ia64_libunwind_frame_sniffer,
+ libunwind_frame_dealloc_cache
+};
+
+static void
+ia64_libunwind_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ gdb_byte buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id = outer_frame_id;
+
+ libunwind_frame_this_id (this_frame, this_cache, &id);
+ if (frame_id_eq (id, outer_frame_id))
+ {
+ (*this_id) = outer_frame_id;
+ return;
+ }
+
+ /* We must add the bsp as the special address for frame comparison
+ purposes. */
+ get_frame_register (this_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8, byte_order);
+
+ /* 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 %s, "
+ "stack %s, special %s, this_frame %s\n",
+ paddress (gdbarch, id.code_addr),
+ paddress (gdbarch, id.stack_addr),
+ paddress (gdbarch, bsp),
+ host_address_to_string (this_frame));
+}
+
+static struct value *
+ia64_libunwind_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct value *prev_ip_val;
+ CORE_ADDR prev_ip;
+
+ /* If the previous frame pc value is 0, then we want to use the SIGCONTEXT
+ method of getting previous registers. */
+ prev_ip_val = libunwind_frame_prev_register (this_frame, this_cache,
+ IA64_IP_REGNUM);
+ prev_ip = extract_unsigned_integer (value_contents_all (prev_ip_val),
+ 8, byte_order);
+
+ if (prev_ip == 0)
+ {
+ void *tmp_cache = NULL;
+ return ia64_sigtramp_frame_prev_register (this_frame, &tmp_cache,
+ regnum);
+ }
+ else
+ return ia64_libunwind_frame_prev_register (this_frame, this_cache, regnum);
+}
+
+static int
+ia64_libunwind_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ if (libunwind_is_initialized ())
+ {
+ if (libunwind_sigtramp_frame_sniffer (self, this_frame, this_cache))
+ return 1;
+ return 0;
+ }
+ else
+ return ia64_sigtramp_frame_sniffer (self, this_frame, this_cache);
+}
+
+static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ ia64_libunwind_sigtramp_frame_this_id,
+ ia64_libunwind_sigtramp_frame_prev_register,
+ NULL,
+ ia64_libunwind_sigtramp_frame_sniffer
+};
+
+/* Set of libunwind callback acccessor functions. */
+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. */
+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_rse_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+/* Set of ia64-libunwind-tdep gdb callbacks and data for generic
+ ia64-libunwind-tdep code to use. */
+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 */
+
+static int
+ia64_use_struct_convention (struct type *type)
+{
+ struct type *float_elt_type;
+
+ /* Don't use the struct convention for anything but structure,
+ union, or array types. */
+ if (!(type->code () == TYPE_CODE_STRUCT
+ || type->code () == TYPE_CODE_UNION
+ || type->code () == TYPE_CODE_ARRAY))
+ return 0;
+
+ /* HFAs are structures (or arrays) consisting entirely of floating
+ point values of the same length. Up to 8 of these are returned
+ in registers. Don't use the struct convention when this is the
+ case. */
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL
+ && TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type) <= 8)
+ return 0;
+
+ /* Other structs of length 32 or less are returned in r8-r11.
+ Don't use the struct convention for those either. */
+ return TYPE_LENGTH (type) > 32;
+}
+
+/* Return non-zero if TYPE is a structure or union type. */
+
+static int
+ia64_struct_type_p (const struct type *type)
+{
+ return (type->code () == TYPE_CODE_STRUCT
+ || type->code () == TYPE_CODE_UNION);
+}
+
+static void
+ia64_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ struct type *float_elt_type;
+
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ gdb_byte from[IA64_FP_REGISTER_SIZE];
+ int offset = 0;
+ int regnum = IA64_FR8_REGNUM;
+ int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+ while (n-- > 0)
+ {
+ regcache->cooked_read (regnum, from);
+ target_float_convert (from, ia64_ext_type (gdbarch),
+ valbuf + offset, float_elt_type);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
+ else if (!ia64_struct_type_p (type) && TYPE_LENGTH (type) < 8)
+ {
+ /* This is an integral value, and its size is less than 8 bytes.
+ These values are LSB-aligned, so extract the relevant bytes,
+ and copy them into VALBUF. */
+ /* brobecker/2005-12-30: Actually, all integral values are LSB aligned,
+ so I suppose we should also add handling here for integral values
+ whose size is greater than 8. But I wasn't able to create such
+ a type, neither in C nor in Ada, so not worrying about these yet. */
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ ULONGEST val;
+
+ regcache_cooked_read_unsigned (regcache, IA64_GR8_REGNUM, &val);
+ store_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order, val);
+ }
+ else
+ {
+ ULONGEST val;
+ int offset = 0;
+ int regnum = IA64_GR8_REGNUM;
+ int reglen = TYPE_LENGTH (register_type (gdbarch, IA64_GR8_REGNUM));
+ int n = TYPE_LENGTH (type) / reglen;
+ int m = TYPE_LENGTH (type) % reglen;
+
+ while (n-- > 0)
+ {
+ ULONGEST regval;
+ regcache_cooked_read_unsigned (regcache, regnum, ®val);
+ memcpy ((char *)valbuf + offset, ®val, reglen);
+ offset += reglen;
+ regnum++;
+ }
+
+ if (m)
+ {
+ regcache_cooked_read_unsigned (regcache, regnum, &val);
+ memcpy ((char *)valbuf + offset, &val, m);
+ }
+ }
+}
+
+static void
+ia64_store_return_value (struct type *type, struct regcache *regcache,
+ const gdb_byte *valbuf)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ struct type *float_elt_type;
+
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ gdb_byte to[IA64_FP_REGISTER_SIZE];
+ int offset = 0;
+ int regnum = IA64_FR8_REGNUM;
+ int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+ while (n-- > 0)
+ {
+ target_float_convert (valbuf + offset, float_elt_type,
+ to, ia64_ext_type (gdbarch));
+ regcache->cooked_write (regnum, to);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
+ else
+ {
+ int offset = 0;
+ int regnum = IA64_GR8_REGNUM;
+ int reglen = TYPE_LENGTH (register_type (gdbarch, IA64_GR8_REGNUM));
+ int n = TYPE_LENGTH (type) / reglen;
+ int m = TYPE_LENGTH (type) % reglen;
+
+ while (n-- > 0)
+ {
+ ULONGEST val;
+ memcpy (&val, (char *)valbuf + offset, reglen);
+ regcache_cooked_write_unsigned (regcache, regnum, val);
+ offset += reglen;
+ regnum++;
+ }
+
+ if (m)
+ {
+ ULONGEST val;
+ memcpy (&val, (char *)valbuf + offset, m);
+ regcache_cooked_write_unsigned (regcache, regnum, val);
+ }
+ }
+}
+
+static enum return_value_convention
+ia64_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *valtype, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ int struct_return = ia64_use_struct_convention (valtype);
+
+ if (writebuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ ia64_store_return_value (valtype, regcache, writebuf);
+ }
+
+ if (readbuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ ia64_extract_return_value (valtype, regcache, readbuf);
+ }
+
+ if (struct_return)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static int
+is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
+{
+ switch (t->code ())
+ {
+ case TYPE_CODE_FLT:
+ if (*etp)
+ return TYPE_LENGTH (*etp) == TYPE_LENGTH (t);
+ else
+ {
+ *etp = t;
+ return 1;
+ }
+ break;
+ case TYPE_CODE_ARRAY:
+ return
+ is_float_or_hfa_type_recurse (check_typedef (TYPE_TARGET_TYPE (t)),
+ etp);
+ break;
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < t->num_fields (); i++)
+ if (!is_float_or_hfa_type_recurse
+ (check_typedef (t->field (i).type ()), etp))
+ return 0;
+ return 1;
+ }
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+/* Determine if the given type is one of the floating point types or
+ and HFA (which is a struct, array, or combination thereof whose
+ bottom-most elements are all of the same floating point type). */
+
+static struct type *
+is_float_or_hfa_type (struct type *t)
+{
+ struct type *et = 0;
+
+ return is_float_or_hfa_type_recurse (t, &et) ? et : 0;
+}
+
+
+/* Return 1 if the alignment of T is such that the next even slot
+ should be used. Return 0, if the next available slot should
+ be used. (See section 8.5.1 of the IA-64 Software Conventions
+ and Runtime manual). */
+
+static int
+slot_alignment_is_next_even (struct type *t)
+{
+ switch (t->code ())
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ if (TYPE_LENGTH (t) > 8)
+ return 1;
+ else
+ return 0;
+ case TYPE_CODE_ARRAY:
+ return
+ slot_alignment_is_next_even (check_typedef (TYPE_TARGET_TYPE (t)));
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < t->num_fields (); i++)
+ if (slot_alignment_is_next_even
+ (check_typedef (t->field (i).type ())))
+ return 1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/* Attempt to find (and return) the global pointer for the given
+ function.
+
+ This is a rather nasty bit of code searchs for the .dynamic section
+ in the objfile corresponding to the pc of the function we're trying
+ to call. Once it finds the addresses at which the .dynamic section
+ lives in the child process, it scans the Elf64_Dyn entries for a
+ DT_PLTGOT tag. If it finds one of these, the corresponding
+ d_un.d_ptr value is the global pointer. */
+
+static CORE_ADDR
+ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch,
+ CORE_ADDR faddr)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);