public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
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.

  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).