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]

[RFC] Gdb line table implementation tweak


The implementation of gdb's line number table can cause gdb to give
misleading results when some parts of a program are compiled with
debugging enabled and other parts are not.  Here is an example:

  $ cat Makefile
  CXX =   g++
  
  all:    p p.stabs p1.o.stabs
  
  p:      p1.o p2.o
          $(CXX) -o p p1.o p2.o
  
  p1.o:   p1.s
          $(CXX) -c p1.s
  
  p2.o:   p2.s
          $(CXX) -c p2.s
  
  p1.s:   p1.cpp
          $(CXX) -g -S p1.cpp
  
  p2.s:   p2.cpp
          $(CXX) -S p2.cpp
  
  p.stabs:        p
          objdump --stabs p >p.stabs
  
  p1.o.stabs:     p1.o
          objdump --stabs p1.o >p1.o.stabs
  
  clean:
          rm -f p1.o p2.o p1.s p2.s p Makefile~ *.syms *.stabs
  
  
  $ cat p1.cpp
  #include <stdio.h>
  
  class MainClass
  {
  public:
    MainClass() {};
    ~MainClass() {};
    virtual void main();
  };
  
  void MainClass::main()
  {
  }
  
  int main(int argc, char** argv)
  {
    extern void subr (int);
    subr (5);
  }
  
  $ cat p2.cpp
  #include <stdio.h>
  
  void subr (int x)
  {
    printf ("x = %d\n", x);
  }
  $

If we run make to build executable 'p', where p1.o is compiled with
debugging enabled and p2.o is compiled without debugging, gdb gets
confused about what file subr() is in.  It thinks it is in p1.cpp,
when it is really in p2.cpp:

  $make
  g++ -g -S p1.cpp
  g++ -c p1.s
  g++ -S p2.cpp
  g++ -c p2.s
  g++ -o p p1.o p2.o
  objdump --stabs p >p.stabs
  objdump --stabs p1.o >p1.o.stabs
  $ /usr/sourceware/bin/gdb p
  GNU gdb 2002-02-12-cvs
  Copyright 2002 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 "i686-pc-linux-gnu"...
  (gdb) br *0x8048634
  Breakpoint 1 at 0x8048634: file p1.cpp, line 19.
  (gdb) x/i 0x8048634
  0x8048634 <subr__Fi>:   push   %ebp
  (gdb) run
  Starting program: /cygnus/cases/106539/example5-linux/p
  
  Breakpoint 1, 0x08048634 in subr () at p1.cpp:19
  19      }
  (gdb) bt
  #0  0x08048634 in subr () at p1.cpp:19
  #1  0x400b2306 in __libc_start_main (main=0x8048618 <main>, argc=1, ubp_av=0xbfffeef4, init=0x8048474 <_init>, fini=0x80486f8 <_fini>, rtld_fini=0x4000d2dc <_dl_fini>,
      stack_end=0xbfffeeec) at ../sysdeps/generic/libc-start.c:129
  (gdb) quit
  The program is running.  Exit anyway? (y or n) y
  $

Note in the above, setting the breakpoint at the first instruction of
subr() appears to put it at line 19 in p1.cpp.  When the program is
run and gdb stops at subr(), which is actually in p2.cpp, it prints it
wrong again.  And in the backtrace, gdb gets the right function, but
the wrong file and line number.

One way to fix this is to slightly change the line table such that it
allows gdb to know what ranges of PC's represent ranges for which line
number info is valid and which don't.  An easy way to do that is to
use an entry with a line number of zero to mark ranges that have no
valid line number info.

For example, the line table for p1.cpp is:

 Line table:

 line 12 at 0x8048610
 line 13 at 0x8048616
 line 16 at 0x8048618
 line 18 at 0x804861e
 line 19 at 0x804862b
 line 9 at 0x8048690
 line 19 at 0x8048696
 line 6 at 0x80486bc
 line 7 at 0x80486cc

