From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 60027 invoked by alias); 18 Jan 2016 16:48:09 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 59970 invoked by uid 89); 18 Jan 2016 16:48:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=lastly, 0v, distant, died X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 18 Jan 2016 16:48:04 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id 23688192445 for ; Mon, 18 Jan 2016 16:48:03 +0000 (UTC) Received: from pinnacle.lan (ovpn-113-155.phx2.redhat.com [10.3.113.155]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0IGm2iH029164 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA256 bits=256 verify=NO) for ; Mon, 18 Jan 2016 11:48:02 -0500 Date: Mon, 18 Jan 2016 16:48:00 -0000 From: Kevin Buettner To: gdb-patches@sourceware.org Subject: Re: [PATCH 0/8] Break at each iteration for breakpoints placed on a while statement Message-ID: <20160118094800.7b41b549@pinnacle.lan> In-Reply-To: <20150818235334.1afb0c85@pinnacle.lan> References: <20150818235334.1afb0c85@pinnacle.lan> MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-IsSubscribed: yes X-SW-Source: 2016-01/txt/msg00387.txt.bz2 Ping. On Tue, 18 Aug 2015 23:53:34 -0700 Kevin Buettner 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 : jmp 0x4005af > 0x00000000004005a0 : mov 0x200a8a(%rip),%eax # 0x601030 > 0x00000000004005a6 : add $0x1,%eax > 0x00000000004005a9 : mov %eax,0x200a81(%rip) # 0x601030 > 0x00000000004005af : mov 0x200a7b(%rip),%eax # 0x601030 > 0x00000000004005b5 : cmp $0x2,%eax > 0x00000000004005b8 : jle 0x4005a0 > > 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.