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


J. Johnston writes:
 > 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?

yes, more comments :-) I mean, can you add comments in the code. There
are basically none, and this stuff is quite complex. If anybody else
needs to uderstand the details, it definitely would be easier if each
function had a comment explaining what it does. 

elena


 > 
 > -- 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]