[PATCH 6/7] range stepping: test case

Yao Qi
2013-04-11T02:44:05Z

This test case is used to verify range stepping is used by means of
checking the internalvar '$range_stepping_counter'.

In V2, the test cases check the value of '$range_stepping_counter'
instead of parsing RSP packets.

gdb/testsuite:

2013-04-10 Yao Qi <yao@codesourcery.com>

* gdb.base/range-stepping.c: New.
* gdb.base/range-stepping.exp: New.
* gdb.trace/range-stepping.c: New.
* gdb.trace/range-stepping.exp: New.
---
gdb/testsuite/gdb.base/range-stepping.c | 69 +++++++++
gdb/testsuite/gdb.base/range-stepping.exp | 222 ++++++++++++++++++++++++++++
gdb/testsuite/gdb.trace/range-stepping.c | 61 ++++++++
gdb/testsuite/gdb.trace/range-stepping.exp | 89 +++++++++++
4 files changed, 441 insertions(+), 0 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/range-stepping.c
create mode 100644 gdb/testsuite/gdb.base/range-stepping.exp
create mode 100644 gdb/testsuite/gdb.trace/range-stepping.c
create mode 100644 gdb/testsuite/gdb.trace/range-stepping.exp

diff --git a/gdb/testsuite/gdb.base/range-stepping.c b/gdb/testsuite/gdb.base/range-stepping.c
new file mode 100644
index 0000000..930cb8d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/range-stepping.c
@@ -0,0 +1,69 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>. */
+
+static int
+func1 (int a, int b)
+{
+ int r = a * b;
+
+ r =+ (a | b);
+ r =+ (a - b);
+
+ return r;
+}
+
+int
+main(void)
+{
+ int a = 0;
+ int b = 1;
+ int c = 2;
+ int d = 3;
+ int e = 4;
+ double d1 = 1.0;
+ double d2 = 2.0;
+
+ /* A line of source will be generated to a number of
+ instructions by compiler. */
+ a = b + c + d * e - a; /* location 1 */
+
+ /* To compose multiple instructions before and after
+ 'function call' or 'branch' instruction. This line
+ of source will be generated to the following instructions,
+
+addr1:
+ insn1;
+ insn2;
+ ...
+ call func1;
+ ...
+ insn3;
+addr2:
+ insn4; */
+ e = 10 + func1 (a + b, c * d); /* location 2 */
+
+ e = 10 + func1 (a + b, c * d);
+ /* Generate a range that includes a loop in it. */
+ for (a = 0, e = 0; a < 15; a++) { e += a;}
+ /* Generate a range that includes a loop in it. */
+ for (a = 0, e = 0; a < 15; a++) { e += a;}
+ /* Generate a range that includes a loop, which is time consuming.
+ Variable C is used to terminate the loop earlier when GDB
+ wants. */
+ for (c = 1, a = 0; a < 65535 && c; a++) {for (b = 0; b < 65535 && c; b++) { d1 = d2 * a / b; d2 = d1 * a;}}
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/range-stepping.exp b/gdb/testsuite/gdb.base/range-stepping.exp
new file mode 100644
index 0000000..0f2a2dd
--- /dev/null
+++ b/gdb/testsuite/gdb.base/range-stepping.exp
@@ -0,0 +1,222 @@
+# Copyright 2013 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/>.
+
+standard_testfile .c
+set executable $testfile
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable {debug nowarnings}] != "" } {
+ untested ${testfile}.exp
+ return -1
+}
+
+clean_restart $executable
+
+if ![runto_main] {
+ fail "Can't run to main"
+ return -1
+}
+
+# Check range stepping is supported by target or not.
+set test "range-stepping is supported"
+gdb_test_multiple "maintenance show range-stepping" "show range-stepping" {
+ -re "Debugger's willingness to do range-stepping is off.*\r\n$gdb_prompt $" {
+ unsupported $test
+ return -1
+ }
+ -re "Debugger's willingness to do range-stepping is on.*\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Check range stepping can step a range of multiple instructions.
+
+with_test_prefix "multi insns" {
+ global executable
+ global hex decimal
+ global gdb_prompt
+
+ gdb_breakpoint [gdb_get_line_number "location 1"]
+ gdb_continue_to_breakpoint "location 1"
+
+ set pc_before_stepping ""
+ set test "pc before stepping"
+ gdb_test_multiple "print/x \$pc" $test {
+ -re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
+ set pc_before_stepping $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ # When execute command "next", GDB should send one vCont;s and
+ # vCont;r and receive two stop replies.
+ # --> vCont;s (step over breakpoint)
+ # <-- T0505:XXX
+ # --> vCont;rSTART,END (do range stepping)
+ # <-- T0505:XXX
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 1"
+
+ set pc_after_stepping ""
+ set msg "pc before stepping"
+ gdb_test_multiple "print/x \$pc" $msg {
+ -re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
+ set pc_after_stepping $expect_out(1,string)
+ pass $msg
+ }
+ }
+
+ # At least, there are two instructions between
+ # PC_BEFORE_STEPPING and PC_AFTER_STEPPING.
+ gdb_test "disassemble ${pc_before_stepping},${pc_after_stepping}" \
+ "${hex} <main\\+${decimal}>:.*${hex} <main\\+${decimal}>:.*" \
+ "stepped multiple insns"
+}
+
+# Check range stepping can step over a function.
+
+with_test_prefix "step over func" {
+ global srcfile
+
+ set line_num [gdb_get_line_number "location 2"]
+ gdb_test "where" "main \\(\\) at .*${srcfile}:${line_num}.*"
+
+ # It is expected to get three stops and two 'vCont;r'. In the C
+ # code, the line of C source produces the following instructions,
+ #
+ # addr1:
+ # insn1;
+ # insn2;
+ # ...
+ # call func1;
+ # addr2:
+ # ...
+ # insn3;
+ # addr3:
+ # insn4;
+ #
+ # Something like this will happen:
+ # --> vCont;rADDR1,ADDR3 (do range stepping from ADDR1 to ADDR3)
+ # <-- T0505:XXXX
+ # (inferior is single-stepping to func, which is out of the range)
+ # --> $Z0,ADDR2
+ # --> vCont;c (set step-resume breakpoint on ADDR2, and resume)
+ # <-- T0505:XXXX (inferior stops at ADD2)
+ # --> vCont;rADDR1,ADDR3 (continues to do range stepping)
+ # <-- T0505:XXXX
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 2"
+}
+
+# Check range stepping works well with breakpoint.
+
+with_test_prefix "breakpoint" {
+ gdb_breakpoint "func1"
+ # Something like this will happen:
+ # --> vCont;rADDR1,ADDR3
+ # <-- T0505:XXXX
+ # (inferior is single-stepping to func1, which is out of the range)
+ # --> $Z0,ADDR2
+ # --> vCont;c (set step-resume breakpoint on ADDR2, and resume)
+ # <-- T0505:XXXX (inferior hits the breakpoint on fun1)
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next" "." ""
+ gdb_test "p \$range_stepping_counter" " = 1" \
+ "range-stepping-counter is 1"
+
+ gdb_test "backtrace" "#0 .* func1 .*#1 .* main .*" \
+ "backtrace from func1"
+ # The range stepping was interrupted by a breakpoint, but the
+ # state related to range stepping should be cleared.
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "stepi"
+ gdb_test "p \$range_stepping_counter" " = 0" \
+ "range-stepping-counter is 0"
+ gdb_test "finish" ".*"
+
+ gdb_test "next" ".*"
+ delete_breakpoints
+}
+
+# Check range stepping works well with a loop in the range.
+
+with_test_prefix "loop" {
+
+ # GDB should send one vCont;r and receive one stop reply.
+ # --> vCont;rSTART,END (do range stepping)
+ # <-- T0505:XXX
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 1"
+
+ # Check loop is done.
+ gdb_test "print a" "\\$${decimal} = 15\[\r\n\].*"
+ gdb_test "print e" "\\$${decimal} = 105\[\r\n\].*"
+}
+
+# Check range stepping works well when PC has already within the loop
+# body.
+
+with_test_prefix "loop" {
+ # Stepi into the loop body. 15 is large enough to make sure
+ # program goes to loop body.
+ gdb_test "stepi 15" ".*"
+ # GDB should send one vCont;r and receive one stop reply.
+ # --> vCont;rSTART,END (do range stepping)
+ # <-- T0505:XXX
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 1"
+
+ # Check loop is done.
+ gdb_test "print a" "\\$${decimal} = 15\[\r\n\].*"
+ gdb_test "print e" "\\$${decimal} = 105\[\r\n\].*"
+}
+
+# Check range stepping works well when it is interrupted by ctrl-c.
+
+with_test_prefix "interrupt" {
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+
+ send_gdb "next\n"
+ sleep 1
+ send_gdb "\003"
+
+ # GDB should send one vCont;r and receive one stop reply about
+ # SIGINT.
+ # --> vCont;rSTART,END (do range stepping)
+ # <-- T0205:XXX
+
+ set test "send gdb ctrl-c"
+ gdb_expect {
+ -re "Program received signal SIGINT.*$gdb_prompt $" {
+ pass $test
+ }
+ timeout { fail "${test} (timeout)" }
+ eof { fail "${test} (eof)" }
+ }
+ gdb_test "p \$range_stepping_counter" " = 1" \
+ "range-stepping-counter is 1"
+
+ # Terminate the loop earlier and continue to do range stepping.
+ gdb_test "set variable c = 0"
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 2" \
+ "range-stepping-counter is 2"
+}
+
+return 0
diff --git a/gdb/testsuite/gdb.trace/range-stepping.c b/gdb/testsuite/gdb.trace/range-stepping.c
new file mode 100644
index 0000000..50db5a0
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/range-stepping.c
@@ -0,0 +1,61 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>. */
+
+#ifdef SYMBOL_PREFIX
+#define SYMBOL(str) SYMBOL_PREFIX #str
+#else
+#define SYMBOL(str) #str
+#endif
+
+/* Called from asm. */
+static void __attribute__((used))
+func2 (void)
+{}
+
+static int
+func1 (int a, int b)
+{
+ int r = a * b;
+
+ /* `set_point' is the label where we'll set tracepoint at. The insn
+ at the label must the large enough to fit a fast tracepoint
+ jump. */
+ asm (" .global " SYMBOL(set_point) "\n"
+ SYMBOL(set_point) ":\n"
+#if (defined __x86_64__ || defined __i386__)
+ " call " SYMBOL(func2) "\n"
+#endif
+ );
+
+ r =+ (a | b);
+ r =+ (a - b);
+
+ return r;
+}
+
+int
+main(void)
+{
+ int a = 0;
+ int b = 1;
+ int c = 2;
+ int d = 3;
+ int e = 4;
+
+ e = 10 + func1 (a + b, c * d); /* location 1 */
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/range-stepping.exp b/gdb/testsuite/gdb.trace/range-stepping.exp
new file mode 100644
index 0000000..22c705d
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/range-stepping.exp
@@ -0,0 +1,89 @@
+# Copyright 2013 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/>.
+
+load_lib "trace-support.exp"
+
+standard_testfile
+set executable $testfile
+set expfile $testfile.exp
+
+if [prepare_for_testing $expfile $executable $srcfile \
+ {debug nowarnings}] {
+ untested "failed to prepare for trace tests"
+ return -1
+}
+
+if ![runto_main] {
+ fail "Can't run to main to check for trace support"
+ return -1
+}
+
+if ![gdb_target_supports_trace] {
+ unsupported "target does not support trace"
+ return -1;
+}
+
+# Check range stepping works well with tracepoint.
+proc range_stepping_with_tracepoint { type } {
+ with_test_prefix "${type}" {
+
+ gdb_breakpoint [gdb_get_line_number "location 1"]
+ gdb_continue_to_breakpoint "location 1"
+ delete_breakpoints
+
+ gdb_test "${type} set_point" ".*"
+ gdb_test_no_output "tstart"
+
+ # GDB will step over function func1, in which a tracepoint is
+ # set. GDB will send two vCont;r packets because calling to
+ # func1 is out of the range. However, tracepoint itself
+ # shouldn't have any effect on range stepping.
+ gdb_test_no_output "set \$range_stepping_counter = 0" ""
+ gdb_test "next"
+ gdb_test "p \$range_stepping_counter" " = 2"
+ gdb_test_no_output "tstop"
+ gdb_test "tfind" "Found trace frame 0.*" "tfind 0"
+ gdb_test "tfind" \
+ "Target failed to find requested trace frame.*" \
+ "tfind 1"
+
+ delete_breakpoints
+ }
+}
+
+range_stepping_with_tracepoint "trace"
+
+set libipa [get_in_proc_agent]
+gdb_load_shlibs $libipa
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+ executable [list debug nowarnings shlib=$libipa] ] != "" } {
+ untested "failed to compile ftrace tests"
+ return -1
+}
+
+clean_restart ${executable}
+
+if ![runto_main] {
+ fail "Can't run to main for ftrace tests"
+ return 0
+}
+
+gdb_reinitialize_dir $srcdir/$subdir
+if { [gdb_test "info sharedlibrary" ".*${libipa}.*" "IPA loaded"] != 0 } {
+ untested "Could not find IPA lib loaded"
+} else {
+ range_stepping_with_tracepoint "ftrace"
+}
--
1.7.7.6