This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: RFA: ia64 portion of libunwind patch
I have addressed your comments below. The bfd stuff (map_segment, map_info) has
been replaced by a simple call to bfd_bread(). I have moved the getunwind
syscall stuff into ia64-linux-tdep.c and I access it via the gdbarch_tdep structure.
The new ChangeLog is:
2003-10-28 Jeff Johnston <jjohnstn@redhat.com>
David Mosberger <davidm@hpl.hp.com>
* ia64-tdep.c: Include <fcntl.h>, elf.h, and <sys/mman.h>.
[HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
(gdbarch_tdep): Add getunwind_table function pointer to struct.
(ia64_rse_slot_num, ia64_rse_skip_regs): Ditto.
(ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
(ia64_is_fpreg, ia64_access_reg): Ditto.
(ia64_access_fpreg, ia64_access_mem): Ditto.
(get_kernel_table): Ditto.
(ia64_find_unwind_table): Ditto.
(ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
(ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
(ia64_libunwind_frame_prev_register): Ditto.
(ia64_libunwind_frame_sniffer,
(ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
sniffer. Set up getunwind_table function. Register libunwind functions
needed by generic libunwind frame code using
libunwind_frame_set_descr().
Ok? More comments?
-- Jeff J.
Kevin Buettner wrote:
On Oct 24, 2:20pm, J. Johnston wrote:
Kevin Buettner wrote:
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+# ifndef __NR_getunwind
+# define __NR_getunwind 1215
+# endif
Is this part still needed?
Not if we include <sys/syscall.h>
I would prefer to see <sys/syscall.h> included -- but not in
ia64-tdep.c. This include and the code for ia64_getunwind() will have
to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
use the unwind library, there'd need to be some remote protocol
modifications.
Also, apparently, there'll be some FreeBSD patches for IA-64 coming
down the pike. FreeBSD, if it chooses to use the libunwind library,
will need to implement its own version of ia64_getunwind().
Hmm... thinking about this some more, I'd like to know why a syscall
is required. Is there anyway this functionality could be implemented
in an OS independent fashion?
+static void *
+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
[...]
For the above, why isn't bfd being employed to read the segment?
Are you referring to using bfd_bread() if the mmap fails or do you mean
something higher level?
I hadn't given it much thought. It looked odd to see file reading
code in this patch. It might be okay to use bfd_bread if the mmap
fails, but I'd prefer to push as much of this problem (reading of
files) as possible over to the bfd side.
Kevin
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.101
diff -u -p -r1.101 ia64-tdep.c
--- ia64-tdep.c 23 Oct 2003 22:06:37 -0000 1.101
+++ ia64-tdep.c 28 Oct 2003 23:45:54 -0000
@@ -36,8 +36,16 @@
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
+#include <fcntl.h>
+#include <sys/mman.h>
#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
@@ -87,6 +95,7 @@ typedef enum instruction_type
/* 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;
@@ -264,12 +273,16 @@ struct gdbarch_tdep
and register number, returns the offset to the
given register from the start of the frame. */
CORE_ADDR (*find_global_pointer) (CORE_ADDR);
+
+ unsigned long (*getunwind_table) (void *buf, size_t len);
};
#define SIGCONTEXT_REGISTER_ADDRESS \
(gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
#define FIND_GLOBAL_POINTER \
(gdbarch_tdep (current_gdbarch)->find_global_pointer)
+#define GETUNWIND_TABLE \
+ (gdbarch_tdep (current_gdbarch)->getunwind_table)
int
ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
@@ -2104,6 +2117,580 @@ static const struct frame_base ia64_fram
ia64_frame_base_address
};
+#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;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+ return unw_is_fpreg (uw_regnum);
+}
+
+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:
+ 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:
+ /* Account for the fact that ptrace() returns 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:
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ 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;
+}
+
+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;
+}
+
+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));
+}
+
+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 (GETUNWIND_TABLE == 0)
+ internal_error (__FILE__, __LINE__,
+ "get_kernel_table: GETUNWIND_TABLE is 0");
+
+ if (!ktab)
+ {
+ size = GETUNWIND_TABLE (NULL, 0);
+ 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;
+}
+
+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_TABLE;
+ dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.ti.segbase = segbase;
+ dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+
+ *buf = xmalloc (p_text->p_filesz);
+ bfd_seek (bfd, p_text->p_offset, SEEK_SET);
+ bfd_bread (*buf, p_text->p_filesz, bfd);
+
+ dip->u.ti.table_data = (unw_word_t *)
+ ((char *)(*buf) + (p_unwind->p_vaddr - p_text->p_vaddr));
+
+ /* The following can happen in corner cases where dynamically
+ generated code falls into the same page that contains the
+ data-segment and the page-offset of the code is within the first
+ page of the executable. */
+ if (ip < dip->start_ip || ip >= dip->end_ip)
+ return -UNW_ENOINFO;
+
+ return 0;
+}
+
+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;
+ }
+ else
+ {
+ ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %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);
+
+ 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;
+}
+
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+ unw_proc_info_t *pip, void *arg)
+{
+ /* Nothing required for now. */
+}
+
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+ unw_word_t *dilap, void *arg)
+{
+ extern unw_word_t (*unw_ia64_find_dyn_list_p) (unw_addr_space_t, void *,
+ size_t, unw_word_t,
+ unw_word_t, void *);
+ 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.u.ti.table_data,
+ (di.u.ti.table_len
+ * sizeof (di.u.ti.table_data[0])),
+ di.u.ti.segbase, di.gp, 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;
+}
+
+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;
+}
+
+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 */
+};
+
+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 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). */
@@ -2771,6 +3358,12 @@ ia64_gdbarch_init (struct gdbarch_info i
else
tdep->find_global_pointer = generic_elf_find_global_pointer;
+ /* Set the method for obtaining the unwind table information. */
+ if (os_ident == ELFOSABI_LINUX)
+ tdep->getunwind_table = ia64_linux_getunwind_table;
+ else
+ tdep->getunwind_table = 0;
+
/* Define the ia64 floating-point format to gdb. */
builtin_type_ia64_ext =
init_type (TYPE_CODE_FLT, 128 / 8,
@@ -2826,6 +3419,10 @@ ia64_gdbarch_init (struct gdbarch_info i
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);
Index: ia64-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-tdep.c,v
retrieving revision 1.4
diff -u -p -r1.4 ia64-linux-tdep.c
--- ia64-linux-tdep.c 15 Oct 2003 22:55:32 -0000 1.4
+++ ia64-linux-tdep.c 28 Oct 2003 23:45:54 -0000
@@ -22,6 +22,7 @@
#include "defs.h"
#include "arch-utils.h"
#include "gdbcore.h"
+#include <sys/syscall.h>
/* The sigtramp code is in a non-readable (executable-only) region
of memory called the ``gate page''. The addresses in question
@@ -92,4 +93,10 @@ ia64_linux_sigcontext_register_address (
default :
return 0;
}
+}
+
+unsigned long
+ia64_linux_getunwind_table (void *buf, size_t len)
+{
+ return syscall (__NR_getunwind, buf, len);
}