aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/breakpoint.c19
-rw-r--r--gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.c29
-rw-r--r--gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp67
-rw-r--r--gdb/testsuite/gdb.base/watchpoint.exp34
4 files changed, 135 insertions, 14 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ebe9794..47f35c6 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2143,6 +2143,21 @@ update_watchpoint (struct watchpoint *b, bool reparse)
}
}
+ /* Helper function to bundle possibly emitting a warning along with
+ changing the type of B to bp_watchpoint. */
+ auto change_type_to_bp_watchpoint = [] (breakpoint *bp)
+ {
+ /* Only warn for breakpoints that have been assigned a +ve number,
+ anything else is either an internal watchpoint (which we don't
+ currently create) or has not yet been finalized, in which case
+ this change of type will be occurring before the user is told
+ the type of this watchpoint. */
+ if (bp->type == bp_hardware_watchpoint && bp->number > 0)
+ warning (_("watchpoint %d downgraded to software watchpoint"),
+ bp->number);
+ bp->type = bp_watchpoint;
+ };
+
/* Change the type of breakpoint between hardware assisted or
an ordinary watchpoint depending on the hardware support and
free hardware slots. Recheck the number of free hardware slots
@@ -2200,7 +2215,7 @@ update_watchpoint (struct watchpoint *b, bool reparse)
"resources for this watchpoint."));
/* Downgrade to software watchpoint. */
- b->type = bp_watchpoint;
+ change_type_to_bp_watchpoint (b);
}
else
{
@@ -2221,7 +2236,7 @@ update_watchpoint (struct watchpoint *b, bool reparse)
"read/access watchpoint."));
}
else
- b->type = bp_watchpoint;
+ change_type_to_bp_watchpoint (b);
loc_type = (b->type == bp_watchpoint? bp_loc_software_watchpoint
: bp_loc_hardware_watchpoint);
diff --git a/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.c b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.c
new file mode 100644
index 0000000..c2f5f2c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2023 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/>. */
+
+struct struct_type
+{
+ unsigned long long array[100];
+};
+
+struct struct_type global_var;
+
+int
+main ()
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp
new file mode 100644
index 0000000..bc579a9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp
@@ -0,0 +1,67 @@
+# Copyright 2023 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/>.
+
+# Ask GDB to watch a large structure before the inferior has started,
+# GDB will assume it can place a hardware watchpoint.
+#
+# Once the inferior starts GDB realises that it is not able to watch
+# such a large structure and downgrades to a software watchpoint.
+#
+# This test checks that GDB emits a warnings about this downgrade, as
+# a software watchpoint will be significantly slower than a hardware
+# watchpoint, and the user probably wants to know about this.
+
+require target_can_use_run_cmd is_x86_64_m64_target
+
+# The remote/extended-remote target has its own set of flags to
+# control the use of s/w vs h/w watchpoints, this test isn't about
+# those, so skip the test in these cases.
+if {[target_info gdb_protocol] == "remote"
+ || [target_info gdb_protocol] == "extended-remote"} {
+ unsupported "using [target_info gdb_protocol] protocol"
+ return -1
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ { debug }] } {
+ return -1
+}
+
+# Insert the watchpoint, it should default to a h/w watchpoint.
+gdb_test "watch global_var" \
+ "Hardware watchpoint $decimal: global_var"
+set num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
+ "get watchpoint number"]
+
+# Watchpoint should initially show as a h/w watchpoint.
+gdb_test "info watchpoints" \
+ "\r\n$num\\s+hw watchpoint\\s+keep\\s+y\\s+global_var" \
+ "check info watchpoints before starting"
+
+# Start the inferior, GDB should emit a warning that the watchpoint
+# type has changed.
+gdb_test "starti" \
+ [multi_line \
+ "warning: watchpoint $num downgraded to software watchpoint" \
+ "" \
+ "Program stopped\\." \
+ ".*"]
+
+# Watchpoint should now have downgraded to a s/w watchpoint.
+gdb_test "info watchpoints" \
+ "\r\n$num\\s+watchpoint\\s+keep\\s+y\\s+global_var" \
+ "check info watchpoints after starting"
diff --git a/gdb/testsuite/gdb.base/watchpoint.exp b/gdb/testsuite/gdb.base/watchpoint.exp
index 513964e..2827668 100644
--- a/gdb/testsuite/gdb.base/watchpoint.exp
+++ b/gdb/testsuite/gdb.base/watchpoint.exp
@@ -273,7 +273,8 @@ proc test_stepping {} {
global gdb_prompt
if {[runto marker1]} {
- gdb_test "watch ival2" ".*\[Ww\]atchpoint \[0-9\]*: ival2"
+ gdb_test "watch ival2" \
+ "^watch ival2\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: ival2"
# Well, let's not be too mundane. It should be a *bit* of a challenge
gdb_test "break func2 if 0" "Breakpoint.*at.*"
@@ -432,7 +433,8 @@ proc test_complex_watchpoint {} {
global gdb_prompt
if {[runto marker4]} {
- gdb_test "watch ptr1->val" ".*\[Ww\]atchpoint \[0-9\]*: ptr1->val"
+ gdb_test "watch ptr1->val" \
+ "^watch ptr1->val\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: ptr1->val"
gdb_test "break marker5" ".*Breakpoint.*"
gdb_test "cont" "Continuing.*\[Ww\]atchpoint.*ptr1->val.*Old value = 1.*New value = 2.*" "test complex watchpoint"
@@ -458,7 +460,9 @@ proc test_complex_watchpoint {} {
# is the function we're now in. This should auto-delete when
# execution exits the scope of the watchpoint.
#
- gdb_test "watch local_a" ".*\[Ww\]atchpoint \[0-9\]*: local_a" "set local watch"
+ gdb_test "watch local_a" \
+ "^watch local_a\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: local_a" \
+ "set local watch"
gdb_test "cont" "\[Ww\]atchpoint.*local_a.*" "trigger local watch"
set test "self-delete local watch"
@@ -487,7 +491,8 @@ proc test_complex_watchpoint {} {
# something whose scope is larger than this invocation
# of "func2". This should also auto-delete.
#
- gdb_test "watch local_a + ival5" ".*\[Ww\]atchpoint \[0-9\]*: local_a . ival5" \
+ gdb_test "watch local_a + ival5" \
+ "^watch local_a \\+ ival5\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: local_a . ival5" \
"set partially local watch"
gdb_test "cont" "Continuing.*\[Ww\]atchpoint .*: local_a . ival5.*" \
"trigger1 partially local watch"
@@ -502,7 +507,8 @@ proc test_complex_watchpoint {} {
# delete.
#
gdb_continue_to_breakpoint "func2 breakpoint here, third time"
- gdb_test "watch static_b" ".*\[Ww\]atchpoint \[0-9\]*: static_b" \
+ gdb_test "watch static_b" \
+ "^watch static_b\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: static_b" \
"set static local watch"
gdb_test "cont" "Continuing.*\[Ww\]atchpoint .*: static_b.*" \
"trigger static local watch"
@@ -521,7 +527,8 @@ proc test_complex_watchpoint {} {
gdb_test "tbreak recurser" ".*breakpoint.*"
gdb_test "cont" "Continuing.*recurser.*"
gdb_test "next" "if \\(x > 0.*" "next past local_x initialization"
- gdb_test "watch local_x" ".*\[Ww\]atchpoint \[0-9\]*: local_x" \
+ gdb_test "watch local_x" \
+ "^watch local_x\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: local_x" \
"set local watch in recursive call"
gdb_test "cont" "Continuing.*\[Ww\]atchpoint .*: local_x.*New value = 2.*" \
"trigger local watch in recursive call"
@@ -536,7 +543,8 @@ proc test_complex_watchpoint {} {
gdb_test "tbreak recurser" ".*breakpoint.*"
gdb_test "cont" "Continuing.*recurser.*" "continue to recurser"
gdb_test "next" "if \\(x > 0.*" "next past local_x initialization"
- gdb_test "watch recurser::local_x" ".*\[Ww\]atchpoint \[0-9\]*: recurser::local_x" \
+ gdb_test "watch recurser::local_x" \
+ "^watch recurser::local_x\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]*: recurser::local_x" \
"set local watch in recursive call with explicit scope"
gdb_test "cont" "Continuing.*\[Ww\]atchpoint .*: recurser::local_x.*New value = 2.*" \
"trigger local watch with explicit scope in recursive call"
@@ -562,7 +570,8 @@ proc test_watchpoint_and_breakpoint {} {
if {[runto func3]} {
gdb_breakpoint [gdb_get_line_number "second x assignment"]
gdb_continue_to_breakpoint "second x assignment"
- gdb_test "watch x" ".*atchpoint \[0-9\]+: x"
+ gdb_test "watch x" \
+ "^watch x\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]+: x"
gdb_test "next" \
".*atchpoint \[0-9\]+: x\r\n\r\nOld value = 0\r\nNew value = 1\r\n.*" \
"next after watch x"
@@ -579,7 +588,8 @@ proc test_constant_watchpoint {} {
"marker1 is constant"
gdb_test "watch count + 6" ".*atchpoint \[0-9\]+: count \\+ 6"
gdb_test_no_output "delete \$bpnum" "delete watchpoint `count + 6'"
- gdb_test "watch 7 + count" ".*atchpoint \[0-9\]+: 7 \\+ count"
+ gdb_test "watch 7 + count" \
+ "^watch 7 \\+ count\r\n\[^\r\n\]*atchpoint \[0-9\]+: 7 \\+ count"
gdb_test_no_output "delete \$bpnum" "delete watchpoint `7 + count'"
}
@@ -588,7 +598,7 @@ proc test_disable_enable_software_watchpoint {} {
# for software watchpoints.
# Watch something not memory to force a software watchpoint.
- gdb_test {watch $pc} ".*atchpoint \[0-9\]+: .pc"
+ gdb_test {watch $pc} "^watch \\\$pc\r\n\[^\r\n\]*\[Ww\]atchpoint \[0-9\]+: .pc"
gdb_test_no_output "disable \$bpnum" "disable watchpoint `\$pc'"
gdb_test_no_output "enable \$bpnum" "reenable watchpoint `\$pc'"
@@ -822,7 +832,7 @@ proc test_no_hw_watchpoints {} {
"show disable fast watches"
gdb_test "watch ival3 if count > 1" \
- "Watchpoint \[0-9\]*: ival3.*" \
+ "^watch ival3 if count > 1\r\nWatchpoint \[0-9\]*: ival3.*" \
"set slow conditional watch"
gdb_test "continue" \
@@ -832,7 +842,7 @@ proc test_no_hw_watchpoints {} {
gdb_test_no_output "delete \$bpnum" "delete watch ival3"
gdb_test "watch ival3 if count > 1 thread 1 " \
- "Watchpoint \[0-9\]*: ival3.*" \
+ "watch ival3 if count > 1 thread 1 \r\nWatchpoint \[0-9\]*: ival3.*" \
"set slow condition watch w/thread"
gdb_test_no_output "delete \$bpnum" "delete watch w/condition and thread"