public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement
@ 2015-08-19  6:53 Kevin Buettner
  2015-08-19  6:58 ` [PATCH 1/8] Add new test, gdb.base/loop-break.exp Kevin Buettner
                   ` (9 more replies)
  0 siblings, 10 replies; 36+ messages in thread
From: Kevin Buettner @ 2015-08-19  6:53 UTC (permalink / raw)
  To: gdb-patches

This patch set changes the current behavior of breakpoints placed on
while loops. (It actually restores past behavior; see below.)

Consider the following code:

7         v = 0;
8
9         while (v < 3)                         /* Loop 1 condition */
10          {
11            v++;                              /* Loop 1 increment */
12          }

This example is taken from the new test case, loop-break.c.

Let's place breakpoints at lines 9 and 11:

(gdb) b 9
Breakpoint 1 at 0x4005af: file gdb.base/loop-break.c, line 9.
(gdb) b 11
Breakpoint 2 at 0x4005a0: file gdb.base/loop-break.c, line 11.

We'll run the program and then continue to get to breakpoint #2:

(gdb) run
Starting program: gdb.base/loop-break

Breakpoint 1, loop_test ()
    at gdb.base/loop-break.c:9
9         while (v < 3)                         /* Loop 1 condition */
(gdb) c
Continuing.

Breakpoint 2, loop_test ()
    at gdb.base/loop-break.c:11
11            v++;                              /* Loop 1 increment */

So far, so good.  Now, watch what happens when we continue again:

(gdb) c
Continuing.

Breakpoint 2, loop_test ()
    at /ironwood1/sourceware-git/mesquite-native-5509943/bld/../../binutils-gdb/gdb/testsuite/gdb.base/loop-break.c:11
11            v++;                              /* Loop 1 increment */

GDB has somehow missed the breakpoint placed on line 9.  The user is
unable to examine state prior to evaluation of the loop condition.

The compiler is implementing this looping construct in the following
fashion.  An unconditional branch is placed at the start of the loop,
branching to an address immediately after the loop body.  At that point,
the condition is evaluated.  If the condition evaluates as true, a
conditional branch causes execution to continue at the first instruction
of the loop body, placed immediately after the unconditional branch.

GDB is placing its breakpoint on the unconditional branch. This is fine
for the first iteration of the loop, but does not work for subsequent
iterations.

This is the code that gcc generates on x86_64:

0x000000000040059e <loop_test+14>:   jmp    0x4005af <loop_test+31>
0x00000000004005a0 <loop_test+16>:   mov    0x200a8a(%rip),%eax # 0x601030 <v>
0x00000000004005a6 <loop_test+22>:   add    $0x1,%eax
0x00000000004005a9 <loop_test+25>:   mov    %eax,0x200a81(%rip) # 0x601030 <v>
0x00000000004005af <loop_test+31>:   mov    0x200a7b(%rip),%eax # 0x601030 <v>
0x00000000004005b5 <loop_test+37>:   cmp    $0x2,%eax
0x00000000004005b8 <loop_test+40>:   jle    0x4005a0 <loop_test+16>

The breakpoint is being placed on 0x40059e (loop_test+14).  As such, it
gets hit only once.  If we could arrange to have the breakpoint placed at
the branch target, it would stop at each iteration of the loop. I.e.
it would behave like this:

(gdb) b 9
Breakpoint 1 at 0x4005af: file gdb.base/loop-break.c, line 9.
(gdb) b 11
Breakpoint 2 at 0x4005a0: file gdb.base/loop-break.c, line 11.
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>p v
>end
(gdb) run
Starting program: gdb.base/loop-break

Breakpoint 1, loop_test ()
    at gdb.base/loop-break.c:9
9         while (v < 3)                         /* Loop 1 condition */
$1 = 0
(gdb) c
Continuing.

Breakpoint 2, loop_test ()
    at gdb.base/loop-break.c:11
11            v++;                              /* Loop 1 increment */
(gdb) c
Continuing.

Breakpoint 1, loop_test ()
    at gdb.base/loop-break.c:9
9         while (v < 3)                         /* Loop 1 condition */
$2 = 1

This change introduces a new gdbarch method for potentially following
an unconditional branch.  If the circumstances are right, it uses
this method to cause the breakpoint to be placed on the branch target
instead of the branch itself.

This fixes the problem described above and causes no regressions.
The new test case includes the loop shown above.  It also contains
several other loops which verify that GDB stops at the the correct
places in each.  Only while loops of the form shown above are
affected by this patch; other looping constructs continue to work
as they had before.

