[1/8] Add new test, gdb.base/loop-break.exp

Message ID 20150818235756.23c9d7db@pinnacle.lan
State New, archived
Headers

Commit Message

Kevin Buettner Aug. 19, 2015, 6:57 a.m. UTC
  This test places breakpoints at various points on several different
looping constructs, making sure that GDB behaves as expected.

gdb/testsuite/ChangeLog:

    	* gdb.base/loop-break.c, gdb.base/loop-break.exp: New files.
---
 gdb/testsuite/gdb.base/loop-break.c   |  42 +++++++++++++
 gdb/testsuite/gdb.base/loop-break.exp | 113 ++++++++++++++++++++++++++++++++++
 2 files changed, 155 insertions(+)
  

Comments

Pedro Alves Aug. 25, 2015, 12:10 p.m. UTC | #1
On 08/19/2015 07:57 AM, Kevin Buettner wrote:

> index 0000000..3e4b5ca
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/loop-break.c
> @@ -0,0 +1,42 @@
> +volatile int v;
> +volatile int w;

Copyright header missing.

> +  v = 0;
> +  goto b;				/* Loop 4 initial goto */
> +a:  v++;
> +b:  if (v < 3) goto a;			/* Loop 4 condition */
> +}
> +
> +int main (int argc, char **argv)

Line break after first int.

> +{
> +  loop_test ();
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/loop-break.exp b/gdb/testsuite/gdb.base/loop-break.exp
> new file mode 100644
> index 0000000..fef3fcb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/loop-break.exp
> @@ -0,0 +1,113 @@
> +# Copyright 2015 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Place breakpoints at various points on several different looping
> +# constructs.  Make sure that GDB correctly runs to each of these
> +# breakpoints and that computed values are correct at each point along
> +# the way.
> +
> +standard_testfile
> +
> +if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} {
> +    return -1
> +}
> +
> +if ![runto_main] then { fail "loop-break tests suppressed" }

This should return rather than continue into a cascade of failures:

if ![runto_main] then {
    fail "Can't run to main"
    return 0
}

