This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[PATCH RFA] symtab.c: Handle functions with multiple #line directives
- To: gdb-patches at sources dot redhat dot com
- Subject: [PATCH RFA] symtab.c: Handle functions with multiple #line directives
- From: Kevin Buettner <kevinb at cygnus dot com>
- Date: Tue, 13 Mar 2001 00:36:00 -0700
The patch (way) below fixes a bug in find_pc_sect_line() which is most
evident when debugging a function which switches between two (or more)
source files multiple times via #line directives in the source. In
order to trigger the bug, it is critical that there be at least two
such transitions in a given function.
Now for some background...
Perl's xsubpp script is used to transform a source (.xs) file
containing a mix of C code and other statements into pure C code. In
the resulting C source code, #line directives are used to indicate
where the original C code from the .xs file was. It is common for
there to be several transitions back and forth between
xsubpp-generated code and the code that appeared in the .xs file.
Here is a small snippet of code taken from the generated "perl.c" from
another project that I occasionally work on:
XS(XS_Vile__Window_window_count)
{
dXSARGS;
dXSI32;
if (items != 0)
Perl_croak(aTHX_ "Usage: %s()", GvNAME(CvGV(cv)));
{
#line 4370 "perl.xs"
int count;
WINDOW *wp;
#line 3616 "perl.c"
int RETVAL;
dXSTARG;
#line 4374 "perl.xs"
count = 0;
for_each_visible_window(wp)
count++;
RETVAL = count;
#line 3625 "perl.c"
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
Again, the thing to notice here is that the xsubpp tool intermixes code
that it has generated with code taken from the .xs file. It marks each
transition with a #line directive. When debugging this code, the
programmer should be able to step from one line to the next. However,
at the moment, GDB is not very accomodating:
Breakpoint 1, XS_Vile__Window_window_count (cv=0x82014f8) at perl.c:3606
3606 dXSARGS;
(gdb) n
3607 dXSI32;
(gdb) n
3608 if (items != 0)
(gdb) n
3617 dXSTARG;
(gdb) n
3625 XSprePUSH; PUSHi((IV)RETVAL);
(gdb) n
3627 XSRETURN(1);
Note that GDB simply skipped over all the following statements:
count = 0;
for_each_visible_window(wp)
count++;
RETVAL = count;
When we debug the same function with the above mentioned symtab.c
patch, we see the following (correct) behavior:
Breakpoint 1, XS_Vile__Window_window_count (cv=0x82014f8) at perl.c:3606
3606 dXSARGS;
(gdb) n
3607 dXSI32;
(gdb)
3608 if (items != 0)
(gdb)
3617 dXSTARG;
(gdb)
4374 count = 0;
(gdb)
4375 for_each_visible_window(wp)
(gdb)
4376 count++;
(gdb)
4375 for_each_visible_window(wp)
(gdb)
4376 count++;
(gdb)
4375 for_each_visible_window(wp)
(gdb)
4377 RETVAL = count;
(gdb)
3625 XSprePUSH; PUSHi((IV)RETVAL);
(gdb)
3627 XSRETURN(1);
I have constructed a new test which I am proposing be added to the
GDB testsuite to test for this bug. The proposal is at:
http://sources.redhat.com/ml/gdb-patches/2001-03/msg00185.html
This test causes 12 new FAILs when run against a current GDB and
no fails when patched with the patch below.
I have tested the patch below on i386-unknown-freebsd4.2 and
i686-pc-linux-gnu and see no regressions. Also, as shown above,
it certainly produces better results when debugging real code.
Okay to commit?
* symtab.c (find_pc_sect_line): Revise method used for finding
the ending pc.
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.32
diff -u -p -r1.32 symtab.c
--- symtab.c 2001/03/06 08:21:17 1.32
+++ symtab.c 2001/03/10 08:22:11
@@ -1759,11 +1759,18 @@ find_pc_sect_line (CORE_ADDR pc, struct
{
best = prev;
best_symtab = s;
- /* If another line is in the linetable, and its PC is closer
- than the best_end we currently have, take it as best_end. */
- if (i < len && (best_end == 0 || best_end > item->pc))
- best_end = item->pc;
+
+ /* Discard BEST_END if it's before the PC of the current BEST. */
+ if (best_end <= best->pc)
+ best_end = 0;
}
+
+ /* If another line (denoted by ITEM) is in the linetable and its
+ PC is after BEST's PC, but before the current BEST_END, then
+ use ITEM's PC as the new best_end. */
+ if (best && i < len && item->pc > best->pc
+ && (best_end == 0 || best_end > item->pc))
+ best_end = item->pc;
}
if (!best_symtab)