After applying the attached patch, gdb's internal representation of
the line table for p1.cpp changes to the following:

 Line table:

 line 12 at 0x8048610
 line 13 at 0x8048616
 line 0 at 0x8048618
 line 16 at 0x8048618
 line 18 at 0x804861e
 line 19 at 0x804862b
 line 0 at 0x8048632
 line 9 at 0x8048690
 line 19 at 0x8048696
 line 0 at 0x80486bb
 line 6 at 0x80486bc
 line 0 at 0x80486ca
 line 7 at 0x80486cc
 line 0 at 0x80486f5

And rerunning gdb on the test case produces:

  $ /tmp/gdb p
  GNU gdb 2002-02-12-cvs
  Copyright 2002 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 "i686-pc-linux-gnu"...
  (gdb) br *0x8048634
  Breakpoint 1 at 0x8048634
  (gdb) x/i 0x8048634
  0x8048634 <subr__Fi>:   push   %ebp
  (gdb) run
  Starting program: /cygnus/cases/106539/example5-linux/p
  
  Breakpoint 1, 0x08048634 in subr ()
  (gdb) bt
  #0  0x08048634 in subr ()
  #1  0x400b2306 in __libc_start_main (main=0x8048618 <main>, argc=1, ubp_av=0xbfffe674, init=0x8048474 <_init>, fini=0x80486f8 <_fini>, rtld_fini=0x4000d2dc <_dl_fini>,
      stack_end=0xbfffe66c) at ../sysdeps/generic/libc-start.c:129
  (gdb) quit
  The program is running.  Exit anyway? (y or n) y
  $