Of particular interest is the test which uses an explicit goto; this
mimics the code that the compiler generates for a while loop.
However, in this example, placing a breakpoint on the goto should
cause execution to stop on the goto.  My initial attempt at a fix
for this problem caused that explicit goto to be followed, which is
definitely not correct.

Lastly, I'll note that, in the distant past, GCC used to output code
for the condition at the top of the loop.  GDB from either then or now
will stop at the evaluation of the condition each time through the
loop.

I was able to locate a compiler that I could run from circa 1998. While
I was able to run the compiler, I was not able to run the linker; it
died with an internal error in collect2, undoubtedly due to not having
compatible libraries.  But I was able to use -S in order to see
what the assembly code looked like.  Here is the assembly code for
our example loop, compiled by gcc 2.9, targeting i386-pc-linux-gnu:

	    movl $0,v
    .stabn 68,0,9,.LM3-loop_test
    .LM3:
	    .align 4
    .L2:
	    movl v,%eax
	    cmpl $2,%eax
	    jle .L4
	    jmp .L3
	    .align 4
    .L4:
    .stabn 68,0,11,.LM4-loop_test
    .LM4:
	    movl v,%eax
	    leal 1(%eax),%edx
	    movl %edx,v
    .stabn 68,0,12,.LM5-loop_test
    .LM5:
	    jmp .L2
    .L3:

The loop begins with the evaluation of the condition at .L2.  The jle
branches to instructions forming the body of the loop; the jmp instruction
immediately following the jle gets us out of the loop.

This code isn't very efficient, but it is a straightforward translation
of the corresponding C code.  A breakpoint placed at the beginning of
line 9 (which is both .LM3 and .L2) will stop on each iteration through
the loop.

My patch-set restores this behavior for while loops implemented in
a more efficient manner.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2016-04-19 16:24 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-19  6:53 [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement Kevin Buettner
2015-08-19  6:58 ` [PATCH 1/8] Add new test, gdb.base/loop-break.exp Kevin Buettner
2015-08-25 12:10   ` Pedro Alves
2015-09-18  0:50     ` Kevin Buettner
2016-02-01 20:00       ` Kevin Buettner
2016-02-15 16:51         ` Kevin Buettner
2016-02-29 16:17         ` Kevin Buettner
2015-09-22  0:11   ` Kevin Buettner
2015-08-19  7:00 ` [PATCH 2/8] Add new gdbarch method, unconditional_branch_address Kevin Buettner
2015-08-25 12:13   ` Pedro Alves
2015-09-18  1:14     ` Kevin Buettner
2015-09-18 12:02   ` Andrew Burgess
2015-09-18 12:06     ` Andrew Burgess
2015-09-18 12:26       ` Kevin Buettner
2015-09-18 12:24     ` Kevin Buettner
2015-09-22 16:09   ` Yao Qi
2015-09-22 18:03     ` Kevin Buettner
2015-08-19  7:03 ` [PATCH 3/8] Break at each iteration for breakpoints placed on a while statement Kevin Buettner
2015-08-25 12:10   ` Pedro Alves
2015-09-18  1:57     ` Kevin Buettner
2015-09-30 12:17       ` Pedro Alves
2015-10-01  1:13         ` Kevin Buettner
2015-10-01  4:09         ` Doug Evans
2015-08-19  7:06 ` [PATCH 4/8] Implement unconditional_branch_address method for x86-64 and i386 Kevin Buettner
2015-09-18  2:03   ` Kevin Buettner
2015-08-19  7:08 ` [PATCH 5/8] Implement unconditional_branch_address method for arm and thumb Kevin Buettner
2015-08-19  7:11 ` [PATCH 6/8] Implement unconditional_branch_address method for powerpc / rs6000 Kevin Buettner
2015-08-19  7:13 ` [PATCH 7/8] Implement unconditional_branch_address method for rl78 Kevin Buettner
2015-08-19  7:15 ` [PATCH 8/8] Implement unconditional_branch_address method for rx Kevin Buettner
2016-01-18 16:48 ` [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement Kevin Buettner
2016-04-04 15:56 ` Yao Qi
2016-04-14 16:31   ` Luis Machado
2016-04-15 11:59     ` Yao Qi
2016-04-15 19:48       ` Kevin Buettner
2016-04-15 22:34         ` Pedro Alves
2016-04-19 16:24           ` Kevin Buettner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).