From: Kevin Buettner <kevinb@redhat.com>
To: gdb-patches@sourceware.org
Subject: Re: [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement
Date: Mon, 18 Jan 2016 16:48:00 -0000 [thread overview]
Message-ID: <20160118094800.7b41b549@pinnacle.lan> (raw)
In-Reply-To: <20150818235334.1afb0c85@pinnacle.lan>
Ping.
On Tue, 18 Aug 2015 23:53:34 -0700
Kevin Buettner <kevinb@redhat.com> wrote:
> 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.
next prev parent reply other threads:[~2016-01-18 16:48 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
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
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 ` Kevin Buettner [this message]
2016-04-04 15:56 ` [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160118094800.7b41b549@pinnacle.lan \
--to=kevinb@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).