1# Copyright 2011-2020 Free Software Foundation, Inc.
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation; either version 3 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program.  If not, see <http://www.gnu.org/licenses/>.
14
15load_lib "trace-support.exp"
16
17if {[skip_shlib_tests]} {
18    return 0
19}
20
21if ![gdb_trace_common_supports_arch] {
22    unsupported "no trace-common.h support for arch"
23    return -1
24}
25
26standard_testfile
27set libfile1 "pendshr1"
28set libfile2 "pendshr2"
29set executable $testfile
30set libsrc1  $srcdir/$subdir/$libfile1.c
31set libsrc2  $srcdir/$subdir/$libfile2.c
32set lib_sl1  [standard_output_file $libfile1.sl]
33set lib_sl2  [standard_output_file $libfile2.sl]
34
35set lib_opts [gdb_target_symbol_prefix_flags]
36
37if { [gdb_compile_shlib $libsrc1 $lib_sl1 $lib_opts] != ""
38     || [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts] != ""} {
39    untested "failed to compile shared library"
40    return -1
41}
42
43set exec_opts [list debug shlib=$lib_sl1 shlib_load]
44if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $exec_opts] != "" } {
45    untested "failed to compile"
46    return -1
47}
48
49clean_restart $executable
50
51gdb_load_shlib $lib_sl1
52gdb_load_shlib $lib_sl2
53
54if ![runto_main] {
55    fail "can't run to main to check for trace support"
56    return -1
57}
58
59if ![gdb_target_supports_trace] {
60    unsupported "current target does not support trace"
61    return -1
62}
63
64# Verify pending tracepoint is resolved to running to main.
65
66proc pending_tracepoint_resolved { trace_type } {
67    with_test_prefix "$trace_type resolved" {
68	global srcdir
69	global subdir
70	global binfile
71	global srcfile
72	global lib_sl1
73
74	# Start with a fresh gdb.
75	gdb_exit
76	gdb_start
77	gdb_reinitialize_dir $srcdir/$subdir
78
79	gdb_test_multiple "$trace_type set_point1" "set pending tracepoint" {
80	    -re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
81		gdb_test "y" "\(Fast t|T\)racepoint.*set_point1.*pending." \
82		    "set pending tracepoint (without symbols)"
83	    }
84	}
85
86	gdb_test "info trace" \
87	    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
88\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*PENDING.*set_point1.*" \
89	    "single pending tracepoint info (without symbols)"
90
91	gdb_load ${binfile}
92
93	gdb_test "break main" "Breakpoint.*at.* file .*$srcfile, line.*" \
94	    "breakpoint function"
95
96	gdb_run_cmd
97	gdb_test "" "Breakpoint 2, main.*"
98
99	# Run to main which should resolve a pending tracepoint
100	gdb_test "info trace" \
101	    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
102\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*pendfunc.*" \
103	    "single tracepoint info"
104    }
105}
106
107# Verify pending tracepoint is resolved and works as expected.
108
109proc pending_tracepoint_works { trace_type } {
110    with_test_prefix "$trace_type works" {
111	global executable
112	global srcfile
113	global lib_sl1
114	global gdb_prompt
115
116	# Restart with a fresh gdb.
117	clean_restart $executable
118
119	# Test setting and querying pending tracepoints
120
121	gdb_test_multiple "$trace_type set_point1" "set pending tracepoint" {
122	    -re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
123		gdb_test "y" \
124		    "\(Fast t|T\)racepoint.*set_point1.*pending." \
125		    "set pending tracepoint"
126	    }
127	}
128
129	gdb_test "info trace" \
130	    "Num     Type\[ \]+Disp Enb Address\[ \]+What.*
131\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*PENDING.*set_point1.*" \
132	    "single pending tracepoint info"
133
134	# Run to main which should resolve a pending tracepoint
135	gdb_test "break main" "Breakpoint.*at.* file .*$srcfile, line.*" \
136	    "breakpoint function"
137	gdb_run_cmd
138	gdb_test "" "Breakpoint 2, main.*"
139
140	gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
141	    "breakpoint on marker"
142
143	set test "start trace experiment"
144	gdb_test_multiple "tstart" $test {
145	    -re "^tstart\r\n$gdb_prompt $" {
146		pass $test
147	    }
148	    -re "Target returns error code .* too far .*$gdb_prompt $" {
149		if [string equal $trace_type "ftrace"] {
150		    # The target was unable to install the fast tracepoint
151		    # (e.g., jump pad too far from tracepoint).
152		    pass "$test (too far)"
153		    # Skip the rest of the tests.
154		    return
155		} else {
156		    fail $test
157		}
158	    }
159
160	}
161
162	gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*$srcfile.*" \
163	    "continue to marker"
164
165	gdb_test "tstop" "\[\r\n\]+" "stop trace experiment"
166
167	gdb_test "tfind start" "#0 .*" "tfind test frame 0"
168	gdb_test "tfind" "Found trace frame 1, tracepoint 1.*" \
169	    "tfind test frame 1"
170	gdb_test "tfind" "Found trace frame 2, tracepoint 1.*" \
171	    "tfind test frame 2"
172	gdb_test "tfind" \
173	    "Target failed to find requested trace frame..*" \
174	    "tfind test frame"
175    }
176}
177
178# Verify pending tracepoint is resolved during trace.
179
180proc pending_tracepoint_resolved_during_trace { trace_type } \
181{ with_test_prefix "$trace_type resolved_in_trace" \
182{
183    global executable
184    global srcfile
185    global gdb_prompt
186    global lib_sl1
187
188    # Start with a fresh gdb.
189    clean_restart $executable
190    if ![runto_main] {
191	fail "can't run to main"
192	return -1
193    }
194
195    gdb_test_multiple "$trace_type set_point2" "set pending tracepoint on set_point2" {
196	-re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
197	    gdb_test "y" "\(Fast t|T\)racepoint.*set_point2.*pending." \
198		"set pending tracepoint (without symbols)"
199	}
200    }
201
202    gdb_test "info trace" \
203	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
204\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*PENDING.*set_point2.*" \
205	"single pending tracepoint on set_point2"
206
207    gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
208	"breakpoint on marker"
209
210    gdb_test_no_output "tstart" "start trace experiment"
211
212    gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*pending.c.*" \
213	"continue to marker 1"
214
215    set test "continue to marker 2"
216    gdb_test_multiple "continue" $test {
217	-re "Target returns error code .* too far .*$gdb_prompt $" {
218	    if [string equal $trace_type "ftrace"] {
219		# Expected if the target was unable to install the
220		# fast tracepoint (e.g., jump pad too far from
221		# tracepoint).
222		pass "$test (too far)"
223		# Skip the rest of the tests.
224		return
225	    } else {
226		fail $test
227	    }
228	}
229	-re "Continuing.\r\n(Reading .* from remote target...\r\n)?\r\n(Thread .* hit )?Breakpoint.*marker.*at.*$srcfile.*$gdb_prompt $" {
230	    pass $test
231	}
232    }
233
234    gdb_test "tstop" "\[\r\n\]+" "stop trace experiment"
235
236    # tracepoint should be resolved.
237    gdb_test "info trace" \
238	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
239\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*pendfunc2.*" \
240	"tracepoint is resolved"
241
242    gdb_test "tfind start" "#0 .*" "tfind test frame 0"
243    gdb_test "tfind" "Target failed to find requested trace frame..*" "tfind test frame"
244}}
245
246# Verify pending tracepoint is resolved and installed during trace.
247
248proc pending_tracepoint_installed_during_trace { trace_type } \
249{ with_test_prefix "$trace_type installed_in_trace" \
250{
251    global executable
252    global srcfile
253    global lib_sl1
254    global gdb_prompt
255    global hex
256
257    # Start with a fresh gdb.
258    clean_restart $executable
259    if ![runto_main] {
260	fail "can't run to main"
261	return -1
262    }
263
264    gdb_test "next" ".*"
265    gdb_test "trace main" "Tracepoint \[0-9\] at .*" "set tracepoint on main"
266
267    gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
268	"breakpoint on marker"
269
270    gdb_test_no_output "tstart" "start trace experiment"
271
272    gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*${srcfile}.*" \
273	"continue to marker 1"
274
275    # Set a pending tracepoint during a tracing experiment.
276    gdb_test_multiple "$trace_type set_point2" "set pending tracepoint on set_point2" {
277	-re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
278	    gdb_test "y" "\(Fast t|T\)racepoint.*set_point2.*pending." \
279		"set pending tracepoint"
280	}
281    }
282
283    gdb_test "info trace" \
284	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
285\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \t\]+keep y.*PENDING.*set_point2.*" \
286	"single pending tracepoint on set_point2"
287
288    set test "continue to marker 2"
289    gdb_test_multiple "continue" $test {
290	-re "Target returns error code .* too far .*$gdb_prompt $" {
291	    if [string equal $trace_type "ftrace"] {
292		# Expected if the target was unable to install the
293		# fast tracepoint (e.g., jump pad too far from
294		# tracepoint).
295		pass "$test (too far)"
296		# Skip the rest of the tests.
297		return
298	    } else {
299		fail $test
300	    }
301	}
302	-re "Continuing.\r\n(Reading .* from remote target...\r\n)?\r\n(Thread .* hit )?Breakpoint.*marker.*at.*$srcfile.*$gdb_prompt $" {
303           pass $test
304       }
305    }
306
307    gdb_test "tstop" "\[\r\n\]+" "stop trace experiment"
308
309    # tracepoint should be resolved.
310    gdb_test "info trace" \
311	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
312\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*pendfunc2.*" \
313	"tracepoint is resolved"
314
315    # powerpc64 shows "in .pendfunc2" here.
316    gdb_test "tfind start" "#0  $hex in .?pendfunc2 .*" "tfind test frame 0"
317    gdb_test "tfind" "Target failed to find requested trace frame..*" "tfind test frame"
318}}
319
320
321# Verify pending tracepoint will no longer work if we disconnect during tracing.
322
323proc pending_tracepoint_disconnect_during_trace { trace_type } \
324{ with_test_prefix "$trace_type disconn" \
325{
326    global executable
327    global srcfile
328    global lib_sl1
329    global gdb_prompt
330
331    # Start with a fresh gdb.
332    clean_restart $executable
333    if ![runto_main] {
334	fail "can't run to main"
335	return -1
336    }
337
338    gdb_test_multiple "trace pendfunc3" "set pending tracepoint on set_point2" {
339	-re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
340	    gdb_test "y" "\(Fast t|T\)racepoint.*pendfunc3.*pending." \
341		"set pending tracepoint on pendfun3"
342	}
343    }
344
345    gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
346	"breakpoint on marker"
347
348    gdb_test_no_output "tstart" "start trace experiment"
349
350    gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*pending.c.*" \
351	"continue to marker"
352
353    set test "disconnect with pending tracepoint"
354    gdb_test_multiple "disconnect" $test {
355       -re "warning: Pending tracepoints will not be resolved while GDB is disconnected.*Trace is running but will stop on detach; detach anyway\\? \\(y or n\\) $" {
356           pass $test
357
358           set test "disconnected"
359           gdb_test_multiple "y" $test {
360	       -re "$gdb_prompt $" {
361		   pass "$test"
362	       }
363	   }
364       }
365    }
366}}
367
368
369# Verify disconnect after pending tracepoint has been resolved.
370
371proc pending_tracepoint_disconnect_after_resolved { trace_type } \
372{ with_test_prefix "$trace_type disconn_resolved" \
373{
374    global executable
375    global srcfile
376    global lib_sl1
377    global gdb_prompt
378
379    # Start with a fresh gdb.
380    clean_restart $executable
381    if ![runto_main] {
382	fail "can't run to main"
383	return -1
384    }
385
386    gdb_test_multiple "trace set_point2" "set pending tracepoint on set_point2" {
387	-re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
388	    gdb_test "y" "\(Fast t|T\)racepoint.*set_point2.*pending." \
389		"set pending tracepoint on pendfun2"
390	}
391    }
392
393    gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
394	"breakpoint on marker"
395
396    gdb_test_no_output "tstart" "start trace experiment"
397
398    gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*pending.c.*" \
399	"continue to marker 1"
400    gdb_test "continue" "Continuing.\r\n(Reading .* from remote target...\r\n)?\r\n(Thread .* hit )?Breakpoint.*marker.*at.*pending.c.*" \
401	"continue to marker 2"
402
403    # There should be no pending tracepoint, so no warning should be emitted.
404    set test "disconnect with resolved tracepoint"
405    gdb_test_multiple "disconnect" $test {
406	-re "warning: Pending tracepoints will not be resolved while GDB is disconnected.*Trace is running but will stop on detach; detach anyway\\? \\(y or n\\) $" {
407	    fail $test
408	}
409	-re "Trace is running but will stop on detach; detach anyway\\? \\(y or n\\) $" {
410	    pass $test
411	}
412    }
413    set test "disconnected"
414    gdb_test_multiple "y" $test {
415	-re "$gdb_prompt $" {
416	    pass "$test"
417	}
418    }
419}}
420
421# Verify action works properly in resolved tracepoint.
422
423proc pending_tracepoint_with_action_resolved { trace_type } \
424{ with_test_prefix "$trace_type action_resolved" \
425{
426    global executable
427    global srcfile
428    global lib_sl1
429    global gdb_prompt
430    global pcreg
431
432    # Start with a fresh gdb.
433    clean_restart $executable
434    if ![runto_main] {
435	fail "can't run to main"
436	return -1
437    }
438
439    gdb_test_multiple "$trace_type set_point2" "set pending tracepoint on set_point2" {
440	-re ".*Make \(fast |\)tracepoint pending.*y or \\\[n\\\]. $" {
441	    gdb_test "y" "\(Fast t|T\)racepoint.*set_point2.*pending." \
442		"set pending tracepoint (without symbols)"
443	}
444    }
445
446    gdb_trace_setactions "set action for pending tracepoint" "" \
447	"collect \$$pcreg" "^$"
448
449    gdb_test "info trace" \
450	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
451\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*PENDING.*set_point2.*" \
452	"single pending tracepoint on set_point2"
453
454    gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
455	"breakpoint on marker"
456
457    gdb_test_no_output "tstart" "start trace experiment"
458
459    gdb_test "continue" "Continuing.\r\n\r\n(Thread .* hit )?Breakpoint.*marker.*at.*pending.c.*" \
460	"continue to marker 1"
461
462    set test "continue to marker 2"
463    gdb_test_multiple "continue" $test {
464	    -re "Target returns error code .* too far .*$gdb_prompt $" {
465            if [string equal $trace_type "ftrace"] {
466		# Expected if the target was unable to install the
467		# fast tracepoint (e.g., jump pad too far from
468		# tracepoint).
469		pass "$test (too far)"
470		# Skip the rest of the tests.
471		return
472            } else {
473		fail $test
474            }
475	}
476	-re "Continuing.\r\n(Reading .* from remote target...\r\n)?\r\n(Thread .* hit )?Breakpoint.*marker.*at.*$srcfile.*$gdb_prompt $" {
477	    pass "continue to marker 2"
478	}
479
480    }
481
482    gdb_test "tstop" "\[\r\n\]+" "stop trace experiment"
483
484    # tracepoint should be resolved.
485    gdb_test "info trace" \
486	"Num     Type\[ \]+Disp Enb Address\[ \]+What.*
487\[0-9\]+\[\t \]+\(fast |\)tracepoint\[ \]+keep y.*pendfunc2.*" \
488	"tracepoint is resolved"
489
490    gdb_test "tfind start" "#0 .*" "tfind test frame 0"
491    gdb_test "tdump" "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${pcreg} = .*"
492    gdb_test "tfind" "Target failed to find requested trace frame..*" "tfind test frame"
493}}
494
495pending_tracepoint_resolved "trace"
496
497pending_tracepoint_works "trace"
498
499pending_tracepoint_resolved_during_trace "trace"
500
501pending_tracepoint_disconnect_during_trace "trace"
502
503pending_tracepoint_disconnect_after_resolved "trace"
504
505pending_tracepoint_with_action_resolved "trace"
506
507pending_tracepoint_installed_during_trace "trace"
508
509# Re-compile test case with IPA.
510set libipa [get_in_proc_agent]
511gdb_load_shlib $libipa
512
513lappend exec_opts "shlib=$libipa"
514
515if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $exec_opts] != "" } {
516    untested "failed to compile with in-process agent library"
517    return -1
518}
519
520pending_tracepoint_resolved "ftrace"
521pending_tracepoint_works "ftrace"
522pending_tracepoint_resolved_during_trace "ftrace"
523pending_tracepoint_disconnect_during_trace "ftrace"
524pending_tracepoint_disconnect_after_resolved "ftrace"
525pending_tracepoint_with_action_resolved "ftrace"
526pending_tracepoint_installed_during_trace "ftrace"
527