Commit | Line | Data |
---|---|---|
88b9d363 | 1 | # Copyright (C) 2021-2022 Free Software Foundation, Inc. |
05c06f31 PA |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation; either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | # Test that we can access memory while all the threads of the inferior | |
17 | # are running, and even if: | |
18 | # | |
19 | # - the leader thread exits | |
20 | # - the selected thread exits | |
21 | # | |
22 | # This test constantly spawns short lived threads to make sure that on | |
23 | # systems with debug APIs that require passing down a specific thread | |
24 | # to work with (e.g., GNU/Linux ptrace and /proc filesystem), GDB | |
25 | # copes with accessing memory just while the thread it is accessing | |
26 | # memory through exits. | |
27 | # | |
28 | # The test spawns two processes and alternates memory accesses between | |
29 | # them to force flushing per-process caches. At the time of writing, | |
30 | # the Linux backend accesses inferior memory via /proc/<pid>/mem, and | |
31 | # keeps one such file open, as a cache. Alternating inferiors forces | |
32 | # opening such file for a different process, which fails if GDB tries | |
33 | # to open the file for a thread that exited. The test does ensures | |
34 | # those reopen/fail code paths are exercised. | |
35 | ||
36 | standard_testfile | |
37 | ||
38 | if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} { | |
39 | return -1 | |
40 | } | |
41 | ||
42 | # The test proper. NON_STOP indicates whether we're testing in | |
43 | # non-stop, or all-stop mode. | |
44 | ||
45 | proc test { non_stop } { | |
46 | global binfile | |
47 | global gdb_prompt | |
48 | global GDBFLAGS | |
49 | ||
50 | save_vars { GDBFLAGS } { | |
51 | append GDBFLAGS " -ex \"set non-stop $non_stop\"" | |
52 | clean_restart ${binfile} | |
53 | } | |
54 | ||
55 | if ![runto_main] { | |
56 | fail "cannot run to main" | |
57 | return -1 | |
58 | } | |
59 | ||
60 | # If debugging with target remote, check whether the all-stop variant | |
61 | # of the RSP is being used. If so, we can't run the background tests. | |
62 | if {!$non_stop | |
63 | && [target_info exists gdb_protocol] | |
64 | && ([target_info gdb_protocol] == "remote" | |
65 | || [target_info gdb_protocol] == "extended-remote")} { | |
66 | ||
67 | gdb_test_multiple "maint show target-non-stop" "" { | |
68 | -wrap -re "(is|currently) on.*" { | |
69 | } | |
70 | -wrap -re "(is|currently) off.*" { | |
71 | unsupported "can't issue commands while target is running" | |
72 | return 0 | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | delete_breakpoints | |
78 | ||
79 | # Start the second inferior. | |
80 | with_test_prefix "second inferior" { | |
81 | gdb_test "add-inferior -no-connection" "New inferior 2.*" | |
82 | gdb_test "inferior 2" "Switching to inferior 2 .*" | |
83 | ||
84 | gdb_load $binfile | |
85 | ||
86 | if ![runto_main] { | |
87 | fail "cannot run to main" | |
88 | return -1 | |
89 | } | |
90 | } | |
91 | ||
92 | delete_breakpoints | |
93 | ||
94 | # These put too much noise in the logs. | |
95 | gdb_test_no_output "set print thread-events off" | |
96 | ||
97 | # Continue all threads of both processes. | |
98 | gdb_test_no_output "set schedule-multiple on" | |
99 | if {$non_stop == "off"} { | |
100 | set cmd "continue &" | |
101 | } else { | |
102 | set cmd "continue -a &" | |
103 | } | |
104 | gdb_test_multiple $cmd "continuing" { | |
105 | -re "Continuing\.\r\n$gdb_prompt " { | |
106 | pass $gdb_test_name | |
107 | } | |
108 | } | |
109 | ||
110 | # Like gdb_test, but: | |
111 | # - don't issue a pass on success. | |
112 | # - on failure, clear the ok variable in the calling context, and | |
113 | # break it. | |
114 | proc my_gdb_test {cmd pattern message} { | |
115 | upvar inf inf | |
116 | upvar iter iter | |
117 | if {[gdb_test_multiple $cmd "access mem ($message, inf=$inf, iter=$iter)" { | |
118 | -wrap -re $pattern { | |
119 | } | |
120 | }] != 0} { | |
121 | uplevel 1 {set ok 0} | |
122 | return -code break | |
123 | } | |
124 | } | |
125 | ||
126 | # Hammer away for 5 seconds, alternating between inferiors. | |
127 | set ::done 0 | |
128 | after 5000 { set ::done 1 } | |
129 | ||
130 | set inf 1 | |
131 | set ok 1 | |
132 | set iter 0 | |
133 | while {!$::done && $ok} { | |
134 | incr iter | |
135 | verbose -log "xxxxx: iteration $iter" | |
136 | gdb_test "info threads" ".*" "" | |
137 | ||
138 | if {$inf == 1} { | |
139 | set inf 2 | |
140 | } else { | |
141 | set inf 1 | |
142 | } | |
143 | ||
144 | my_gdb_test "inferior $inf" ".*" "inferior $inf" | |
145 | ||
146 | my_gdb_test "print global_var = 555" " = 555" \ | |
147 | "write to global_var" | |
148 | my_gdb_test "print global_var" " = 555" \ | |
149 | "print global_var after writing" | |
150 | my_gdb_test "print global_var = 333" " = 333" \ | |
151 | "write to global_var again" | |
152 | my_gdb_test "print global_var" " = 333" \ | |
153 | "print global_var after writing again" | |
154 | } | |
155 | ||
156 | if {$ok} { | |
157 | pass "access mem" | |
158 | } | |
159 | } | |
160 | ||
161 | foreach non_stop { "off" "on" } { | |
162 | set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"] | |
163 | with_test_prefix "$stop_mode" { | |
164 | test $non_stop | |
165 | } | |
166 | } |