range stepping: tests
This adds tests to verify range stepping is used as expected, by inspecting the RSP traffic, looking for vCont;s and vCont;r packets. gdb/testsuite/ 2013-05-23 Yao Qi <yao@codesourcery.com> Pedro Alves <palves@redhat.com> * gdb.base/range-stepping.c: New file. * gdb.base/range-stepping.exp: New file. * gdb.trace/range-stepping.c: New file. * gdb.trace/range-stepping.exp: New file. * lib/range-stepping-support.exp: New file.
This commit is contained in:
parent
c2d6af84da
commit
bc5065a70f
@ -1,3 +1,12 @@
|
||||
2013-05-23 Yao Qi <yao@codesourcery.com>
|
||||
Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.base/range-stepping.c: New file.
|
||||
* gdb.base/range-stepping.exp: New file.
|
||||
* gdb.trace/range-stepping.c: New file.
|
||||
* gdb.trace/range-stepping.exp: New file.
|
||||
* lib/range-stepping-support.exp: New file.
|
||||
|
||||
2013-05-22 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.cp/class2.cc (main): New local 'aref'.
|
||||
|
104
gdb/testsuite/gdb.base/range-stepping.c
Normal file
104
gdb/testsuite/gdb.base/range-stepping.c
Normal file
@ -0,0 +1,104 @@
|
||||
/* 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/>. */
|
||||
|
||||
/* Note: 'volatile' is used to make sure the compiler doesn't fold /
|
||||
optimize out the arithmetic that uses the variables. */
|
||||
|
||||
static int
|
||||
func1 (int a, int b)
|
||||
{
|
||||
volatile int r = a * b;
|
||||
|
||||
r += (a | b);
|
||||
r += (a - b);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
volatile int a = 0;
|
||||
volatile int b = 1;
|
||||
volatile int c = 2;
|
||||
volatile int d = 3;
|
||||
volatile int e = 4;
|
||||
volatile double d1 = 1.0;
|
||||
volatile double d2 = 2.0;
|
||||
|
||||
/* A macro that expands to a single source line that compiles to a
|
||||
number of instructions, with no branches. */
|
||||
#define LINE_WITH_MULTIPLE_INSTRUCTIONS \
|
||||
do \
|
||||
{ \
|
||||
a = b + c + d * e - a; \
|
||||
} while (0)
|
||||
|
||||
LINE_WITH_MULTIPLE_INSTRUCTIONS; /* location 1 */
|
||||
|
||||
/* A line of source code that compiles to a function call (jump or
|
||||
branch), surrounded by instructions before and after. IOW, this
|
||||
will generate approximately the following pseudo-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 single source line that includes a short loop. */
|
||||
#define LINE_WITH_LOOP \
|
||||
do \
|
||||
{ \
|
||||
for (a = 0, e = 0; a < 15; a++) \
|
||||
e += a; \
|
||||
} while (0)
|
||||
|
||||
LINE_WITH_LOOP;
|
||||
|
||||
LINE_WITH_LOOP;
|
||||
|
||||
/* Generate a single source line that includes a time-consuming
|
||||
loop. GDB breaks the loop early by clearing variable 'c'. */
|
||||
#define LINE_WITH_TIME_CONSUMING_LOOP \
|
||||
do \
|
||||
{ \
|
||||
for (c = 1, a = 0; a < 65535 && c; a++) \
|
||||
for (b = 0; b < 65535 && c; b++) \
|
||||
{ \
|
||||
d1 = d2 * a / b; \
|
||||
d2 = d1 * a; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
LINE_WITH_TIME_CONSUMING_LOOP;
|
||||
|
||||
/* Some multi-instruction lines for software watchpoint tests. */
|
||||
LINE_WITH_MULTIPLE_INSTRUCTIONS;
|
||||
LINE_WITH_MULTIPLE_INSTRUCTIONS; /* soft-watch */
|
||||
LINE_WITH_MULTIPLE_INSTRUCTIONS;
|
||||
|
||||
return 0;
|
||||
}
|
237
gdb/testsuite/gdb.base/range-stepping.exp
Normal file
237
gdb/testsuite/gdb.base/range-stepping.exp
Normal file
@ -0,0 +1,237 @@
|
||||
# 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 "range-stepping-support.exp"
|
||||
|
||||
standard_testfile
|
||||
set executable $testfile
|
||||
|
||||
if { [prepare_for_testing $testfile.exp $testfile $srcfile {debug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
fail "Can't run to main"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Check whether range stepping is supported by the target.
|
||||
|
||||
proc gdb_range_stepping_enabled { } {
|
||||
global gdb_prompt
|
||||
|
||||
set command "set range-stepping on"
|
||||
set message "probe range-stepping support"
|
||||
gdb_test_multiple $command $message {
|
||||
-re "Range stepping is not supported.*\r\n$gdb_prompt $" {
|
||||
pass $message
|
||||
return 0
|
||||
}
|
||||
-re "^$command\r\n$gdb_prompt $" {
|
||||
pass $message
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
if ![gdb_range_stepping_enabled] {
|
||||
unsupported "range stepping not supported by the target"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Check that range stepping can step a range of multiple instructions.
|
||||
|
||||
with_test_prefix "multi insns" {
|
||||
|
||||
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 "next" is executed, GDB should send one vCont;s and vCont;r
|
||||
# and receive two stop replies:
|
||||
#
|
||||
# --> vCont;s (step over breakpoint)
|
||||
# <-- T05
|
||||
# --> vCont;rSTART,END (range step)
|
||||
# <-- T05
|
||||
exec_cmd_expect_vCont_count "next" 1 1
|
||||
|
||||
set pc_after_stepping ""
|
||||
set msg "pc after 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
|
||||
}
|
||||
}
|
||||
|
||||
# There should be at least 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 that range stepping can step over a function.
|
||||
|
||||
with_test_prefix "step over func" {
|
||||
|
||||
set line_num [gdb_get_line_number "location 2"]
|
||||
gdb_test "where" "main \\(\\) at .*${srcfile}:${line_num}.*"
|
||||
|
||||
# It's expected to get three stops and two 'vCont;r's. In the C
|
||||
# code, the line of C source produces roughly the following
|
||||
# instructions:
|
||||
#
|
||||
# addr1:
|
||||
# insn1
|
||||
# insn2
|
||||
# ...
|
||||
# call func1
|
||||
# addr2:
|
||||
# ...
|
||||
# insn3
|
||||
# addr3:
|
||||
# insn4
|
||||
#
|
||||
# Something like this will happen:
|
||||
# --> vCont;rADDR1,ADDR3 (range step from ADDR1 to ADDR3)
|
||||
# <-- T05 (target single-stepped to func, which is out of the step range)
|
||||
# --> $Z0,ADDR2 (place step-resume breakpoint at ADDR2)
|
||||
# --> vCont;c (resume)
|
||||
# <-- T05 (target stops at ADDR2)
|
||||
# --> vCont;rADDR1,ADDR3 (continues range stepping)
|
||||
# <-- T05
|
||||
exec_cmd_expect_vCont_count "next" 0 2
|
||||
}
|
||||
|
||||
# Check that breakpoints interrupt range stepping correctly.
|
||||
|
||||
with_test_prefix "breakpoint" {
|
||||
gdb_breakpoint "func1"
|
||||
# Something like this will happen:
|
||||
# --> vCont;rADDR1,ADDR3
|
||||
# <-- T05 (target single-steps to func1, which is out of the step range)
|
||||
# --> $Z0,ADDR2 (step-resume breakpoint at ADDR2)
|
||||
# --> vCont;c (resume)
|
||||
# <-- T05 (target hits the breakpoint at func1)
|
||||
exec_cmd_expect_vCont_count "next" 0 1
|
||||
|
||||
gdb_test "backtrace" "#0 .* func1 .*#1 .* main .*" \
|
||||
"backtrace from func1"
|
||||
|
||||
# A cancelled range step should not confuse the following
|
||||
# execution commands.
|
||||
exec_cmd_expect_vCont_count "stepi" 1 0
|
||||
gdb_test "finish" ".*"
|
||||
gdb_test "next" ".*"
|
||||
delete_breakpoints
|
||||
}
|
||||
|
||||
# Check that range stepping works well even when there's a loop in the
|
||||
# step range.
|
||||
|
||||
with_test_prefix "loop" {
|
||||
|
||||
# GDB should send one vCont;r and receive one stop reply:
|
||||
# --> vCont;rSTART,END (range step)
|
||||
# <-- T05
|
||||
exec_cmd_expect_vCont_count "next" 0 1
|
||||
|
||||
# Confirm the loop completed.
|
||||
gdb_test "print a" " = 15"
|
||||
gdb_test "print e" " = 105"
|
||||
}
|
||||
|
||||
# Check that range stepping works well even when the target's PC was
|
||||
# already within the loop's body.
|
||||
|
||||
with_test_prefix "loop 2" {
|
||||
# Stepi into the loop body. 15 should be large enough to make
|
||||
# sure the program stops within the loop's body.
|
||||
gdb_test "stepi 15" ".*"
|
||||
# GDB should send one vCont;r and receive one stop reply:
|
||||
# --> vCont;rSTART,END (range step)
|
||||
# <-- T05
|
||||
exec_cmd_expect_vCont_count "next" 0 1
|
||||
|
||||
# Confirm the loop completed.
|
||||
gdb_test "print a" " = 15"
|
||||
gdb_test "print e" " = 105"
|
||||
}
|
||||
|
||||
# Check that range stepping works well even when it is interrupted by
|
||||
# ctrl-c.
|
||||
|
||||
with_test_prefix "interrupt" {
|
||||
gdb_test_no_output "set debug remote 1"
|
||||
|
||||
send_gdb "next\n"
|
||||
sleep 1
|
||||
send_gdb "\003"
|
||||
|
||||
# GDB should send one vCont;r and receive one stop reply for
|
||||
# SIGINT:
|
||||
# --> vCont;rSTART,END (range step)
|
||||
# <-- T02 (SIGINT)
|
||||
|
||||
set vcont_r_counter 0
|
||||
|
||||
set test "send ctrl-c to GDB"
|
||||
gdb_test_multiple "" $test {
|
||||
-re "vCont;r\[^\r\n\]*\.\.\." {
|
||||
incr vcont_r_counter
|
||||
exp_continue
|
||||
}
|
||||
-re "Program received signal SIGINT.*$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
gdb_test_no_output "set debug remote 0"
|
||||
|
||||
# Check the number of 'vCont;r' packets.
|
||||
if { $vcont_r_counter == 1 } {
|
||||
pass "${test}: 1 vCont;r"
|
||||
} else {
|
||||
fail "${test}: 1 vCont;r"
|
||||
}
|
||||
|
||||
# Break the loop earlier and continue range stepping.
|
||||
gdb_test "set variable c = 0"
|
||||
exec_cmd_expect_vCont_count "next" 0 1
|
||||
}
|
||||
|
||||
# Check that range stepping doesn't break software watchpoints. With
|
||||
# those, GDB needs to be notified of all single-steps, to evaluate
|
||||
# whether the watched value changes at each step.
|
||||
with_test_prefix "software watchpoint" {
|
||||
gdb_test "step" "soft-watch.*" "step into multiple instruction line"
|
||||
# A software watchpoint at PC makes the thread stop before the
|
||||
# whole line range is over (after one single-step, actually).
|
||||
gdb_test "watch \$pc" ".*" "set watchpoint"
|
||||
gdb_test "step" "soft-watch.*" "step still in same line"
|
||||
}
|
||||
|
||||
return 0
|
56
gdb/testsuite/gdb.trace/range-stepping.c
Normal file
56
gdb/testsuite/gdb.trace/range-stepping.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* 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
|
||||
|
||||
/* `set_point' further below is the label where we'll set tracepoints
|
||||
at. The insn at the label must the large enough to fit a fast
|
||||
tracepoint jump. */
|
||||
#if (defined __x86_64__ || defined __i386__)
|
||||
# define NOP " .byte 0xe9,0x00,0x00,0x00,0x00\n" /* jmp $+5 (5-byte nop) */
|
||||
#else
|
||||
# define NOP "" /* port me */
|
||||
#endif
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
/* Note: 'volatile' is used to make sure the compiler doesn't
|
||||
optimize out these variables. We want to be sure instructions
|
||||
are generated for accesses. */
|
||||
volatile int i = 0;
|
||||
|
||||
/* Generate a single line with a label in the middle where we can
|
||||
place either a trap tracepoint or a fast tracepoint. */
|
||||
#define LINE_WITH_FAST_TRACEPOINT \
|
||||
do { \
|
||||
i = 1; \
|
||||
asm (" .global " SYMBOL (set_point) "\n" \
|
||||
SYMBOL (set_point) ":\n" \
|
||||
NOP \
|
||||
); \
|
||||
i = 2; \
|
||||
} while (0)
|
||||
|
||||
LINE_WITH_FAST_TRACEPOINT; /* location 1 */
|
||||
|
||||
return 0;
|
||||
}
|
85
gdb/testsuite/gdb.trace/range-stepping.exp
Normal file
85
gdb/testsuite/gdb.trace/range-stepping.exp
Normal file
@ -0,0 +1,85 @@
|
||||
# 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"
|
||||
load_lib "range-stepping-support.exp"
|
||||
|
||||
standard_testfile
|
||||
set executable $testfile
|
||||
|
||||
if [prepare_for_testing $testfile.exp $executable $srcfile \
|
||||
{debug nowarnings}] {
|
||||
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 that range stepping works well with tracepoints.
|
||||
|
||||
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"
|
||||
|
||||
# Step a line with a tracepoint in the middle. The tracepoint
|
||||
# itself shouldn't have any effect on range stepping. We
|
||||
# should see one vCont;r and no vCont;s's.
|
||||
exec_cmd_expect_vCont_count "step" 0 1
|
||||
gdb_test_no_output "tstop"
|
||||
gdb_test "tfind" "Found trace frame .*" "first tfind"
|
||||
gdb_test "tfind" \
|
||||
"Target failed to find requested trace frame.*" \
|
||||
"second tfind"
|
||||
|
||||
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"
|
||||
}
|
50
gdb/testsuite/lib/range-stepping-support.exp
Normal file
50
gdb/testsuite/lib/range-stepping-support.exp
Normal file
@ -0,0 +1,50 @@
|
||||
# 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/>.
|
||||
|
||||
# Execute command CMD and check that GDB sends the expected number of
|
||||
# vCont;s and vCont;r packets.
|
||||
|
||||
proc exec_cmd_expect_vCont_count { cmd exp_vCont_s exp_vCont_r } {
|
||||
global gdb_prompt
|
||||
|
||||
gdb_test_no_output "set debug remote 1" ""
|
||||
|
||||
set test "${cmd}: vCont;s=${exp_vCont_s} vCont;r=${exp_vCont_r}"
|
||||
set r_counter 0
|
||||
set s_counter 0
|
||||
gdb_test_multiple $cmd $test {
|
||||
-re "vCont;s\[^\r\n\]*Packet received: T\[\[:xdigit:\]\]\[\[:xdigit:\]\]" {
|
||||
incr s_counter
|
||||
exp_continue
|
||||
}
|
||||
-re "vCont;r\[^\r\n\]*Packet received: T\[\[:xdigit:\]\]\[\[:xdigit:\]\]" {
|
||||
incr r_counter
|
||||
exp_continue
|
||||
}
|
||||
-re "\r\n" {
|
||||
# Prevent overflowing the expect buffer.
|
||||
exp_continue
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
if { $r_counter == ${exp_vCont_r} && $s_counter == ${exp_vCont_s} } {
|
||||
pass $test
|
||||
} else {
|
||||
fail $test
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test_no_output "set debug remote 0" ""
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user