summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.exp
blob: 575761e69a10022a1694bd7639b4799fb79cc02a (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# Copyright (C) 2015-2022 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 several threads forking while another thread
# is constantly stepping over a breakpoint is properly handled.

standard_testfile

set linenum [gdb_get_line_number "set break here"]

if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
    return -1
}

# Assume yes.
set displaced_stepping_supported 1

# "set displaced on" only tells gdb to use displaced stepping if
# possible.  Probe for actual support.

proc probe_displaced_stepping_support {} {
    global displaced_stepping_supported
    global binfile gdb_prompt

    with_test_prefix "probe displaced-stepping support" {
	clean_restart $binfile

	gdb_test_no_output "set displaced on"
	if {![runto_main]} {
	    return 0
	}

	# We're stopped at the main breakpoint.  If displaced stepping is
	# supported, we'll see related debug output while we step past
	# that breakpoint.
	gdb_test_no_output "set debug displaced 1"
	gdb_test_multiple "next" "probe" {
	    -re "prepared successfully .*$gdb_prompt $" {
		pass "supported"
	    }
	    -re ".*$gdb_prompt $" {
		set displaced_stepping_supported 0
		pass "not supported"
	    }
	}
    }
}

# The test proper.  If COND_BP_TARGET is true, then test with
# conditional breakpoints evaluated on the target side, if possible.
# DETACH_ON_FORK is used as value for the "set detach-on-fork"
# setting.  If "on", this exercises GDB explicitly continuing the fork
# child until exit.  If "off", this exercises GDB detaching the fork
# child.  DISPLACED indicates whether to use displaced stepping or
# not.
proc do_test { cond_bp_target detach_on_fork displaced } {
    global GDBFLAGS
    global srcfile testfile binfile
    global decimal gdb_prompt
    global linenum
    global is_remote_target

    set saved_gdbflags $GDBFLAGS
    set GDBFLAGS [concat $GDBFLAGS " -ex \"set non-stop on\""]
    clean_restart $binfile
    set GDBFLAGS $saved_gdbflags

    if {![runto_main]} {
	return 0
    }

    if {$cond_bp_target} {
	set test "set breakpoint condition-evaluation target"
	gdb_test_multiple $test $test {
	    -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" {
		# Target doesn't support breakpoint condition
		# evaluation on its side.  Skip the test.
		return 0
	    }
	    -re "^$test\r\n$gdb_prompt $" {
	    }
	}
    } else {
	gdb_test_no_output "set breakpoint condition-evaluation host"
    }

    gdb_test_no_output "set detach-on-fork $detach_on_fork"
    gdb_test_no_output "set displaced $displaced"

    gdb_test "break $linenum if zero == 1" \
	"Breakpoint .*" \
	"set breakpoint that evals false"

    set test "continue &"
    gdb_test_multiple $test $test {
	-re "$gdb_prompt " {
	    pass $test
	}
    }

    set fork_count 0
    set ok 0

    with_timeout_factor 10 {
        set test "inferior 1 exited"
        gdb_test_multiple "" $test {
	    -re "Inferior 1 \(\[^\r\n\]+\) exited normally" {
	        set ok 1
	        pass $test
	    }
	    -re "Inferior $decimal \(\[^\r\n\]+\) exited normally" {
	        incr fork_count
	        if {$fork_count <= 100} {
		    exp_continue
	        } else {
		    fail "$test (too many forks)"
	        }
	    }
	}
    }

    if {!$ok} {
	# No use testing further.
	return
    }

    gdb_test "info threads" "No threads\." \
	"no threads left"

    gdb_test "info inferiors" \
	"Num\[ \t\]+Description\[ \t\]+Connection\[ \t\]+Executable\[ \t\]+\r\n\\* 1 \[^\r\n\]+" \
	"only inferior 1 left"
}

probe_displaced_stepping_support

foreach_with_prefix cond_bp_target {1 0} {
    foreach_with_prefix detach_on_fork {"on" "off"} {
	# Disable "off" for now.  The test does pass with
	# detach-on-fork off (at the time of writing), but gdb seems
	# to slow down quadratically as inferiors are created, and
	# then the test takes annoyingly long to complete...
	if {$detach_on_fork == "off"} {
	    continue
	}

	foreach_with_prefix displaced {"on" "off"} {
	    if {$displaced == "on" && !$displaced_stepping_supported} {
		continue
	    }

	    do_test $cond_bp_target $detach_on_fork $displaced
	}
    }
}