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]

RFA/mips: Use ".pdr" sections generated by GAS


ECOFF debug information (mdebug) included the concept of a PDR.  MIPS uses
these for unwinding through functions, among other things.  Right now we can
get them from mdebug or from code inspection.  But current GNU binutils
emits ".pdr" sections instead of using the old ".mdebug" style debug info.

This patch lets us read and handle the .pdr sections.  It's only for
32-bit, because for 64-bit gas currently emits only half the address.  That
I'll address later.  It changes a testsuite run from 5591 calls to
heuristic_proc_desc to 1787 calls.  Most or all of those are because we
build a heuristic procedure description if we find that we are still in the
prologue of a function.  The new ".pdr" method finds a PDR successfully for
nearly all calls to non_heuristic_proc_desc; the others are probably either a
lingering library on my system built by an older assembler, or signal/solib
trampolines.  Only 29 misses total.

There's an increase in memory usage per-objfile, but no leaks, and the
section is generally not large; for all of GDB it is only 78K.

Andrew, does this look OK to you?

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer
2002-06-11  Daniel Jacobowitz  <drow@mvista.com>

	* mips-tdep.c (PROC_SYMBOL): Add warning comment.
	(struct mips_objfile_private, compare_pdr_entries): New.
	(non_heuristic_proc_desc): Read the ".pdr" section if it
	is present.

Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.75
diff -u -p -u -r1.75 mips-tdep.c
--- mips-tdep.c	9 Jun 2002 19:36:15 -0000	1.75
+++ mips-tdep.c	11 Jun 2002 16:54:51 -0000
@@ -425,6 +425,8 @@ static unsigned int heuristic_fence_post
 #define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
 #define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
 #define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
+/* FIXME drow/2002-06-10: If a pointer on the host is bigger than a long,
+   this will corrupt pdr.iline.  Fortunately we don't use it.  */
 #define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym)
 #define _PROC_MAGIC_ 0x0F0F0F0F
 #define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_)
@@ -1932,6 +1934,30 @@ heuristic_proc_desc (CORE_ADDR start_pc,
   return &temp_proc_desc;
 }
 
+struct mips_objfile_private
+{
+  bfd_size_type size;
+  char *contents;
+};
+
+/* Global used to communicate between non_heuristic_proc_desc and
+   compare_pdr_entries.  */
+static bfd *the_bfd;
+
+static int
+compare_pdr_entries (const void *a, const void *b)
+{
+  CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a);
+  CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b);
+
+  if (lhs < rhs)
+    return -1;
+  else if (lhs == rhs)
+    return 0;
+  else
+    return 1;
+}
+
 static mips_extra_func_info_t
 non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
 {
@@ -1939,22 +1965,143 @@ non_heuristic_proc_desc (CORE_ADDR pc, C
   mips_extra_func_info_t proc_desc;
   struct block *b = block_for_pc (pc);
   struct symbol *sym;
+  struct obj_section *sec;
+  struct mips_objfile_private *priv;
+
+  if (PC_IN_CALL_DUMMY (pc, 0, 0))
+    return NULL;
 
   find_pc_partial_function (pc, NULL, &startaddr, NULL);
   if (addrptr)
     *addrptr = startaddr;
-  if (b == NULL || PC_IN_CALL_DUMMY (pc, 0, 0))
-    sym = NULL;
-  else
+
+  priv = NULL;
+
+  sec = find_pc_section (pc);
+  if (sec != NULL)
     {
-      if (startaddr > BLOCK_START (b))
-	/* This is the "pathological" case referred to in a comment in
-	   print_frame_info.  It might be better to move this check into
-	   symbol reading.  */
-	sym = NULL;
-      else
-	sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
+      priv = (struct mips_objfile_private *) sec->objfile->obj_private;
+
+      /* Search the ".pdr" section generated by GAS.  This includes most of
+	 the information normally found in ECOFF PDRs.
+
+	 Right now GAS only outputs the address as a four-byte sequence.  This
+	 means that we should not bother with this method on 64-bit targets
+	 until that is fixed.  */
+
+      the_bfd = sec->objfile->obfd;
+      if (priv == NULL
+	  && (the_bfd->format == bfd_object
+	      && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
+	      && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
+	{
+	  priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+				sizeof (struct mips_objfile_private));
+	  priv->size = 0;
+	  sec->objfile->obj_private = priv;
+	}
+      else if (priv == NULL)
+	{
+	  asection *bfdsec;
+
+	  priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+				sizeof (struct mips_objfile_private));
+
+	  bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
+	  if (bfdsec != NULL)
+	    {
+	      priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
+	      priv->contents = obstack_alloc (& sec->objfile->psymbol_obstack,
+					      priv->size);
+	      bfd_get_section_contents (sec->objfile->obfd, bfdsec,
+					priv->contents, 0, priv->size);
+
+	      /* In general, the .pdr section is sorted.  However, in the
+		 presence of multiple code sections (and other corner cases)
+		 it can become unsorted.  Sort it so that we can use a faster
+		 binary search.  */
+	      qsort (priv->contents, priv->size / 32, 32, compare_pdr_entries);
+	    }
+	  else
+	    priv->size = 0;
+
+	  sec->objfile->obj_private = priv;
+	}
+
+      if (priv->size != 0)
+	{
+	  int low, mid, high;
+	  char *ptr;
+
+	  low = 0;
+	  high = priv->size / 32;
+
+	  do
+	    {
+	      CORE_ADDR pdr_pc;
+
+	      mid = (low + high) / 2;
+
+	      ptr = priv->contents + mid * 32;
+	      pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
+	      pdr_pc += ANOFFSET (sec->objfile->section_offsets,
+				  SECT_OFF_TEXT (sec->objfile));
+	      if (pdr_pc == startaddr)
+		break;
+	      if (pdr_pc > startaddr)
+		high = mid;
+	      else
+		low = mid + 1;
+	    }
+	  while (low != high);
+
+	  if (low != high)
+	    {
+	      struct symbol *sym = find_pc_function (pc);
+
+	      /* Fill in what we need of the proc_desc.  */
+	      proc_desc = (mips_extra_func_info_t)
+		obstack_alloc (&sec->objfile->psymbol_obstack,
+			       sizeof (struct mips_extra_func_info));
+	      PROC_LOW_ADDR (proc_desc) = startaddr;
+
+	      /* Only used for dummy frames.  */
+	      PROC_HIGH_ADDR (proc_desc) = 0;
+
+	      PROC_FRAME_OFFSET (proc_desc)
+		= bfd_get_32 (sec->objfile->obfd, ptr + 20);
+	      PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+						       ptr + 24);
+	      PROC_FRAME_ADJUST (proc_desc) = 0;
+	      PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+						      ptr + 4);
+	      PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+						       ptr + 12);
+	      PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+							ptr + 8);
+	      PROC_FREG_OFFSET (proc_desc)
+		= bfd_get_32 (sec->objfile->obfd, ptr + 16);
+	      PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+						    ptr + 28);
+	      proc_desc->pdr.isym = (long) sym;
+
+	      return proc_desc;
+	    }
+	}
     }
+
+  if (b == NULL)
+    return NULL;
+
+  if (startaddr > BLOCK_START (b))
+    {
+      /* This is the "pathological" case referred to in a comment in
+	 print_frame_info.  It might be better to move this check into
+	 symbol reading.  */
+      return NULL;
+    }
+
+  sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
 
   /* If we never found a PDR for this function in symbol reading, then
      examine prologues to find the information.  */

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