This is the mail archive of the gdb-patches@sourceware.org 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] Fix "break foo" when `foo's prologue ends before line table


With the following test program (tchset.c)

    #include <stdio.h>
    #include <libcharset.h>

    int main (void)
    {
      const char *cset = locale_charset ();

      if (cset)
	printf ("locale_charset: `%s'\n", cset);
      else
	printf ("locale_charset: NULL\n");

      return 0;
    }

and the DJGPP build of a recent snapshot, trying to set a breakpoint
in `main' makes GDB think `main' has no source line info, if I compile
the program with COFF debug info ("gcc -gcoff -o tchset44c.exe tchset.c").

Observe:

  D:\usr\djgpp\gnu\gdb-68.410\gdb>.\gdb.exe --nx ./tchset44c.exe
  GNU gdb (GDB) 6.8.50.20090410
  Copyright (C) 2009 Free Software Foundation, Inc.
  License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  This is free software: you are free to change and redistribute it.
  There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
  and "show warranty" for details.
  This GDB was configured as "--host=i586-pc-msdosdjgpp --target=djgpp".
  For bug reporting instructions, please see:
  <http://www.gnu.org/software/gdb/bugs/>...
  (gdb) break main
  Breakpoint 1 at 0x1732
  (gdb) 

With GDB 6.1, it does work:

  GNU gdb 6.1
  Copyright 2004 Free Software Foundation, Inc.
  GDB is free software, covered by the GNU General Public License, and you are
  welcome to change it and/or distribute copies of it under certain conditions.
  Type "show copying" to see the conditions.
  There is absolutely no warranty for GDB.  Type "show warranty" for details.
  This GDB was configured as "--host=i386-pc-msdosdjgpp --target=djgpp"...
  (gdb) break main
  Breakpoint 1 at 0x1748: file tchset.c, line 6.

The reason is this change:

  2006-11-28  Daniel Jacobowitz  <dan@codesourcery.com>

	  * symtab.c (find_pc_sect_line): Do not return a line before
	  the start of a symtab.

(No, I'm not suggesting to revert that change.  I want to show my
analysis of this problem and suggest a solution.)

Using "maint print symbols", I see this:

  Symtab for file tchset.c
  Read from object file d:/usr/djgpp/gnu/gdb-68.410/gdb/./tchset44c.exe (0x43be20)
  Language: c

  Line table:

   line 6 at 0x1748
   line 8 at 0x1750
   line 9 at 0x1756
   line 11 at 0x176b
   line 13 at 0x177b
   line 14 at 0x1780

  Blockvector:

  block #000, object at 0x4403fc, 1 syms/buckets in 0x1700..0x1782
   int main(); block object 0x440394, 0x172c..0x1782 section .text
    block #001, object at 0x4403c4 under 0x4403fc, 2 syms/buckets in 0x1700..0x1782
  [...]
      block #002, object at 0x440394 under 0x4403c4, 0 syms/buckets in 0x172c..0x1782, function main

Note that the lineinfo table for the program starts at line 6 at PC
0x1748, whereas the function `main' begins at PC 0x172c.

When I type "break main", we eventually call find_function_start_sal,
which skips the prologue, and then calls find_pc_sect_line to find the
sal for the PC after the prologue.  But skipping the prologue in this
cases gets us to PC 0x1732, which is still outside the lineinfo
table.  So find_pc_sect_line fails to find a suitable source line,
returns a sal without a symtab, and GDB then thinks `main' is a
function with no source line information.

