| # Copyright 2017-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 file is part of the gdb testsuite. |
| |
| # Test inserting read watchpoints on unaligned addresses. |
| |
| require allow_hw_watchpoint_tests |
| |
| standard_testfile |
| if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { |
| return -1 |
| } |
| |
| if {![runto_main]} { |
| return -1 |
| } |
| |
| gdb_breakpoint [gdb_get_line_number "start_again"] "Breakpoint $decimal at $hex" "start_again" |
| |
| set sizes {1 2 4 8} |
| array set alignedend {1 1 2 2 3 4 4 4 5 8 6 8 7 8 8 8} |
| |
| set rwatch "rwatch" |
| set rwatch_exp "Hardware read watchpoint" |
| if {[istarget "s390*-*-*"]} { |
| # Target does not support this type of hardware watchpoint." |
| set rwatch "watch" |
| set rwatch_exp "Hardware watchpoint" |
| } |
| |
| foreach wpsize $sizes { |
| for {set wpoffset 0} {$wpoffset < 8 / $wpsize} {incr wpoffset} { |
| set wpstart [expr {$wpoffset * $wpsize}] |
| set wpend [expr {($wpoffset + 1) * $wpsize}] |
| set wpendaligned $alignedend($wpend) |
| foreach rdsize $sizes { |
| for {set rdoffset 0} {$rdoffset < 8 / $rdsize} {incr rdoffset} { |
| set rdstart [expr {$rdoffset * $rdsize}] |
| set rdend [expr {($rdoffset + 1) * $rdsize}] |
| set expect_hit [expr {max ($wpstart, $rdstart) < min ($wpend, $rdend)}] |
| set test "$rwatch data.u.size$wpsize\[$wpoffset\]" |
| set wpnum "" |
| gdb_test_multiple $test $test { |
| -re "$rwatch_exp (\[0-9\]+): .*\r\n$gdb_prompt $" { |
| set wpnum $expect_out(1,string) |
| } |
| -re "Expression cannot be implemented with read/access watchpoint.\r\n$gdb_prompt $" { |
| if {$wpsize == 8 && [istarget "arm*-*-*"]} { |
| untested $test |
| continue |
| } |
| fail $test |
| } |
| } |
| gdb_test_no_output -nopass "set variable size = $rdsize" |
| gdb_test_no_output -nopass "set variable offset = $rdoffset" |
| set test "continue" |
| set got_hit 0 |
| gdb_test_multiple $test $test { |
| -re "$rwatch_exp $wpnum:.*alue = .*\r\n$gdb_prompt $" { |
| set got_hit 1 |
| send_gdb "continue\n" |
| exp_continue |
| } |
| -re " start_again .*\r\n$gdb_prompt $" { |
| } |
| } |
| gdb_test_no_output -nopass "delete $wpnum" |
| set test "wp(size=$wpsize offset=$wpoffset) rd(size=$rdsize offset=$rdoffset) expect=$expect_hit" |
| if {$expect_hit == $got_hit} { |
| pass $test |
| } else { |
| # We do not know if we run on a fixed Linux kernel |
| # or not. Report XFAIL only in the FAIL case. |
| if {$expect_hit == 0 && $rdstart < $wpendaligned} { |
| setup_xfail external/20207 "aarch64*-*-linux*" |
| } |
| if {!$expect_hit && max ($wpstart / 8, $rdstart / 8) < min (($wpend + 7) / 8, ($rdend + 7) / 8)} { |
| setup_xfail breakpoints/23131 "powerpc*-*-*" |
| } |
| fail $test |
| } |
| } |
| } |
| } |
| } |
| |
| foreach_with_prefix wpcount {4 7} { |
| array set wpoffset_to_wpnum {} |
| for {set wpoffset 1} {$wpoffset <= $wpcount} {incr wpoffset} { |
| set test "$rwatch data.u.size1\[$wpoffset\]" |
| set wpnum "" |
| # Initialize the result incase the test fails. |
| set wpoffset_to_wpnum($wpoffset) 0 |
| gdb_test_multiple $test $test { |
| -re "$rwatch_exp (\[0-9\]+): .*\r\n$gdb_prompt $" { |
| set wpoffset_to_wpnum($wpoffset) $expect_out(1,string) |
| } |
| -re "There are not enough available hardware resources for this watchpoint.\r\n$gdb_prompt $" { |
| if {$wpoffset > 1} { |
| setup_xfail breakpoints/23131 "powerpc*-*-*" |
| setup_xfail breakpoints/23131 "arm*-*-*" |
| } |
| fail $test |
| } |
| } |
| } |
| gdb_test_no_output -nopass "set variable size = 1" |
| gdb_test_no_output -nopass "set variable offset = 1" |
| set test "continue" |
| set got_hit 0 |
| gdb_test_multiple $test $test { |
| -re "\r\nCould not insert hardware watchpoint .*\r\n$gdb_prompt $" { |
| } |
| -re "$rwatch_exp $wpoffset_to_wpnum(1):.*alue = .*\r\n$gdb_prompt $" { |
| set got_hit 1 |
| send_gdb "continue\n" |
| exp_continue |
| } |
| -re " start_again .*\r\n$gdb_prompt $" { |
| } |
| } |
| for {set wpoffset 1} {$wpoffset <= $wpcount} {incr wpoffset} { |
| if {$wpoffset_to_wpnum($wpoffset)} { |
| gdb_test_no_output "delete $wpoffset_to_wpnum($wpoffset)" "" |
| } |
| } |
| set test "wpcount($wpcount)" |
| if {!$wpoffset_to_wpnum([expr {$wpcount - 1}])} { |
| untested $test |
| continue |
| } |
| if {$wpcount > 4} { |
| if {![istarget "s390*-*-*"]} { |
| setup_kfail tdep/22389 *-*-* |
| } |
| } |
| gdb_assert $got_hit $test |
| } |
| |
| proc size8twice { function cmd offset index } { |
| clean_restart $::testfile |
| |
| if { ![runto $function] } { |
| return -1 |
| } |
| |
| # Set offset in the inferior. |
| gdb_test_no_output "set var offset = $offset" |
| |
| # Set a breakpoint. |
| set bp_src_string "${function}_return" |
| set bp_loc [gdb_get_line_number $bp_src_string] |
| gdb_breakpoint $bp_loc \ |
| "Breakpoint $::decimal at $::hex" "$bp_src_string" |
| |
| # Set a hardware watchpoint. |
| set watch_index [expr {$offset + $index}] |
| set test "$cmd data.u.size8twice\[$watch_index\]" |
| set wpnum 0 |
| gdb_test_multiple $test "" { |
| -re -wrap "Hardware (read )?watchpoint ($::decimal): .*" { |
| set wpnum $expect_out(2,string) |
| pass $gdb_test_name |
| } |
| -re -wrap "Watchpoint ($::decimal): .*" { |
| if {[istarget "arm*-*-*"]} { |
| untested $gdb_test_name |
| } else { |
| fail $gdb_test_name |
| } |
| } |
| } |
| |
| if { ! $wpnum } { |
| # No hardware watchpoint, we're done. |
| return 0 |
| } |
| |
| # Try to trigger the hardware watchpoint. |
| set got_hit 0 |
| gdb_test_multiple "continue" "" { |
| -re -wrap "\r\nCould not insert hardware watchpoint .*" { |
| } |
| -re -wrap "Hardware (read )?watchpoint $wpnum:.*(New value|Value) = .*" { |
| set got_hit 1 |
| send_gdb "continue\n" |
| exp_continue |
| } |
| -re -wrap " $bp_src_string .*" { |
| } |
| } |
| gdb_assert { $got_hit } |
| |
| return $got_hit |
| } |
| |
| # We've got an array with 3 8-byte elements. Do a store of 16 bytes, |
| # to: |
| # - elements 0 and 1 (offset == 0), and |
| # - elements 1 and 2 (offset == 1). |
| # For each case, check setting a watchpoint at: |
| # - the first written element (index == 0), and |
| # - the second element (index == 1). |
| foreach_with_prefix fun { write_size8twice read_size8twice } { |
| if { $fun == "write_size8twice" } { |
| set cmd "watch" |
| } else { |
| set cmd "rwatch" |
| } |
| foreach_with_prefix offset { 0 1 } { |
| foreach_with_prefix index { 0 1 } { |
| set res [size8twice $fun $cmd $offset $index] |
| if { $res != 1 } { |
| break |
| } |
| } |
| if { $res != 1 } { |
| break |
| } |
| } |
| } |