This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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);
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]