1# This testcase is part of GDB, the GNU debugger.
2#
3# Copyright 2015-2020 Free Software Foundation, Inc.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18if { [skip_btrace_tests] } {
19    unsupported "target does not support record-btrace"
20    return -1
21}
22
23standard_testfile
24if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } {
25    untested "failed to prepare"
26    return -1
27}
28
29save_vars { GDBFLAGS } {
30    append GDBFLAGS " -ex \"set non-stop on\""
31    clean_restart $testfile
32}
33
34if ![runto_main] {
35    untested "failed to run to main"
36    return -1
37}
38
39# set up breakpoints
40set bp_1 [gdb_get_line_number "bp.1" $srcfile]
41set bp_2 [gdb_get_line_number "bp.2" $srcfile]
42set bp_3 [gdb_get_line_number "bp.3" $srcfile]
43
44gdb_breakpoint $bp_1
45gdb_breakpoint $bp_2
46
47# get the line number containing most of the trace
48set loop [gdb_get_line_number "loop" $srcfile]
49
50# a stop on the above line as reported by GDB
51set loop_line "$loop\[^\\\r\\\n\]*/\\\* loop \\\*/"
52
53# make sure $line matches the full expected output per thread.
54# and let's hope that GDB never mixes the output from different threads.
55proc gdb_cont_to { threads cmd line nthreads } {
56    global gdb_prompt
57    set full_cmd "thread apply $threads $cmd"
58
59    # consume the prompt.  since we started the command in the background,
60    # the prompt precedes any further output except some errors.
61    gdb_test_multiple "$full_cmd &" "$full_cmd: prompt" {
62        -re "$gdb_prompt " {
63            pass "$full_cmd: prompt"
64        }
65    }
66
67    # now check for the expected line - one per thread.
68    for {set i 0} {$i < $nthreads} {incr i} {
69        set test "$full_cmd: thread $i"
70
71        gdb_test_multiple "" $test {
72            -re "$line\[^\\\r\\\n\]*\r\n" {
73                pass $test
74            }
75        }
76    }
77}
78
79proc gdb_cont_to_bp_line { line threads nthreads } {
80    gdb_cont_to $threads "continue" \
81        [multi_line \
82             "Breakpoint\[^\\\r\\\n\]*$line" \
83             "\[^\\\r\\\n\]*" \
84            ] \
85        $nthreads
86}
87
88proc gdb_cont_to_no_history { threads cmd nthreads } {
89    gdb_cont_to $threads $cmd \
90        [multi_line \
91             "No more reverse-execution history\." \
92             "\[^\\\r\\\n\]*" \
93             "\[^\\\r\\\n\]*" \
94            ] \
95        $nthreads
96}
97
98# trace the code between the two breakpoints
99gdb_cont_to_bp_line "$srcfile:$bp_1" all 2
100gdb_test_no_output "record btrace"
101gdb_cont_to_bp_line "$srcfile:$bp_2" all 2
102
103# we don't need those breakpoints any longer.
104# they will only disturb our stepping.
105delete_breakpoints
106
107# show the threads - this is useful for debugging fails
108gdb_test "thread apply all info rec" ".*"
109gdb_test "info threads" ".*"
110
111with_test_prefix "navigate" {
112    gdb_test "thread apply 1 record goto 2" "$loop_line"
113    gdb_test "thread apply 2 record goto 4" "$loop_line"
114    gdb_test "thread apply 1 info record" \
115        ".*Replay in progress\.  At instruction 2\."
116    gdb_test "thread apply 2 info record" \
117        ".*Replay in progress\.  At instruction 4\."
118
119    gdb_test "thread apply all record goto 5" "$loop_line"
120    gdb_test "thread apply 1 info record" \
121        ".*Replay in progress\.  At instruction 5\."
122    gdb_test "thread apply 2 info record" \
123        ".*Replay in progress\.  At instruction 5\."
124}
125
126with_test_prefix "step" {
127    with_test_prefix "thread 1" {
128        gdb_test "thread apply 1 stepi 2" "$loop_line"
129        gdb_test "thread apply 1 info record" \
130            ".*Replay in progress\.  At instruction 7\."
131        gdb_test "thread apply 2 info record" \
132            ".*Replay in progress\.  At instruction 5\."
133    }
134
135    with_test_prefix "thread 2" {
136        gdb_test "thread apply 2 stepi 3" "$loop_line"
137        gdb_test "thread apply 1 info record" \
138            ".*Replay in progress\.  At instruction 7\."
139        gdb_test "thread apply 2 info record" \
140            ".*Replay in progress\.  At instruction 8\."
141    }
142
143    with_test_prefix "all" {
144        gdb_cont_to all "stepi 4" "$loop_line" 2
145        gdb_test "thread apply 1 info record" \
146            ".*Replay in progress\.  At instruction 11\."
147        gdb_test "thread apply 2 info record" \
148            ".*Replay in progress\.  At instruction 12\."
149    }
150}
151
152with_test_prefix "reverse-step" {
153    with_test_prefix "thread 1" {
154        gdb_test "thread apply 1 reverse-stepi 2" "$loop_line"
155        gdb_test "thread apply 1 info record" \
156            ".*Replay in progress\.  At instruction 9\."
157        gdb_test "thread apply 2 info record" \
158            ".*Replay in progress\.  At instruction 12\."
159    }
160
161    with_test_prefix "thread 2" {
162        gdb_test "thread apply 2 reverse-stepi 3" "$loop_line"
163        gdb_test "thread apply 1 info record" \
164            ".*Replay in progress\.  At instruction 9\."
165        gdb_test "thread apply 2 info record" \
166            ".*Replay in progress\.  At instruction 9\."
167    }
168
169    with_test_prefix "all" {
170        gdb_cont_to all "reverse-stepi 4" "$loop_line" 2
171        gdb_test "thread apply 1 info record" \
172            ".*Replay in progress\.  At instruction 5\."
173        gdb_test "thread apply 2 info record" \
174            ".*Replay in progress\.  At instruction 5\."
175    }
176}
177
178with_test_prefix "continue" {
179    with_test_prefix "thread 1" {
180        gdb_cont_to_no_history 1 "continue" 1
181        gdb_test "thread apply 1 info record" \
182            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
183        gdb_test "thread apply 2 info record" \
184            ".*Replay in progress\.  At instruction 5\."
185
186        gdb_cont_to_no_history 1 "reverse-continue" 1
187        gdb_test "thread apply 1 info record" \
188            ".*Replay in progress\.  At instruction 1\."
189        gdb_test "thread apply 2 info record" \
190            ".*Replay in progress\.  At instruction 5\."
191    }
192
193    with_test_prefix "thread 2" {
194        gdb_cont_to_no_history 2 "continue" 1
195        gdb_test "thread apply 1 info record" \
196            ".*Replay in progress\.  At instruction 1\."
197        gdb_test "thread apply 2 info record" \
198            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
199
200        gdb_cont_to_no_history 2 "reverse-continue" 1
201        gdb_test "thread apply 1 info record" \
202            ".*Replay in progress\.  At instruction 1\."
203        gdb_test "thread apply 2 info record" \
204            ".*Replay in progress\.  At instruction 1\."
205    }
206}
207
208# a thread may only resume if no thread is still replaying
209with_test_prefix "no progress" {
210    with_test_prefix "thread 1" {
211        gdb_test "thread apply 1 record goto end" ".*"
212        gdb_test "thread apply 2 record goto begin" ".*"
213
214        gdb_cont_to_no_history 1 "continue" 1
215        gdb_cont_to_no_history 1 "step" 1
216        gdb_test "thread apply 1 info record" \
217            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
218        gdb_test "thread apply 2 info record" \
219            ".*Replay in progress\.  At instruction 1\."
220    }
221
222    with_test_prefix "thread 2" {
223        gdb_test "thread apply 1 record goto begin" ".*"
224        gdb_test "thread apply 2 record goto end" ".*"
225
226        gdb_cont_to_no_history 2 "continue" 1
227        gdb_cont_to_no_history 2 "step" 1
228        gdb_test "thread apply 1 info record" \
229            ".*Replay in progress\.  At instruction 1\."
230        gdb_test "thread apply 2 info record" \
231            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
232    }
233
234    with_test_prefix "all" {
235        gdb_test "thread apply all record goto begin" ".*"
236
237        gdb_cont_to_no_history all "continue" 2
238        gdb_test "thread apply 1 info record" \
239            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
240        gdb_test "thread apply 2 info record" \
241            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
242    }
243}
244
245# now that both threads stopped replaying we may resume recording
246with_test_prefix "cont to end" {
247    gdb_breakpoint $bp_3
248    gdb_cont_to_bp_line "$srcfile:$bp_3" all 1
249}
250