Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Re: RFA: ia64 portion of libunwind patch
@ 2003-10-31 19:25 J. Johnston
  2003-10-31 20:46 ` Andrew Cagney
  2003-10-31 21:36 ` Marcel Moolenaar
  0 siblings, 2 replies; 63+ messages in thread
From: J. Johnston @ 2003-10-31 19:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Cagney, Kevin Buettner, davidm

David Mosberger has answered the questions below.  I'd like to include him in 
the discussion from now on.

-- Jeff J.

-------- Original Message --------

>>>>> On Thu, 30 Oct 2003 14:18:20 -0500, "J. Johnston" <jjohnstn@redhat.com> said:

   Andrew> Can you expand a little here on how this function interacts
   Andrew> with libunwind?

It is used by libunwind to access the unwind info.  This is read-only
data that part of the ELF image and (at least for ia64) is also mapped
into the target space.

   Andrew> I can see that its reading in data, but is that data found
   Andrew> in the target's space?

It could be found there.

   Andrew> If it is then the info should be pulled direct from the
   Andrew> target and the BFD/objfile should not be used.  The relevant
   Andrew> target stratum can then re-direct the request to a local
   Andrew> file.

I agree, it sounds like this would be a much cleaner way of doing it.

   Andrew> I'm also wondering if the unwind code (probably impossible I
   Andrew> know) could use a callback to request the memory rather than
   Andrew> require an entire buffer.

The way the libunwind interface works nowadays, the only buffering
that is strictly needed is for the unwind info of the procedure being
looked up (which usually has a size of the order of tens of bytes).
But this would require doing a binary search on the unwind-table in
the target space, which might be rather slow (there is one 24-byte
entry in this table per procedure).  Thus, it might be easier (and
certainly faster) to buffer the unwind table inside gdb.

	--david


^ permalink raw reply	[flat|nested] 63+ messages in thread
* RFA: ia64 portion of libunwind patch
@ 2003-10-24  0:11 J. Johnston
  2003-10-24 17:57 ` Kevin Buettner
  2003-10-29 15:18 ` Andrew Cagney
  0 siblings, 2 replies; 63+ messages in thread
From: J. Johnston @ 2003-10-24  0:11 UTC (permalink / raw)
  To: gdb-patches; +Cc: ac131313