Here's the disassembly of `main', in case someone thinks that
skip_prologue function didn't do a good job (I think it did a
reasonable job, but I'm far from being an expert on prologue
analysis):

    Dump of assembler code for function main:
    0x0000172c <main+0>:    push   %ebp
    0x0000172d <main+1>:    mov    %esp,%ebp
    0x0000172f <main+3>:    sub    $0x8,%esp
    0x00001732 <main+6>:    and    $0xfffffff0,%esp
    0x00001735 <main+9>:    mov    $0x0,%eax
    0x0000173a <main+14>:   add    $0xf,%eax
    0x0000173d <main+17>:   add    $0xf,%eax
    0x00001740 <main+20>:   shr    $0x4,%eax
    0x00001743 <main+23>:   shl    $0x4,%eax
    0x00001746 <main+26>:   sub    %eax,%esp
    0x00001748 <main+28>:   call   0x17e0 <locale_charset>
    0x0000174d <main+33>:   mov    %eax,0xfffffffc(%ebp)
    0x00001750 <main+36>:   cmpl   $0x0,0xfffffffc(%ebp)
    0x00001754 <main+40>:   je     0x176b <main+63>
    0x00001756 <main+42>:   sub    $0x8,%esp
    0x00001759 <main+45>:   pushl  0xfffffffc(%ebp)
    0x0000175c <main+48>:   push   $0x1700
    0x00001761 <main+53>:   call   0x3950 <printf>
    0x00001766 <main+58>:   add    $0x10,%esp
    0x00001769 <main+61>:   jmp    0x177b <main+79>
    0x0000176b <main+63>:   sub    $0xc,%esp
    0x0000176e <main+66>:   push   $0x1716
    0x00001773 <main+71>:   call   0x3950 <printf>
    0x00001778 <main+76>:   add    $0x10,%esp
    0x0000177b <main+79>:   mov    $0x0,%eax
    0x00001780 <main+84>:   leave
    0x00001781 <main+85>:   ret

If I compile the same program with -gdwarf-2, the problem does not
happen because the lineinfo table now includes one more entry, for
line 5 of the file.  But I cannot deprecate usage of COFF debug info
in DJGPP, because that is the only way to build the DJGPP port of
Emacs (the code in Emacs's unexec.c was never updated to handle
DWARF-2, and probably never will).

My suggestion for solving this is in the patch below.  The idea is
that we make one more attempt to find the first line of the function's
body, using the lineinfo table.  We loop over all symtabs for the
function's file, looking for an entry in a lineinfo table whose PC is
in the range [FUNC_START..FUNC_END] and whose line number is the
smallest.  FUNC_START and FUNC_END are obtained via a call to
find_pc_partial_function.

Is this idea reasonable?  Is the patch okay to commit?

2009-05-09  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.

--- symtab.c~0	2009-04-01 02:21:07.000000000 +0300
+++ symtab.c	2009-05-09 16:40:36.442027000 +0300
@@ -2599,6 +2599,68 @@
   return pc;
 }
 
+/* Given a function start address FUNC_ADDR and SYMTAB, find the first
+   address for that function that has an entry in any line info table
+   that comes from any symtab for the same file as SYMTAB.  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 objfile *objfile;
+  struct partial_symtab *p;
+  struct symtab *s;
+  int best_lineno = 0;
+  CORE_ADDR best_pc = 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;
+
+  ALL_PSYMTABS (objfile, p)
+    {
+      if (FILENAME_CMP (symtab->filename, p->filename) != 0)
+	continue;
+      PSYMTAB_TO_SYMTAB (p);
+    }
+
+  /* Loop over all symtabs for the function's file, looking for an
+     entry in a lineinfo table whose PC is in the range
+     [FUNC_START..FUNC_END] and whose line number is the smallest.  */
+  ALL_SYMTABS (objfile, s)
+    {
+      struct linetable *l;
+      int ind, i, len;
+
+      if (FILENAME_CMP (symtab->filename, s->filename) != 0)
+	continue;
+      l = LINETABLE (s);
+      if (l == NULL)
+	continue;
+
+      len = l->nitems;
+      for (i = 0; i < len; 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)
+	    {
+	      if (!best_lineno || item->line < best_lineno)
+		{
+		  best_lineno = item->line;
+		  best_pc = item->pc;
+		}
+	    }
+	}
+    }
+  return best_pc;
+}
+
 /* 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 +2711,15 @@
       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
+     line in the lineinfo table that belongs to the same function.  */
+  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;


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