stabs at function entry point?

Daniel Jacobowitz drow@mvista.com
Sat Mar 16 17:14:00 GMT 2002


John reported a bug in addr2line with stabs debug info.

Right now, we initialize everything (file name, directory name, etc.)
except for line number before we start the linear search.  But we've found
which function it is in at this point, and if it is in the prologue
we've just skipped past the only stab that will tell us the line
number.  This patch simply picks up the line number from the N_FUN stab
before we begin (or possible an N_SO in some circumstances, I think). 
It looks correct to me, and causes no regressions in binutils, ld, or
gas (although I get a flonums FAIL in gas/gasp right now).  GDB doesn't
use this code at all, though perhaps it should :)

As for DWARF2 - we don't do this correctly there either.  For the first
function in a compilation unit, we will return ??:0, because the first
entry in the line table will be just after the prologue.  For the
second and subsequent functions, we return the name of the correct
function but the last line of the previous function.  You could argue
this either way; it sounds to me as if GCC should emit line number
information for the first PC of the function.  We can detect this and
handle it correctly in binutils, however, and I believe we should
(permissive in what we accept and all that).  If the line we found
starts before the function we found, we could use the first line of the
function we found.  It's a little hokey of a heuristic, but I can think
of no case in which it would return less useful information than what
we have, and I've got two trivial examples in which it is better.


All the other debug formats seem to have the same "problem".  These are
just the two I could easily test; if someone hollers I could try to fix
dwarf1 too (though I'd rather just let it die...).  I don't grok ecoff
well enough, and I'm keeping my hands out of pdp11.c on principal
(;-)).  There's probably one or two more, but most of the others (like
SOM) seem to be dummies.

Is the patch at the end of this message OK?  John, does the patch work
for you?

On Wed, Mar 13, 2002 at 09:19:20PM -0500, Daniel Jacobowitz wrote:
> On Thu, Mar 14, 2002 at 01:32:24AM +0000, John Levon wrote:
> > On Wed, Mar 13, 2002 at 08:18:05PM -0500, Daniel Jacobowitz wrote:
> > 
> > > Have you looked at the find_nearest_line code for stabs?  It's in
> > > bfd/syms.c.  It reads the line numbers from function stabs into the
> > > line table.  The presence or absence of a matching line number marking
> > > should be No Big Deal for this interface.
> > 
> > Browsing the code, it looks like if I look up the very start of the
> > function, and there's no entry at the given vma (so that :
> > 
> >    1185           if (offset >= info->indextable[mid].val
> >    1186               && offset < info->indextable[mid + 1].val)
> > 
> > would catch it), then the above binary search will find the previous
> > stab entry. So for example the first function in a file will come out as
> > :
> > 
> > file.c:0
> > 
> > since *pline never gets set properly.
> > 
> > And we've recently seen this problem with a user using 2.95.3.
> > 
> > So either our definitions of Big Deal differ, or I'm just wrong and 
> > the problem we've been seeing is unrelated to what's being discussed
> > here.
> 
> Both right again... the line information for the N_FUN stab is entered,
> but then not used in the line number search.  I believe this is simply
> a bug in BFD.  I'll test a patch later this week.
> 
> In other words, I don't believe this function needs the initial stab.

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer


2002-03-16  Daniel Jacobowitz  <drow@mvista.com>

	* dwarf2.c (struct funcinfo): Move up.
	(lookup_address_in_function_table): New argument function_ptr.
	Set it.
	(lookup_address_in_line_table): New argument function.  If function
	is non-NULL, use it to handle ``addr'' before the first line note of
	the function.
	(comp_unit_find_nearest_line): Update and swap calls to
	lookup_address_in_function_table and lookup_address_in_line_table.
	* syms.c (_bfd_stab_section_find_nearest_line): Set *pline initially
	to the start of the function containing ``offset''.