It might be a little easier to understand how the line table describes
the entire range of PC's from it's lowest to highest if we match up
the new line table entries with a disassembly produced by gdb.  Note
in the following that now gdb knows which parts actually come from
p1.cpp (a range starting with a nonzero line number) and which parts
have no valid line info (a range starting with a zero line number):


 line 12 at 0x8048610	0x8048610 <main__9MainClass>:   push   %ebp
			0x8048611 <main__9MainClass+1>: mov    %esp,%ebp
			0x8048613 <main__9MainClass+3>: mov    0x8(%ebp),%eax
 line 13 at 0x8048616	0x8048616 <main__9MainClass+6>: pop    %ebp
			0x8048617 <main__9MainClass+7>: ret
 line 0 at  0x8048618
 line 16 at 0x8048618	0x8048618 <main>:       push   %ebp
			0x8048619 <main+1>:     mov    %esp,%ebp
			0x804861b <main+3>:     sub    $0x8,%esp

 line 18 at 0x804861e	0x804861e <main+6>:     sub    $0xc,%esp
			0x8048621 <main+9>:     push   $0x5
			0x8048623 <main+11>:    call   0x8048634 <subr__Fi>
			0x8048628 <main+16>:    add    $0x10,%esp

 line 19 at 0x804862b	0x804862b <main+19>:    mov    $0x0,%eax
			0x8048630 <main+24>:    leave
			0x8048631 <main+25>:    ret

 line 0 at 0x8048632	0x8048632 <main+26>:    mov    %esi,%esi
			0x8048634 <subr__Fi>:   push   %ebp
			0x8048635 <subr__Fi+1>: mov    %esp,%ebp
			0x8048637 <subr__Fi+3>: sub    $0x8,%esp
			0x804863a <subr__Fi+6>: sub    $0x8,%esp
			0x804863d <subr__Fi+9>: pushl  0x8(%ebp)
			0x8048640 <subr__Fi+12>:        push   $0x804872b
			0x8048645 <subr__Fi+17>:        call   0x80484cc <printf>
			0x804864a <subr__Fi+22>:        add    $0x10,%esp
			0x804864d <subr__Fi+25>:        leave
			0x804864e <subr__Fi+26>:        ret
			0x804864f <subr__Fi+27>:        nop
			0x8048650 <__do_global_ctors_aux>:      push   %ebp
			0x8048651 <__do_global_ctors_aux+1>:    mov    %esp,%ebp
			0x8048653 <__do_global_ctors_aux+3>:    push   %ebx
			0x8048654 <__do_global_ctors_aux+4>:    sub    $0x4,%esp
			0x8048657 <__do_global_ctors_aux+7>:    mov    0x804978c,%eax
			0x804865c <__do_global_ctors_aux+12>:   mov    $0x804978c,%ebx
			0x8048661 <__do_global_ctors_aux+17>:   cmp    $0xffffffff,%eax
			0x8048664 <__do_global_ctors_aux+20>:   je     0x804867c <__do_global_ctors_aux+44>
			0x8048666 <__do_global_ctors_aux+22>:   lea    0x0(%esi),%esi
			0x8048669 <__do_global_ctors_aux+25>:   lea    0x0(%edi,1),%edi
			0x8048670 <__do_global_ctors_aux+32>:   sub    $0x4,%ebx
			0x8048673 <__do_global_ctors_aux+35>:   call   *%eax
			0x8048675 <__do_global_ctors_aux+37>:   mov    (%ebx),%eax
			0x8048677 <__do_global_ctors_aux+39>:   cmp    $0xffffffff,%eax
			0x804867a <__do_global_ctors_aux+42>:   jne    0x8048670 <__do_global_ctors_aux+32>
			0x804867c <__do_global_ctors_aux+44>:   pop    %eax
			0x804867d <__do_global_ctors_aux+45>:   pop    %ebx
			0x804867e <__do_global_ctors_aux+46>:   pop    %ebp
			0x804867f <__do_global_ctors_aux+47>:   ret
			0x8048680 <init_dummy>: push   %ebp
			0x8048681 <init_dummy+1>:       mov    %esp,%ebp
			0x8048683 <init_dummy+3>:       sub    $0x8,%esp
			0x8048686 <init_dummy+6>:       mov    %ebp,%esp
			0x8048688 <init_dummy+8>:       pop    %ebp
			0x8048689 <init_dummy+9>:       ret
			0x804868a <init_dummy+10>:      lea    0x0(%esi),%esi

 line 9 at 0x8048690	0x8048690 <__tf9MainClass>:     push   %ebp
			0x8048691 <__tf9MainClass+1>:   mov    %esp,%ebp
			0x8048693 <__tf9MainClass+3>:   sub    $0x8,%esp

 line 19 at 0x8048696	0x8048696 <__tf9MainClass+6>:   cmpl   $0x0,0x80498b8
			0x804869d <__tf9MainClass+13>:  jne    0x80486b4 <__tf9MainClass+36>
			0x804869f <__tf9MainClass+15>:  sub    $0x8,%esp
			0x80486a2 <__tf9MainClass+18>:  push   $0x8048720
			0x80486a7 <__tf9MainClass+23>:  push   $0x80498b8
			0x80486ac <__tf9MainClass+28>:  call   0x804849c <__rtti_user>
			0x80486b1 <__tf9MainClass+33>:  add    $0x10,%esp
			0x80486b4 <__tf9MainClass+36>:  mov    $0x80498b8,%eax
			0x80486b9 <__tf9MainClass+41>:  leave
			0x80486ba <__tf9MainClass+42>:  ret

 line 0 at 0x80486bb	0x80486bb <__tf9MainClass+43>:  nop

 line 6 at 0x80486bc	0x80486bc <__9MainClass>:       push   %ebp
			0x80486bd <__9MainClass+1>:     mov    %esp,%ebp
			0x80486bf <__9MainClass+3>:     mov    0x8(%ebp),%eax
			0x80486c2 <__9MainClass+6>:     movl   $0x8049748,(%eax)
			0x80486c8 <__9MainClass+12>:    pop    %ebp
			0x80486c9 <__9MainClass+13>:    ret

 line 0 at 0x80486ca	0x80486ca <__9MainClass+14>:    mov    %esi,%esi

 line 7 at 0x80486cc	0x80486cc <_._9MainClass>:      push   %ebp
			0x80486cd <_._9MainClass+1>:    mov    %esp,%ebp
			0x80486cf <_._9MainClass+3>:    sub    $0x8,%esp
			0x80486d2 <_._9MainClass+6>:    mov    0xc(%ebp),%eax
			0x80486d5 <_._9MainClass+9>:    mov    0x8(%ebp),%edx
			0x80486d8 <_._9MainClass+12>:   movl   $0x8049748,(%edx)
			0x80486de <_._9MainClass+18>:   and    $0x1,%eax
			0x80486e1 <_._9MainClass+21>:   test   %al,%al
			0x80486e3 <_._9MainClass+23>:   je     0x80486f3 <_._9MainClass+39>
			0x80486e5 <_._9MainClass+25>:   sub    $0xc,%esp
			0x80486e8 <_._9MainClass+28>:   pushl  0x8(%ebp)
			0x80486eb <_._9MainClass+31>:   call   0x80484ec <__builtin_delete>
			0x80486f0 <_._9MainClass+36>:   add    $0x10,%esp
			0x80486f3 <_._9MainClass+39>:   leave
			0x80486f4 <_._9MainClass+40>:   ret

 line 0 at 0x80486f5	0x80486f5 <_._9MainClass+41>:   lea    0x0(%esi),%esi

