summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.threads/step-over-trips-on-watchpoint.exp
blob: 2f0be507f614a908c9f492b8a39983f354265196 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Copyright (C) 2014-2016 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/>.

# Test that when a step-over trips on a watchpoint, that watchpoint is
# reported.

standard_testfile
set executable ${testfile}

# This test verifies that a watchpoint is detected in a multithreaded
# program so the test is only meaningful on a system with hardware
# watchpoints.
if {[skip_hw_watchpoint_tests]} {
    return 0
}

if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
	 executable [list debug "incdir=${objdir}"]] != "" } {
    return -1
}

# The test proper.  DISPLACED is true if we should try with displaced
# stepping.  WITH_BP is true if we should try with a thread-specific
# breakpoint (for the wrong thread) right after the instruction that
# triggers the watchpoint.
proc do_test { displaced with_bp } {
    global executable
    global gdb_prompt
    global hex

    if ${with_bp} {
	set prefix "with thread-specific bp"
    } else {
	set prefix "no thread-specific bp"
    }
    with_test_prefix "displaced=$displaced: $prefix" {
	# Cover both stepping and non-stepping execution commands.
	foreach command {"step" "next" "continue" } {
	    with_test_prefix $command {
		clean_restart $executable

		if ![runto_main] {
		    continue
		}

		gdb_test_no_output "set displaced-stepping $displaced"

		gdb_breakpoint [gdb_get_line_number "set wait-thread breakpoint here"]
		gdb_continue_to_breakpoint "run to wait-thread breakpoint"
		gdb_test "info threads" "\\\* 1 .*  2 .*" "info threads shows all threads"

		gdb_test_no_output "set scheduler-locking on"

		delete_breakpoints

		gdb_breakpoint [gdb_get_line_number "set breakpoint child here"]
		gdb_test "thread 2" "Switching to .*"
		gdb_continue_to_breakpoint "run to breakpoint in thread 2"

		set address_triggers_watch "<invalid>"
		set after_address_triggers_watch "<invalid>"

		# Let the watchpoint trigger once (with the other
		# thread locked), in order to find both the address of
		# the instruction that triggers the watchpoint and the
		# address of the instruction immediately after.
		with_test_prefix "find addresses" {
		    gdb_test "p watch_me = 0" " = 0" "clear watch_me"
		    gdb_test "watch watch_me" "Hardware watchpoint .*"

		    gdb_test "continue" \
			"Hardware watchpoint.*: watch_me.*New value = 1.*" \
			"continue to watchpoint"

		    set msg "find addresses"
		    gdb_test_multiple "disassemble" $msg {
			-re " ($hex) \[^\r\n\]*\r\n=> ($hex) .*$gdb_prompt $" {
			    set address_triggers_watch $expect_out(1,string)
			    set after_address_triggers_watch $expect_out(2,string)
			    pass $msg
			}
		    }

		    delete_breakpoints
		}

		gdb_test "break *$address_triggers_watch" "Breakpoint .*" \
		    "set breakpoint at address that triggers watch"
		gdb_continue_to_breakpoint \
		    "run to instruction that triggers watch in thread 2"

		gdb_test "p counter = 0" " = 0" "unbreak loop in thread 2"
		gdb_test "p watch_me = 0" " = 0" "clear watch_me"
		gdb_test "watch watch_me" "Hardware watchpoint .*"

		if ${with_bp} {
		    gdb_test "b *$after_address_triggers_watch thread 1" \
			"Breakpoint .*" \
			"set breakpoint specific to thread 1"
		}

		# Switch back to thread 1 and disable scheduler locking.
		gdb_test "thread 1" "Switching to .*"
		gdb_test_no_output "set scheduler-locking off"

		# Thread 2 is still stopped at a breakpoint that needs
		# to be stepped over.  However, the instruction that
		# is under the breakpoint triggers a watchpoint, which
		# should trap and be reported to the user.
		gdb_test "$command" "Hardware watchpoint.*: watch_me.*New value = 1.*"
	    }
	}
    }
}

foreach displaced { "off" "on" } {
    if { $displaced != "off" && ![support_displaced_stepping] } {
	continue
    }

    foreach with_bp { 0 1 } {
	do_test $displaced $with_bp
    }
}