blob: 95b506a80b61506d767be40f79fddb3550dd84c6 [file] [log] [blame]
# This testcase is part of GDB, the GNU debugger.
# Copyright 2023-2026 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/>.
# This test verifies that you can set a watchpoint that watches global
# memory, when the selected thread is running.
set allow_hw_watchpoint_tests_p [allow_hw_watchpoint_tests]
standard_testfile
if {[build_executable "failed to prepare" $testfile $srcfile {debug}]} {
return -1
}
# STOP_MODE is either "all-stop" or "non-stop". HW is true if we are
# testing hardware watchpoints, and false if we're testing software
# watchpoints.
proc test {stop_mode hw} {
save_vars { ::GDBFLAGS } {
if { $stop_mode == "non-stop" } {
append ::GDBFLAGS " -ex \"set non-stop on\""
} elseif {[target_info gdb_protocol] == "remote"
|| [target_info gdb_protocol]== "extended-remote"} {
# Communicating with the target while the inferior is
# running depends on target running in non-stop mode.
# Force it on for remote targets, until this is the
# default.
append ::GDBFLAGS " -ex \"maint set target-non-stop on\""
}
clean_restart $::testfile
}
gdb_test_no_output "set can-use-hw-watchpoints $hw"
if {![runto_main]} {
return
}
delete_breakpoints
# Continue the program in the background.
set test "continue&"
gdb_test_multiple "continue&" $test {
-re "Continuing\\.\r\n$::gdb_prompt " {
pass $test
}
}
set val1 ""
gdb_test_multiple "print global_var" "global_var once" {
-re -wrap " = ($::decimal)" {
set val1 $expect_out(1,string)
pass "$gdb_test_name"
}
}
# Sleep for a bit, so the variable is sure to be incremented, if
# indeed we managed to get the target running.
sleep 1
set val2 ""
gdb_test_multiple "print global_var" "global_var twice" {
-re -wrap " = ($::decimal)" {
set val2 $expect_out(1,string)
pass "$gdb_test_name"
}
}
# The variable should have incremented. (Note we didn't give it
# sufficient time to ever wrap around.)
gdb_assert {$val1 != $val2} "values are different"
set wp_str [expr {($hw)?"Hardware watchpoint":"Watchpoint"}]
# Now set a watchpoint, while the inferior is running. Since
# we're watching a global, and we can read global memory while the
# target is running, this should be able to work.
gdb_test_multiple "watch global_var" "" {
-re "$wp_str $::decimal: global_var\r\n$::gdb_prompt " {
pass $gdb_test_name
}
}
# Check that the watchpoint triggers.
save_vars ::timeout {
if {!$hw} {
# This doesn't currently work with software watchpoints.
# GDB should transparently temporarily pause the inferior,
# to force it to single step, but it doesn't, so the
# thread continues running free.
setup_kfail gdb/31833 *-*-*
# No point waiting too much for output we know isn't
# coming.
set ::timeout 1
}
set re [multi_line \
"$wp_str $::decimal: global_var" \
"" \
"Old value = $::decimal" \
"New value = $::decimal"]
gdb_test_multiple "" "watchpoint hit" {
-re $re {
pass $gdb_test_name
}
}
}
}
foreach hw {0 1} {
if {$hw && !$allow_hw_watchpoint_tests_p} {
continue
}
foreach stop_mode {all-stop non-stop} {
set wp_type [expr {($hw)?"hardware":"software"}]
with_test_prefix "$stop_mode: $wp_type" {
test $stop_mode $hw
}
}
}