The patch to make this work for stabs is very simple and supplied
below for discussion purposes.  I presume it would be fairly easy to
also change the other debug info readers to do the same thing.
Obviously someday we would like to have gdb take full advantage of
more expressive formats like DWARF, but for now this patch seems to
have substantial advantages.

I did run before and after testing with the gdb testsuite and it
didn't show any regressions, or improvements for that matter, but that
is to be expected since we don't actually test for functionality with
mixed levels of debugging information.

-Fred

Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.2184
diff -c -p -r1.2184 ChangeLog
*** ChangeLog	2002/02/12 00:59:27	1.2184
--- ChangeLog	2002/02/13 00:22:47
***************
*** 1,3 ****
--- 1,14 ----
+ 2002-02-11  Fred Fish  <fnf@redhat.com>
+ 
+ 	* dbxread.c (process_one_symbol): When finding an N_FUN symbol
+ 	that marks the end of the range of a function, enter a line number
+ 	entry that has a line number of zero and a PC offset that matches
+ 	the end of the function.  This starts a range of PC's for which no
+ 	line number information is known.
+ 	* symtab.c (find_pc_sect_line): If our best fit is in a range of
+ 	PC's for which no line number info is found (line number is zero)
+ 	then we didn't find any valid line information.
+ 
  2002-02-11  Richard Earnshaw  <rearnsha@arm.com>
  
  	* arm-linux-nat.c: Really include arm-tdep.h.
Index: dbxread.c
===================================================================
RCS file: /cvs/src/src/gdb/dbxread.c,v
retrieving revision 1.29
diff -c -p -r1.29 dbxread.c
*** dbxread.c	2002/02/04 11:55:34	1.29
--- dbxread.c	2002/02/13 00:22:50
*************** process_one_symbol (int type, int desc, 
*** 2741,2746 ****
--- 2741,2747 ----
  	{
  	  /* This N_FUN marks the end of a function.  This closes off the
  	     current block.  */
+ 	  record_line (current_subfile, 0, function_start_offset + valu);
  	  within_function = 0;
  	  new = pop_context ();
  
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.54
diff -c -p -r1.54 symtab.c
*** symtab.c	2002/02/11 03:21:53	1.54
--- symtab.c	2002/02/13 00:22:54
*************** find_pc_sect_line (CORE_ADDR pc, struct 
*** 1823,1828 ****
--- 1823,1835 ----
  	  val.end = alt->pc;
  	}
      }
+   else if (best->line == 0)
+     {
+       /* If our best fit is in a range of PC's for which no line
+ 	 number info is available (line number is zero) then we didn't
+ 	 find any valid line information. */
+       val.pc = pc;
+     }
    else
      {
        val.symtab = best_symtab;


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