> +
> +proc break_at { search_string } {
> +	global srcfile
> +	set bp_location [gdb_get_line_number $search_string]
> +	gdb_test "break $bp_location" \
> +	    "Breakpoint.*at.* file .*$srcfile, line $bp_location\\." \
> +	    "break $search_string"
> +
> +	return $bp_location;
> +}
> +
> +proc continue_to { linenum testname iter } {
> +    global srcfile
> +    global gdb_prompt
> +    set full_name "continue to $testname, $iter"
> +
> +    send_gdb "continue\n"
> +    gdb_expect {
> +	-re "Continuing.*Breakpoint.*$srcfile:$linenum\r\n.*\r\n$gdb_prompt $" {
> +	    pass $full_name
> +	}
> +	-re ".*$gdb_prompt $" {
> +	    fail $full_name
> +	}
> +	timeout { 
> +	    fail "$full_name (timeout)"
> +	}

Use gdb_test_multiple.  Or even, gdb_test ?

Thanks,
Pedro Alves
  
Kevin Buettner Sept. 22, 2015, 12:11 a.m. UTC | #2
The test case for loop-break.exp contains some code which performs
looping via gotos:

    volatile int v;
    ...
48        v = 0;
49        goto b;                               /* Loop 4 initial goto */
50      a:  v++;
51      b:  if (v < 3) goto a;                  /* Loop 4 condition */

While testing on arm and powerpc, I'm seeing this failure:

FAIL: gdb.base/loop-break.exp: continue to Loop 4 condition, 3 (the program exited)

The test places a breakpoint on lines 49 and 51. We expect the breakpoint
at line 49 to be hit once and the breakpoint at line 51 to be hit four
times, with v assuming the values 0, 1, 2, and 3 at successive stops
at this breakpoint.

For both arm and powerpc, the breakpoint on line 51 is being hit only
three times; the breakpoint is not being hit when v = 3.

In order to figure out what's going on, I placed breakpoints on lines
48, 49, 50, and 51.  Here's the assembly code for arm with annotations
showing the location of each breakpoint.  I've adjusted GDB's output
somewhat to better fit in 80 columns (without wrapping) along with
providing a more informative comment regarding v.

0x833c <loop_test+228>:   ldr r3, [pc, #64]   ; v		# line 48 bkpt
0x8340 <loop_test+232>:   mov     r2, #0
0x8344 <loop_test+236>:   str     r2, [r3]
0x8348 <loop_test+240>:   b       0x8364 <loop_test+268>	# line 49 bkpt
0x834c <loop_test+244>:   nop					# line 51 bkpt
0x8350 <loop_test+248>:   ldr r3, [pc, #44]   ; v		# line 50 bkpt
0x8354 <loop_test+252>:   ldr     r3, [r3]
0x8358 <loop_test+256>:   add     r3, r3, #1
0x835c <loop_test+260>:   ldr r2, [pc, #32]   ; v
0x8360 <loop_test+264>:   str     r3, [r2]
0x8364 <loop_test+268>:   ldr r3, [pc, #24]   ; v		# Loop 4 Cond
0x8368 <loop_test+272>:   ldr     r3, [r3]
0x836c <loop_test+276>:   cmp     r3, #2
0x8370 <loop_test+280>:   ble     0x834c <loop_test+244>
0x8374 <loop_test+284>:   nop

The locations for breakpoints for line 48, 49, and 50 are not surprising;
these are exactly where I would expect them to be.

The breakpoint for line 51 is placed on the nop instruction
immediately following the branch.  This nop is the branch destination
for the conditional branch at the bottom of the loop.  As such, the
breakpoint at line 51 will only be hit after evaluation of the condition,
but immediately before the increment on line 50.

The correct location for a breakpoint on line 51 is 0x8364, which I've
annotated with "Loop 4 Cond".

I've performed an analysis for powerpc too; the code being generated
is the same (modulo the differences in instruction sets) as that of
arm.

The .debug_line section contains these statements for this section of
code:

[0x0000016c]  Special opcode 68: advance Address by 8 to 0x833c and Line by 7 to 48
[0x0000016d]  Special opcode 90: advance Address by 12 to 0x8348 and Line by 1 to 49
[0x0000016e]  Special opcode 35: advance Address by 4 to 0x834c and Line by 2 to 51
[0x0000016f]  Special opcode 32: advance Address by 4 to 0x8350 and Line by -1 to 50
[0x00000170]  Special opcode 146: advance Address by 20 to 0x8364 and Line by 1 to 51

It's not clear to me why the nop is considered to be part of line 51. 
This might make (some) sense if either architecture had branch delay
slots, but to the best of my knowledge they do not.

In any case, things would work correctly if the statement at
0x0000016e were removed.

Kevin
  

Patch

diff --git a/gdb/testsuite/gdb.base/loop-break.c b/gdb/testsuite/gdb.base/loop-break.c
new file mode 100644
index 0000000..3e4b5ca
--- /dev/null
+++ b/gdb/testsuite/gdb.base/loop-break.c
@@ -0,0 +1,42 @@ 
+volatile int v;
+volatile int w;
+
+void
+loop_test (void)
+{
+  v = 0;
+
+  while (v < 3)				/* Loop 1 condition */
+    {
+      v++;				/* Loop 1 increment */
+    }
+
+  v = -42;
+
+  for (v = 0; v < 3; )			/* Loop 2 */
+    {
+      v++;				/* Loop 2 increment */
+    }
+
+  v = -42;
+  w = 42;
+
+  for (v = 0;				/* Loop 3 initialization */
+       v < 3;				/* Loop 3 condition */
+       v++)				/* Loop 3 increment */
+     {
+      w = w - v;	
+     }
+
+  v = 0;
+  goto b;				/* Loop 4 initial goto */
+a:  v++;
+b:  if (v < 3) goto a;			/* Loop 4 condition */
+}
+
+int main (int argc, char **argv)
+{
+  loop_test ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/loop-break.exp b/gdb/testsuite/gdb.base/loop-break.exp
new file mode 100644
index 0000000..fef3fcb
--- /dev/null
+++ b/gdb/testsuite/gdb.base/loop-break.exp
@@ -0,0 +1,113 @@ 
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Place breakpoints at various points on several different looping
+# constructs.  Make sure that GDB correctly runs to each of these
+# breakpoints and that computed values are correct at each point along
+# the way.
+
+standard_testfile
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} {
+    return -1
+}
+
+if ![runto_main] then { fail "loop-break tests suppressed" }
+
+proc break_at { search_string } {
+	global srcfile
+	set bp_location [gdb_get_line_number $search_string]
+	gdb_test "break $bp_location" \
+	    "Breakpoint.*at.* file .*$srcfile, line $bp_location\\." \
+	    "break $search_string"
+
+	return $bp_location;
+}
+
+proc continue_to { linenum testname iter } {
+    global srcfile
+    global gdb_prompt
+    set full_name "continue to $testname, $iter"
+
+    send_gdb "continue\n"
+    gdb_expect {
+	-re "Continuing.*Breakpoint.*$srcfile:$linenum\r\n.*\r\n$gdb_prompt $" {
+	    pass $full_name
+	}
+	-re ".*$gdb_prompt $" {
+	    fail $full_name
+	}
+	timeout { 
+	    fail "$full_name (timeout)"
+	}
+    }
+}
+
+set bp_location1a [break_at "Loop 1 condition"]
+set bp_location1b [break_at "Loop 1 increment"]
+set bp_location2a [break_at "Loop 2"]
+set bp_location2b [break_at "Loop 2 increment"]
+set bp_location3a [break_at "Loop 3 initialization"]
+set bp_location3b [break_at "Loop 3 condition"]
+set bp_location3c [break_at "Loop 3 increment"]
+set bp_location4a [break_at "Loop 4 initial goto"]
+set bp_location4b [break_at "Loop 4 condition"]
+
+continue_to $bp_location1a "Loop 1 condition" 0
+gdb_test "p v" "= 0" "Loop 1 value check at condition 0"
+continue_to $bp_location1b "Loop 1 increment" 0
+gdb_test "p v" "= 0" "Loop 1 value check at increment 0"
+
+continue_to $bp_location1a "Loop 1 condition" 1
+gdb_test "p v" "= 1" "Loop 1 value check at condition 1"
+continue_to $bp_location1b "Loop 1 increment" 1
+gdb_test "p v" "= 1" "Loop 1 value check at increment 1"
+
+continue_to $bp_location1a "Loop 1 condition" 2
+continue_to $bp_location1b "Loop 1 increment" 2
+
+continue_to $bp_location1a "Loop 1 condition" 3
+
+continue_to $bp_location2a "Loop 2" 0
+gdb_test "p v" "= -42" "Loop 2 value check at loop start"
+continue_to $bp_location2b "Loop 2 increment" 0
+gdb_test "p v" "= 0" "Loop 2 value check at increment 0"
+continue_to $bp_location2b "Loop 2 increment" 1
+gdb_test "p v" "= 1" "Loop 2 value check at increment 1"
+continue_to $bp_location2b "Loop 2 increment" 2
+gdb_test "p v" "= 2" "Loop 2 value check at increment 2"
+
+continue_to $bp_location3a "Loop 3 initialization" 0
+gdb_test "p v" "= -42" "Loop 3 value check at initialization"
+continue_to $bp_location3b "Loop 3 condition" 0
+gdb_test "p v" "= 0" "Loop 3 value check at condition 0"
+continue_to $bp_location3c "Loop 3 increment" 0
+gdb_test "p v" "= 0" "Loop 3 value check at increment 0"
+continue_to $bp_location3b "Loop 3 condition" 1
+continue_to $bp_location3c "Loop 3 increment" 1
+continue_to $bp_location3b "Loop 3 condition" 2
+continue_to $bp_location3c "Loop 3 increment" 2
+continue_to $bp_location3b "Loop 3 condition" 3
+
+continue_to $bp_location4a "Loop 4 initial goto" 0
+gdb_test "p v" "= 0" "Loop 4 value check at initial goto"
+continue_to $bp_location4b "Loop 4 condition" 0
+gdb_test "p v" "= 0" "Loop 4 value check at condition 0"
+continue_to $bp_location4b "Loop 4 condition" 1
+gdb_test "p v" "= 1" "Loop 4 value check at condition 1"
+continue_to $bp_location4b "Loop 4 condition" 2
+gdb_test "p v" "= 2" "Loop 4 value check at condition 2"
+continue_to $bp_location4b "Loop 4 condition" 3
+gdb_test "p v" "= 3" "Loop 4 value check at condition 3"