Index: bfd/dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.28
diff -u -p -r1.28 dwarf2.c
--- dwarf2.c	2002/01/30 10:28:47	1.28
+++ dwarf2.c	2002/03/17 01:09:03
@@ -240,9 +240,10 @@ static void arange_add PARAMS ((struct c
 static struct line_info_table *decode_line_info
   PARAMS ((struct comp_unit *, struct dwarf2_debug *));
 static boolean lookup_address_in_line_info_table
-  PARAMS ((struct line_info_table *, bfd_vma, const char **, unsigned int *));
+  PARAMS ((struct line_info_table *, bfd_vma, struct funcinfo *,
+	   const char **, unsigned int *));
 static boolean lookup_address_in_function_table
-  PARAMS ((struct funcinfo *, bfd_vma, const char **));
+  PARAMS ((struct funcinfo *, bfd_vma, struct funcinfo **, const char **));
 static boolean scan_unit_for_functions PARAMS ((struct comp_unit *));
 static bfd_vma find_rela_addend
   PARAMS ((bfd *, asection *, bfd_size_type, asymbol**));
@@ -808,6 +809,14 @@ struct line_info_table
   struct line_info* last_line;
 };
 
+struct funcinfo
+{
+  struct funcinfo *prev_func;
+  char* name;
+  bfd_vma low;
+  bfd_vma high;
+};
+
 static void
 add_line_info (table, address, filename, line, column, end_sequence)
      struct line_info_table* table;
@@ -1215,10 +1224,12 @@ decode_line_info (unit, stash)
 static boolean
 lookup_address_in_line_info_table (table,
 				   addr,
+				   function,
 				   filename_ptr,
 				   linenumber_ptr)
      struct line_info_table* table;
      bfd_vma addr;
+     struct funcinfo *function;
      const char **filename_ptr;
      unsigned int *linenumber_ptr;
 {
@@ -1235,35 +1246,52 @@ lookup_address_in_line_info_table (table
       if (!each_line->end_sequence
 	  && addr >= each_line->address && addr < next_line->address)
 	{
-	  *filename_ptr = each_line->filename;
-	  *linenumber_ptr = each_line->line;
+	  /* If this line appears to span functions, and addr is in the
+	     later function, return the first line of that function instead
+	     of the last line of the earlier one.  */
+	  if (function != NULL
+	      && each_line->address < function->low
+	      && next_line->address > function->low)
+	    {
+	      *filename_ptr = next_line->filename;
+	      *linenumber_ptr = next_line->line;
+	    }
+	  else
+	    {
+	      *filename_ptr = each_line->filename;
+	      *linenumber_ptr = each_line->line;
+	    }
 	  return true;
 	}
       next_line = each_line;
       each_line = each_line->prev_line;
     }
 
+  /* At this point each_line is NULL but next_line is not.  If we found the
+     containing function in this compilation unit, return the first line we
+     have a number for.  */
+  if (function != NULL)
+    {
+      *filename_ptr = next_line->filename;
+      *linenumber_ptr = next_line->line;
+      return true;
+    }
+
   return false;
 }
 
 /* Function table functions.  */
 
-struct funcinfo
-{
-  struct funcinfo *prev_func;
-  char* name;
-  bfd_vma low;
-  bfd_vma high;
-};
-
 /* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return true.  */
 
 static boolean
 lookup_address_in_function_table (table,
 				  addr,
+				  function_ptr,
 				  functionname_ptr)
      struct funcinfo* table;
      bfd_vma addr;
+     struct funcinfo** function_ptr;
      const char **functionname_ptr;
 {
   struct funcinfo* each_func;
@@ -1275,6 +1303,7 @@ lookup_address_in_function_table (table,
       if (addr >= each_func->low && addr < each_func->high)
 	{
 	  *functionname_ptr = each_func->name;
+	  *function_ptr = each_func;
 	  return true;
 	}
     }
@@ -1636,6 +1665,7 @@ comp_unit_find_nearest_line (unit, addr,
 {
   boolean line_p;
   boolean func_p;
+  struct funcinfo *function;
 
   if (unit->error)
     return false;
@@ -1664,13 +1694,16 @@ comp_unit_find_nearest_line (unit, addr,
 	}
     }
 
+  function = NULL;
+  func_p = lookup_address_in_function_table (unit->function_table,
+					     addr,
+					     &function,
+					     functionname_ptr);
   line_p = lookup_address_in_line_info_table (unit->line_table,
 					      addr,
+					      function,
 					      filename_ptr,
 					      linenumber_ptr);
-  func_p = lookup_address_in_function_table (unit->function_table,
-					     addr,
-					     functionname_ptr);
   return line_p || func_p;
 }
 
Index: bfd/syms.c
===================================================================
RCS file: /cvs/src/src/bfd/syms.c,v
retrieving revision 1.18
diff -u -p -r1.18 syms.c
--- syms.c	2002/02/19 16:33:04	1.18
+++ syms.c	2002/03/17 01:09:04
@@ -1233,6 +1233,7 @@ _bfd_stab_section_find_nearest_line (abf
       file_name = indexentry->file_name;
     }
 
+  *pline = bfd_get_16 (abfd, indexentry->stab + DESCOFF);
   directory_name = indexentry->directory_name;
   str = indexentry->str;
 



More information about the Binutils mailing list