#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
#include "dis-asm.h"
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
+
/* Hook for determining the global pointer when calling functions in
the inferior under AIX. The initialization code in ia64-aix-nat.c
sets this hook to the address of a function which will find the
/* 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);
+extern unsigned long ia64_linux_getunwind_table (void *, size_t);
static gdbarch_init_ftype ia64_gdbarch_init;
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);
};
-/* 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''. */
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)
{
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=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *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=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ return 0;
+}
+
+/* Libunwind callback accessor function for floating-point registers. */
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+
+ if (write)
+ regcache_cooked_write (current_regcache, regnum, (char *) val);
+ else
+ regcache_cooked_read (current_regcache, regnum, (char *) val);
+ return 0;
+}
+
+/* Libunwind callback accessor function for accessing memory. */
+static int
+ia64_access_mem (unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ /* XXX do we need to normalize byte-order here? */
+ if (write)
+ return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+/* Call low-level function to access the kernel unwind table. */
+static int
+getunwind_table (void *buf, size_t len)
+{
+ LONGEST x;
+ x = target_read_partial (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
+ buf, 0, len);
+
+ return (int)x;
+}
+
+/* Get the kernel unwind table. */
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+ size_t size;
+ struct ia64_table_entry
+ {
+ uint64_t start_offset;
+ uint64_t end_offset;
+ uint64_t info_offset;
+ };
+ static struct ia64_table_entry *ktab = NULL, *etab;
+
+ if (!ktab)
+ {
+ size = getunwind_table (NULL, 0);
+ if ((int)size < 0)
+ return -UNW_ENOINFO;
+ ktab = xmalloc (size);
+ getunwind_table (ktab, size);
+
+ /* Determine length of kernel's unwind table and relocate
+ it's entries. */
+ for (etab = ktab; etab->start_offset; ++etab)
+ etab->info_offset += (uint64_t) ktab;
+ }
+
+ if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+ return -UNW_ENOINFO;
+
+ di->format = UNW_INFO_FORMAT_TABLE;
+ di->gp = 0;
+ di->start_ip = ktab[0].start_offset;
+ di->end_ip = etab[-1].end_offset;
+ di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+ di->u.ti.segbase = 0;
+ di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+ di->u.ti.table_data = (unw_word_t *) ktab;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+ "segbase=%lx, length=%lu, gp=%lx\n",
+ (char *) di->u.ti.name_ptr, di->u.ti.segbase,
+ di->u.ti.table_len, di->gp);
+ return 0;
+}
+
+/* Find the unwind table entry for a specified address. */
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+ unw_dyn_info_t *dip, void **buf)
+{
+ Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+ Elf_Internal_Ehdr *ehdr;
+ unw_word_t segbase = 0;
+ CORE_ADDR load_base;
+ bfd *bfd;
+ int i;
+
+ bfd = objfile->obfd;
+
+ ehdr = elf_tdata (bfd)->elf_header;
+ phdr = elf_tdata (bfd)->phdr;
+
+ load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ switch (phdr[i].p_type)
+ {
+ case PT_LOAD:
+ if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+ < phdr[i].p_memsz)
+ p_text = phdr + i;
+ break;
+
+ case PT_IA_64_UNWIND:
+ p_unwind = phdr + i;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!p_text || !p_unwind
+ /* Verify that the segment that contains the IP also contains
+ the static unwind table. If not, we are dealing with
+ runtime-generated code, for which we have no info here. */
+ || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+ return -UNW_ENOINFO;
+
+ segbase = p_text->p_vaddr + load_base;
+
+ dip->start_ip = segbase;
+ dip->end_ip = dip->start_ip + p_text->p_memsz;
+ dip->gp = FIND_GLOBAL_POINTER (ip);
+ dip->format = UNW_INFO_FORMAT_REMOTE_TABLE;
+ dip->u.rti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.rti.segbase = segbase;
+ dip->u.rti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+ dip->u.rti.table_data = p_unwind->p_vaddr + load_base;
+
+ return 0;
+}
+
+/* Libunwind callback accessor function to acquire procedure unwind-info. */
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct obj_section *sec = find_pc_section (ip);
+ unw_dyn_info_t di;
+ int ret;
+ void *buf = NULL;
+
+ if (!sec)
+ {
+ /* XXX This only works if the host and the target architecture are
+ both ia64 and if the have (more or less) the same kernel
+ version. */
+ if (get_kernel_table (ip, &di) < 0)
+ return -UNW_ENOINFO;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: %lx -> "
+ "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+ "length=%lu,data=%p)\n",
+ ip, (char *)di.u.ti.name_ptr,
+ di.u.ti.segbase, di.start_ip, di.end_ip,
+ di.gp, di.u.ti.table_len, 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: %lx -> "
+ "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+ "length=%lu,data=%lx)\n",
+ ip, (char *)di.u.rti.name_ptr,
+ di.u.rti.segbase, di.start_ip, di.end_ip,
+ di.gp, di.u.rti.table_len, 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 %lx (gp=%lx)\n",
+ bfd_get_filename (objfile->obfd),
+ addr, di.gp);
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+
+/* Frame interface functions for libunwind. */
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ char buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id;
+
+ libunwind_frame_this_id (next_frame, this_cache, &id);
+
+ /* We must add the bsp as the special address for frame comparison purposes. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
+ id.code_addr, id.stack_addr, bsp, next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ int reg = regnum;
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ reg = IA64_PR_REGNUM;
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ reg = IA64_UNAT_REGNUM;
+
+ /* Let libunwind do most of the work. */
+ libunwind_frame_prev_register (next_frame, this_cache, reg,
+ optimizedp, lvalp, addrp, realnump, valuep);
+
+ 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 %lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+ return &ia64_libunwind_frame_unwind;
+
+ return NULL;
+}
+
+/* Set of libunwind callback acccessor functions. */
+static unw_accessors_t ia64_unw_accessors =
+{
+ ia64_find_proc_info_x,
+ ia64_put_unwind_info,
+ ia64_get_dyn_info_list,
+ ia64_access_mem,
+ ia64_access_reg,
+ ia64_access_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use. */
+static struct libunwind_descr ia64_libunwind_descr =
+{
+ ia64_gdb2uw_regnum,
+ ia64_uw2gdb_regnum,
+ ia64_is_fpreg,
+ &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
+/* Should we use DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS instead of
+ EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc and TYPE
+ is the type (which is known to be struct, union or array). */
int
ia64_use_struct_convention (int gcc_p, struct type *type)
{
*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)
{
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);
set_gdbarch_extract_return_value (gdbarch, ia64_extract_return_value);
set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
- set_gdbarch_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
+ set_gdbarch_deprecated_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+ frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+ libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
frame_base_set_default (gdbarch, &ia64_frame_base);
/* Settings that should be unnecessary. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
- set_gdbarch_function_start_offset (gdbarch, 0);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_remote_translate_xfer_address (