From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31378 invoked by alias); 13 Feb 2002 00:28:51 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 31279 invoked from network); 13 Feb 2002 00:28:49 -0000 Received: from unknown (HELO fred.ninemoons.com) (68.15.182.197) by sources.redhat.com with SMTP; 13 Feb 2002 00:28:49 -0000 Received: (from fnf@localhost) by fred.ninemoons.com (8.11.6/8.11.6) id g1D0StM11730; Tue, 12 Feb 2002 17:28:55 -0700 From: Fred Fish Message-Id: <200202130028.g1D0StM11730@fred.ninemoons.com> Subject: [RFC] Gdb line table implementation tweak To: gdb-patches@sources.redhat.com Date: Tue, 12 Feb 2002 16:28:00 -0000 Cc: fnf@redhat.com Reply-To: fnf@redhat.com X-Mailer: ELM [version 2.5 PL6] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-02/txt/msg00343.txt.bz2 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 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 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 : 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
, 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 : 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
, 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 : push %ebp 0x8048611 : mov %esp,%ebp 0x8048613 : mov 0x8(%ebp),%eax line 13 at 0x8048616 0x8048616 : pop %ebp 0x8048617 : ret line 0 at 0x8048618 line 16 at 0x8048618 0x8048618
: push %ebp 0x8048619 : mov %esp,%ebp 0x804861b : sub $0x8,%esp line 18 at 0x804861e 0x804861e : sub $0xc,%esp 0x8048621 : push $0x5 0x8048623 : call 0x8048634 0x8048628 : add $0x10,%esp line 19 at 0x804862b 0x804862b : mov $0x0,%eax 0x8048630 : leave 0x8048631 : ret line 0 at 0x8048632 0x8048632 : mov %esi,%esi 0x8048634 : push %ebp 0x8048635 : mov %esp,%ebp 0x8048637 : sub $0x8,%esp 0x804863a : sub $0x8,%esp 0x804863d : pushl 0x8(%ebp) 0x8048640 : push $0x804872b 0x8048645 : call 0x80484cc 0x804864a : add $0x10,%esp 0x804864d : leave 0x804864e : ret 0x804864f : 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 : push %ebp 0x8048681 : mov %esp,%ebp 0x8048683 : sub $0x8,%esp 0x8048686 : mov %ebp,%esp 0x8048688 : pop %ebp 0x8048689 : ret 0x804868a : 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 + + * 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 * 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;