There are a couple of failures in the gdb test suite on i386 and
x86_64 with gcc 4.3.0 or newer. The tests gdb.base/break.exp and
gdb.base/sepdebug.exp are failing with a function begins with a while
loop. The into_cfg_layout_mode pass was added in 4.3.0 (see
http://gcc.gnu.org/ml/gcc-patches/2007-03/msg00687.html), and that
pass removes the instruction that jumps from the end of the first
basic block to the bottom of the while loop. The outof_cfg_layout_mode
pass reintroduces the branch (in force_nonfallthru_and_redirect) once
the basic blocks have been laid out, but the source location
information has been lost by that point.

When you try to set a breakpoint at the beginning of the function, gdb
looks for the second row in the line table (it skips the first to get
past the prologue), and sets the breakpoint there. Because of the
missing locator on the jump, the second row is now the interior of the
while loop, and the breakpoint is in the wrong place.

Here's a reduced test case:

void foo(int a)
{
   while (a) { // line 3
     a--;      // line 4
   }
}

If you compile this (for x86_64) with a top-of-trunk gcc with -S -g,
you can see that the jmp to .L2 has no .loc directive in front of it,
and the first .loc directive is now the one for the body of the while
loop:

        .file 1 "foo.cc"
        .loc 1 1 0
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    %edi, -4(%rbp)
        jmp     .L2
.L3:
        .loc 1 4 0
        subl    $1, -4(%rbp)
.L2:
        .loc 1 3 0
        cmpl    $0, -4(%rbp)
        jne     .L3
        .loc 1 6 0
        leave
        ret

For comparison, here's the output from gcc 4.2.1:

        .file 1 "foo.cc"
        .loc 1 1 0
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    %edi, -4(%rbp)
        .loc 1 3 0
        jmp     .L2
.L3:
        .loc 1 4 0
        subl    $1, -4(%rbp)
.L2:
        .loc 1 3 0
        cmpl    $0, -4(%rbp)
        jne     .L3
        .loc 1 6 0
        leave
        ret

I've tried changing force_nonfallthru_and_redirect (in cfgrtl.c) to
use to e->goto_locus field as the location for the reintroduced jump,
but that seems to mark the jump with line #6 (goto_locus might not
even be valid yet at this point, I'm told, and I'm not even sure that
a locus can be used where an INSN_LOCATOR is expected -- the
location_from_locus macro was removed). I've also tried looking
through the target bb's instruction list to find the first instruction
with an INSN_LOCATOR and using that for the locator of the jump -- it
fixed this problem, but broke other tests because now a forward branch
in other contexts (if-then-else, for example) gets the line number of
its target, and gdb will now use that branch as the breakpoint
location for that line number.

I'd argue that gcc really ought to be flagging the end of the prologue
-- there's a debug hook for that, and it's used by most of the debug
formats, but not by DWARF. The DWARF spec was extended (in version 3)
to allow the line number table to indicate the end of prologue, so gcc
(and gas) ought to be updated to record it in the line table, and gdb
ought to be taught to use that in lieu of looking for the second row
in the line table. Until all that happens, though, I think a quicker
fix is necessary.

Any suggestions?

-cary

Reply via email to