* symtab.c (skip_prologue_using_lineinfo): New function.
authorEli Zaretskii <eliz@gnu.org>
Sat, 23 May 2009 10:11:42 +0000 (10:11 +0000)
committerEli Zaretskii <eliz@gnu.org>
Sat, 23 May 2009 10:11:42 +0000 (10:11 +0000)
(find_function_start_sal): Use it to get to the first line of
function's body that has an entry in the lineinfo table.

gdb/ChangeLog
gdb/symtab.c

index 496ea3b8043506817e6e7d14a01fec9df90112d8..97806a147a0dad0ed3332fa92281dc85d82669fc 100644 (file)
@@ -1,5 +1,9 @@
 2009-05-23  Eli Zaretskii  <eliz@gnu.org>
 
+       * symtab.c (skip_prologue_using_lineinfo): New function.
+       (find_function_start_sal): Use it to get to the first line of
+       function's body that has an entry in the lineinfo table.
+
        * symmisc.c (dump_symtab): Switch the current language to
        the language of the symtab we are dumping only if the symtab's
        language is neither language_auto nor language_unknown.
index b8a6c31b1b04c5253ee062e973ebdb2b45882c01..5d375abaa94fecd88a8467992bead61b8d5e6c1a 100644 (file)
@@ -2599,6 +2599,47 @@ find_function_start_pc (struct gdbarch *gdbarch,
   return pc;
 }
 
+/* Given a function start address FUNC_ADDR and SYMTAB, find the first
+   address for that function that has an entry in SYMTAB's line info
+   table.  If such an entry cannot be found, return FUNC_ADDR
+   unaltered.  */
+CORE_ADDR
+skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab)
+{
+  CORE_ADDR func_start, func_end;
+  struct linetable *l;
+  int ind, i, len;
+  int best_lineno = 0;
+  CORE_ADDR best_pc = func_addr;
+
+  /* Give up if this symbol has no lineinfo table.  */
+  l = LINETABLE (symtab);
+  if (l == NULL)
+    return func_addr;
+
+  /* Get the range for the function's PC values, or give up if we
+     cannot, for some reason.  */
+  if (!find_pc_partial_function (func_addr, NULL, &func_start, &func_end))
+    return func_addr;
+
+  /* Linetable entries are ordered by PC values, see the commentary in
+     symtab.h where `struct linetable' is defined.  Thus, the first
+     entry whose PC is in the range [FUNC_START..FUNC_END[ is the
+     address we are looking for.  */
+  for (i = 0; i < l->nitems; i++)
+    {
+      struct linetable_entry *item = &(l->item[i]);
+
+      /* Don't use line numbers of zero, they mark special entries in
+        the table.  See the commentary on symtab.h before the
+        definition of struct linetable.  */
+      if (item->line > 0 && func_start <= item->pc && item->pc < func_end)
+       return item->pc;
+    }
+
+  return func_addr;
+}
+
 /* Given a function symbol SYM, find the symtab and line for the start
    of the function.
    If the argument FUNFIRSTLINE is nonzero, we want the first line
@@ -2649,6 +2690,21 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
       sal = find_pc_sect_line (pc, SYMBOL_OBJ_SECTION (sym), 0);
     }
 
+  /* If we still don't have a valid source line, try to find the first
+     PC in the lineinfo table that belongs to the same function.  This
+     happens with COFF debug info, which does not seem to have an
+     entry in lineinfo table for the code after the prologue which has
+     no direct relation to source.  For example, this was found to be
+     the case with the DJGPP target using "gcc -gcoff" when the
+     compiler inserted code after the prologue to make sure the stack
+     is aligned.  */
+  if (funfirstline && sal.symtab == NULL)
+    {
+      pc = skip_prologue_using_lineinfo (pc, SYMBOL_SYMTAB (sym));
+      /* Recalculate the line number.  */
+      sal = find_pc_sect_line (pc, SYMBOL_OBJ_SECTION (sym), 0);
+    }
+
   sal.pc = pc;
 
   return sal;