[-- Attachment #1: Type: text/plain, Size: 1137 bytes --]

As requested, here is the other part of the libunwind patch to the ia64-tdep.c file.

2003-10-23  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.
	(ia64_getunwind): New function for libunwind support.
	(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, map_segment): Ditto.
	(map_info_free, 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.  Register libunwind functions needed by generic libunwind
	frame code using libunwind_frame_set_descr().

Ok to commit?  Questions regarding this in conjunction with the generic 
libunwind frame code?

-- Jeff J.

[-- Attachment #2: ia64-tdep.c.libunwind.patch --]
[-- Type: text/plain, Size: 20252 bytes --]

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	24 Oct 2003 00:00:41 -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
@@ -2104,6 +2112,659 @@ static const struct frame_base ia64_fram
   ia64_frame_base_address
 };
 
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+# ifndef __NR_getunwind
+#  define __NR_getunwind	1215
+# endif
+
+static unsigned long
+ia64_getunwind (void *buf, size_t len)
+{
+  return syscall (__NR_getunwind, buf, len);
+}
+
+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 (!ktab)
+      {
+      size = ia64_getunwind (NULL, 0);
+      ktab = xmalloc (size);
+      ia64_getunwind (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;
+}
+
+struct map_info
+{
+  void *buf;
+  size_t length;
+  int mapped;
+};
+
+static void *
+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
+  {
+  size_t page_mask = getpagesize () - 1, nbytes;
+  char *buf, *cp;
+  ssize_t nread;
+  int fd;
+  
+  if (bfd->iostream)
+    fd = fileno (bfd->iostream);
+  else
+    fd = open (bfd_get_filename (bfd), O_RDONLY);
+  
+  if (fd < 0)
+    return NULL;
+
+  buf = mmap (0, p_text->p_filesz, PROT_READ, MAP_PRIVATE, fd,
+	      p_text->p_offset & ~page_mask);
+  if (buf != (char *) -1)
+    {
+      mi->buf = buf;
+      mi->length = p_text->p_filesz;
+      mi->mapped = 1;
+      buf += p_text->p_offset & page_mask;
+    }
+  else
+    {
+      /* mmap () failed, try reading the file: */
+      mi->mapped = 0;
+      
+      if (lseek (fd, p_text->p_offset, SEEK_SET) < 0)
+	{
+	  if (!bfd->iostream)
+	    close (fd);
+	  return NULL;
+	}
+      
+      nbytes = p_text->p_filesz;
+      cp = buf = xmalloc (nbytes);
+      while ((nbytes > 0) && (nread = read (fd, cp, nbytes)) > 0)
+	{
+	  cp += nread;
+	  nbytes -= nread;
+  	}
+      if (nbytes > 0)
+	{
+	  /* premature end-of-file or some error */
+	  xfree (buf);
+	  buf = 0;
+	}
+      mi->buf = buf;
+    }
+  if (!bfd->iostream)
+    close (fd);
+  
+  return buf;
+}
+
+static void
+map_info_free (struct map_info *mi)
+{
+  if (mi->mapped)
+    munmap (mi->buf, mi->length);
+  else if (mi->buf)
+    xfree (mi->buf);
+}
+
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+			unw_dyn_info_t *dip, struct map_info *mip)
+{
+  Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+  Elf_Internal_Ehdr *ehdr;
+  void *unwind_info_base;
+  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);
+  unwind_info_base = map_segment (bfd, p_text, mip);
+  if (!unwind_info_base)
+    return -UNW_ENOINFO;
+  dip->u.ti.table_data = (unw_word_t *)
+    ((char *) unwind_info_base + (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;
+  struct map_info mi;
+
+  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, &mi);
+      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.  */
+  map_info_free (&mi);
+
+  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)
+    {
+      struct map_info mi;
+
+      text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+      ip = text_sec->addr;
+      ret = ia64_find_unwind_table (objfile, ip, &di, &mi);
+      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.  */
+	  map_info_free (&mi);
+
+	  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).  */
@@ -2826,6 +3487,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);
 

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2004-02-23 21:15 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-10-31 19:25 RFA: ia64 portion of libunwind patch J. Johnston
2003-10-31 20:46 ` Andrew Cagney
2003-10-31 22:55   ` David Mosberger
2003-11-07 21:47     ` Andrew Cagney
2003-11-07 22:43       ` David Mosberger
2003-11-07 23:01         ` Andrew Cagney
2003-11-07 23:12           ` David Mosberger
2003-11-07 23:38             ` Andrew Cagney
2003-11-07 23:55               ` David Mosberger
2003-11-08  0:07                 ` Andrew Cagney
2003-11-08  0:13                   ` Kevin Buettner
2003-11-08  0:27                     ` Andrew Cagney
2003-11-08  7:21                       ` David Mosberger
2003-11-09  0:13                         ` Andrew Cagney
2003-11-10 22:10                           ` David Mosberger
2003-11-10 22:43                             ` Andrew Cagney
2003-11-10 23:01                               ` David Mosberger
2003-11-26  0:11                               ` David Mosberger
2003-12-04  2:15                                 ` David Mosberger
2003-12-04  3:15                                   ` Kevin Buettner
2003-12-04 23:57                                   ` J. Johnston
2003-12-05  0:39                                     ` David Mosberger
2003-12-10 20:58                                       ` J. Johnston
2003-12-10 22:15                                         ` David Mosberger
2003-12-12 22:25                                         ` Kevin Buettner
     [not found]                                 ` <davidm@napali.hpl.hp.com>
2003-12-13  4:01                                   ` Kevin Buettner
2003-12-31 20:19                                     ` make inferior calls work on ia64 even when syscall is pending David Mosberger
2003-12-31 23:37                                       ` Mark Kettenis
2004-01-01  2:43                                         ` David Mosberger
2004-02-13  1:14                                         ` David Mosberger
2004-02-13 15:00                                           ` Mark Kettenis
2004-02-13 15:09                                             ` Andrew Cagney
2004-02-13 15:12                                             ` Andrew Cagney
2004-02-13 22:07                                               ` David Mosberger
2004-02-17 16:21                                                 ` Andrew Cagney
2004-02-23 19:58                                                   ` Kevin Buettner
2004-02-23 21:15                                                 ` Kevin Buettner
2003-11-09  1:34             ` RFA: ia64 portion of libunwind patch Marcel Moolenaar
2003-11-10 21:54               ` David Mosberger
2003-11-10 23:18                 ` Marcel Moolenaar
2003-10-31 21:36 ` Marcel Moolenaar
2003-10-31 23:00   ` David Mosberger
2003-10-31 23:42     ` Andrew Cagney
2003-10-31 23:59       ` David Mosberger
  -- strict thread matches above, loose matches on Subject: below --
2003-10-24  0:11 J. Johnston
2003-10-24 17:57 ` Kevin Buettner
2003-10-24 18:20   ` J. Johnston
2003-10-24 18:56     ` Kevin Buettner
2003-10-24 21:53       ` Marcel Moolenaar
2003-10-24 23:58         ` Kevin Buettner
2003-10-28 23:53       ` J. Johnston
2003-10-29  1:28         ` Daniel Jacobowitz
2003-10-29  4:48           ` Kevin Buettner
2003-10-29 18:43             ` J. Johnston
2003-10-29 22:48           ` Andrew Cagney
2003-11-04 19:09             ` J. Johnston
2003-11-04 20:48               ` Kevin Buettner
2003-11-14  0:26               ` J. Johnston
2003-11-14  1:17                 ` Kevin Buettner
2003-11-14 20:49                   ` J. Johnston
2003-10-29 23:28         ` Andrew Cagney
2003-11-02 20:39         ` Elena Zannoni
2003-10-29 15:18 ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox