1# Copyright 2010, 2011 Free Software Foundation, Inc.
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# This test only works on GNU/Linux.
17if { ![isnative] || [is_remote host] || ![istarget *-linux*] || [skip_shlib_tests]} {
18    continue
19}
20
21load_lib prelink-support.exp
22
23set test "break-interp"
24set binprefix ${objdir}/${subdir}/${test}
25# Only to get the $interp_system name.
26set srcfile_test "start.c"
27set binfile_test ${test}-test
28set binfile_lib ${objdir}/${subdir}/${test}.so
29set srcfile "${test}-main.c"
30set srcfile_lib "${test}-lib.c"
31
32if [get_compiler_info ${binfile_lib}] {
33    return -1
34}
35
36# Use -soname so that the new library gets copied by build_executable_own_libs.
37
38if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} [list debug ldflags=-Wl,-soname,${test}.so]] != ""} {
39    return -1
40}
41
42if {[build_executable ${test}.exp $binfile_test ${srcfile_test} {}] == -1} {
43    return -1
44}
45
46# Note: The separate debug info file content build-id/crc32 are not verified
47# contrary to the GDB search algorithm skipping non-matching ones.
48proc system_debug_get {exec} {
49    global debug_root
50
51    set exec_build_id_debug [build_id_debug_filename_get $exec]
52    set debug_base "[file tail $exec].debug"
53    set exec_dir [file dirname $exec]
54
55    # isfile returns 1 even for symlinks to files.
56    set retval $debug_root/$exec_build_id_debug
57    if [file isfile $retval] {
58	return $retval
59    }
60    set retval $exec_dir/$debug_base
61    if [file isfile $retval] {
62	return $retval
63    }
64    set retval $exec_dir/.debug/$debug_base
65    if [file isfile $retval] {
66	return $retval
67    }
68    set retval $debug_root/$exec_dir/$debug_base
69    if [file isfile $retval] {
70	return $retval
71    }
72    return ""
73}
74
75gdb_exit
76gdb_start
77set debug_root ""
78set test "show debug-file-directory"
79gdb_test_multiple $test $test {
80    -re "The directory where separate debug symbols are searched for is \"(.*)\".\r\n$gdb_prompt $" {
81	set debug_root $expect_out(1,string)
82    }
83}
84
85set interp_system [section_get ${objdir}/${subdir}/$binfile_test .interp]
86set interp_system_debug [system_debug_get $interp_system]
87verbose -log "$interp_system has debug $interp_system_debug"
88
89proc prelinkNO {arg {name ""}} {
90    return [prelink_no $arg $name]
91}
92
93proc prelinkYES {arg {name ""}} {
94    return [prelink_yes $arg $name]
95}
96
97proc strip_debug {dest} {
98    set test "strip [file tail $dest]"
99    set strip_program [transform strip]
100    set command "exec $strip_program --strip-debug $dest"
101    verbose -log "command is $command"
102    if [catch $command] {
103	fail $test
104	return 0
105    } else {
106    	pass $test
107	return 1
108    }
109}
110
111# Implementation of reach.
112
113proc reach_1 {func command displacement} {
114    global gdb_prompt expect_out
115
116    if {$func == "_dl_debug_state"} {
117	# Breakpoint on _dl_debug_state can have problems due to its overlap
118	# with the existing internal breakpoint from GDB.
119	gdb_test_no_output "set stop-on-solib-events 1"
120    } elseif {! [gdb_breakpoint $func allow-pending]} {
121	return
122    }
123
124    set test "reach"
125    set test_displacement "seen displacement message as $displacement"
126    set debug_state_count 0
127    gdb_test_multiple $command $test {
128	-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
129	    # Missing "$gdb_prompt $" is intentional.
130	    if {$expect_out(1,string) == "0x0"} {
131		set case "ZERO"
132	    } else {
133		set case "NONZERO"
134	    }
135	    if {$displacement == $case || $displacement == "PRESENT"} {
136		pass $test_displacement
137		set displacement "FOUND-$displacement"
138	    } else {
139		fail $test_displacement
140	    }
141	    exp_continue
142	}
143	-re "Breakpoint \[0-9\]+, \\.?(__GI_)?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
144	    if {$func == "_dl_debug_state"} {
145		fail $test
146	    } else {
147		pass $test
148	    }
149	}
150	-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?(__GI_)?$func \\(\\).*\r\n$gdb_prompt $" {
151	    if {$func == "_dl_debug_state"} {
152		fail $test
153	    } else {
154		pass $test
155	    }
156	}
157	-re "Stopped due to shared library event\r\n$gdb_prompt $" {
158	    if {$func == "_dl_debug_state"} {
159		if {$debug_state_count == 0} {
160		    # First stop does not yet relocate the _start function
161		    # descriptor on ppc64.
162		    set debug_state_count 1
163		    send_gdb "continue\n"
164		    exp_continue
165		} else {
166		    pass $test
167		}
168	    } else {
169		fail $test
170	    }
171	}
172    }
173    if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
174	fail $test_displacement
175    }
176
177    if {$func == "_dl_debug_state"} {
178	gdb_test_no_output "set stop-on-solib-events 0"
179    }
180}
181
182# `runto' does not check we stopped really at the function we specified.
183# DISPLACEMENT can be "NONE" for no message to be present, "ZERO" for
184# displacement of 0 bytes to be present, "NONZERO" for displacement of non-0
185# bytes to be present and "PRESENT" if both "ZERO" and "NONZERO" are valid.
186proc reach {func command displacement} {
187    global pf_prefix
188    set old_ldprefix $pf_prefix
189    lappend pf_prefix "reach-$func:"
190
191    reach_1 $func $command $displacement
192
193    set pf_prefix $old_ldprefix
194}
195
196proc test_core {file displacement} {
197    global srcdir subdir gdb_prompt expect_out
198
199    set corefile [core_find $file {} "segv"]
200    if {$corefile == ""} {
201	return
202    }
203
204    global pf_prefix
205    set old_ldprefix $pf_prefix
206    lappend pf_prefix "core:"
207
208    gdb_exit
209    gdb_start
210    # Clear it to never find any separate debug infos in $debug_root.
211    gdb_test_no_output "set debug-file-directory" \
212	"set debug-file-directory for core"
213    gdb_reinitialize_dir $srcdir/$subdir
214    gdb_load $file
215
216    # Print the "PIE (Position Independent Executable) displacement" message.
217    gdb_test_no_output "set verbose on"
218
219    set test "core loaded"
220    set test_displacement "seen displacement message as $displacement"
221    gdb_test_multiple "core-file $corefile" $test {
222	-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
223	    # Missing "$gdb_prompt $" is intentional.
224	    if {$expect_out(1,string) == "0x0"} {
225		set case "ZERO"
226	    } else {
227		set case "NONZERO"
228	    }
229	    if {$displacement == $case || $displacement == "PRESENT"} {
230		pass $test_displacement
231		set displacement "FOUND-$displacement"
232	    } else {
233		fail $test_displacement
234	    }
235	    exp_continue
236	}
237	-re "Core was generated by .*\r\n#0 .*$gdb_prompt $" {
238	    # Do not check the binary filename as it may be truncated.
239	    pass $test
240	}
241    }
242    if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
243	fail $test_displacement
244    }
245
246    gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain\\M.*" "core main bt"
247
248    set pf_prefix $old_ldprefix
249}
250
251proc test_attach_gdb {file pid displacement prefix} {
252    global gdb_prompt expect_out
253
254    global pf_prefix
255    set old_ldprefix $pf_prefix
256    lappend pf_prefix "$prefix:"
257
258    gdb_exit
259    gdb_start
260
261    # Print the "PIE (Position Independent Executable) displacement" message.
262    gdb_test_no_output "set verbose on"
263
264    if {$file != ""} {
265	gdb_test "file $file" "Reading symbols from .*done\\." "file"
266    }
267
268    set test "attach"
269    gdb_test_multiple "attach $pid" $test {
270	-re "Attaching to (program: .*, )?process $pid\r\n" {
271	    # Missing "$gdb_prompt $" is intentional.
272	    pass $test
273	}
274    }
275
276    set test "attach final prompt"
277    set test_displacement "seen displacement message as $displacement"
278    gdb_test_multiple "" $test {
279	-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
280	    # Missing "$gdb_prompt $" is intentional.
281	    if {$expect_out(1,string) == "0x0"} {
282		set case "ZERO"
283	    } else {
284		set case "NONZERO"
285	    }
286	    if {$displacement == $case || $displacement == "PRESENT"} {
287		pass $test_displacement
288		set displacement "FOUND-$displacement"
289	    } else {
290		fail $test_displacement
291	    }
292	    exp_continue
293	}
294	-re "$gdb_prompt $" {
295	    pass $test
296	}
297    }
298    if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
299	fail $test_displacement
300    }
301
302    gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain\\M.*" "attach main bt"
303    gdb_exit
304
305    set pf_prefix $old_ldprefix
306}
307
308proc test_attach {file displacement {relink_args ""}} {
309    global board_info
310
311    gdb_exit
312
313    set test "sleep function started"
314
315    set command "${file} sleep"
316    set res [remote_spawn host $command];
317    if { $res < 0 || $res == "" } {
318	perror "Spawning $command failed."
319	fail $test
320	return
321    }
322    set pid [exp_pid -i $res]
323    gdb_expect {
324	-re "sleeping\r\n" {
325	    pass $test
326	}
327	eof {
328	    fail "$test (eof)"
329	    return
330	}
331	timeout {
332	    fail "$test (timeout)"
333	    return
334	}
335    }
336
337    if {$relink_args == ""} {
338	test_attach_gdb "" $pid $displacement "attach"
339    } else {
340	# These could be rather passed as arguments.
341	global exec interp_saved interp
342
343	foreach relink {YES NO} {
344	    # Formerly this test was testing only prelinking of $EXEC.  As the
345	    # prelink command automatically prelinks all of $EXEC's libraries,
346	    # even $INTERP got prelinked.  Therefore, we formerly had to
347	    # `[file_copy $interp_saved $interp]' to make $INTERP not affected
348	    # by this prelinking of $EXEC.
349	    #
350	    # But now we need to test even prelinking of $INTERP.  We could
351	    # create a separate test to test just the $INTERP prelinking.  For
352	    # test simplicity, we merged this test and the test above by not
353	    # restoring $INTERP after $EXEC prelink.  $INTERP gets restored
354	    # later below.
355
356	    if [prelink$relink $relink_args [file tail $exec]] {
357		# /proc/PID/exe cannot be loaded as it is "EXECNAME (deleted)".
358		test_attach_gdb $exec $pid $displacement "attach-relink$relink"
359	    }
360	}
361	file_copy $interp_saved $interp
362    }
363
364    remote_exec host "kill -9 $pid"
365}
366
367proc test_ld {file ifmain trynosym displacement} {
368    global srcdir subdir gdb_prompt expect_out inferior_exited_re
369
370    # First test normal `file'-command loaded $FILE with symbols.
371
372    gdb_exit
373    gdb_start
374    # Clear it to never find any separate debug infos in $debug_root.
375    gdb_test_no_output "set debug-file-directory"
376    gdb_reinitialize_dir $srcdir/$subdir
377    gdb_load $file
378
379    # Print the "PIE (Position Independent Executable) displacement" message.
380    gdb_test_no_output "set verbose on"
381
382    # We want to test the re-run of a PIE in the case where the executable
383    # is loaded with a different displacement, but disable-randomization
384    # prevents that from happening.  So turn it off.
385    gdb_test "set disable-randomization off"
386
387    if $ifmain {
388	gdb_test_no_output "set args segv"
389    } else {
390	global objdir binfile_test
391
392	# ld.so needs some executable to run to reach _dl_debug_state.
393	gdb_test_no_output "set args ${objdir}/${subdir}/$binfile_test" "set args OBJDIR/${subdir}/$binfile_test"
394    }
395
396    reach "_dl_debug_state" "run" $displacement
397
398    gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?_dl_debug_state\\M.*" "dl bt"
399
400    if $ifmain {
401	reach "main" continue "NONE"
402
403	reach "libfunc" continue "NONE"
404
405	gdb_test "bt" "#0 +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#1 +\[^\r\n\]*\\mmain\\M.*" "main bt"
406    }
407
408    # Try re-run if the new PIE displacement takes effect.
409    gdb_test "kill" "" "kill" {Kill the program being debugged\? \(y or n\) } "y"
410    reach "_dl_debug_state" "run" $displacement
411
412    if $ifmain {
413	test_core $file $displacement
414
415	test_attach $file $displacement
416    }
417
418    if !$trynosym {
419	return
420    }
421
422    global pf_prefix
423    set old_ldprefix $pf_prefix
424    lappend pf_prefix "symbol-less:"
425
426    # Test also `exec-file'-command loaded $FILE - therefore without symbols.
427    # SYMBOL_OBJFILE is not available and only EXEC_BFD must be used.
428
429    gdb_exit
430    gdb_start
431    # Clear it to never find any separate debug infos in $debug_root.
432    gdb_test_no_output "set debug-file-directory"
433    gdb_reinitialize_dir $srcdir/$subdir
434
435    # Print the "PIE (Position Independent Executable) displacement" message.
436    gdb_test_no_output "set verbose on"
437
438    # Test no (error) message has been printed by `exec-file'.
439    set escapedfile [string_to_regexp $file]
440    gdb_test "exec-file $file" "exec-file $escapedfile" "load"
441
442    if $ifmain {
443	reach "_dl_debug_state" run $displacement
444
445	# Use two separate gdb_test_multiple statements to avoid timeouts due
446	# to slow processing of wildcard capturing long output
447	set test "info files"
448	set entrynohex ""
449	gdb_test_multiple $test $test {
450	    -re "\r\n\[\t \]*Entry point:\[\t \]*0x(\[0-9a-f\]+)\r\n" {
451		set entrynohex $expect_out(1,string)
452		gdb_test_multiple "" $test {
453		    -re "\r\n$gdb_prompt $" {
454			pass $test
455		    }
456		}
457	    }
458	}
459
460	# `info sym' cannot be tested for .opd as the binary may not have
461	# symbols.
462	if {[istarget powerpc64-*] && [is_lp64_target]} {
463	    set test "convert entry point"
464	    gdb_test_multiple "p *(void(*)(void) *) 0x$entrynohex" $test {
465		-re " =( \\(\[^0-9\]*\\))? 0x(\[0-9a-f\]+)( < \[^\r\n\]*)?\r\n$gdb_prompt $" {
466		    set entrynohex $expect_out(2,string)
467		    pass $test
468		}
469	    }
470	}
471	if {$entrynohex != ""} {
472	    gdb_test "break *0x$entrynohex" "" "break at entry point"
473	    gdb_test "continue" "\r\nBreakpoint \[0-9\]+, 0x0*$entrynohex in .*" "entry point reached"
474	}
475    } else {
476	# There is no symbol to break at ld.so.  Moreover it can exit with an
477	# error code.
478
479	set test "ld.so exit"
480	set test_displacement "seen displacement message as $displacement"
481	gdb_test_multiple "run" $test {
482	    -re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
483		# Missing "$gdb_prompt $" is intentional.
484		if {$expect_out(1,string) == "0x0"} {
485		    set case "ZERO"
486		} else {
487		    set case "NONZERO"
488		}
489		if {$displacement == $case || $displacement == "PRESENT"} {
490		    pass $test_displacement
491		    set displacement "FOUND-$displacement"
492		} else {
493		    fail $test_displacement
494		}
495		exp_continue
496	    }
497	    -re "$inferior_exited_re (normally|with code \[0-9\]+).\r\n$gdb_prompt $" {
498		# Do not check the binary filename as it may be truncated.
499		pass $test
500	    }
501	}
502	if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
503	    fail $test_displacement
504	}
505    }
506
507    set pf_prefix $old_ldprefix
508}
509
510# Create separate binaries for each testcase - to make the possible reported
511# problem reproducible after the whole test run finishes.
512
513set old_ldprefix $pf_prefix
514foreach ldprelink {NO YES} {
515    foreach ldsepdebug {NO IN SEP} {
516	# Skip running the ldsepdebug test if we do not have system separate
517	# debug info available.
518	if {$interp_system_debug == "" && $ldsepdebug == "SEP"} {
519	    continue
520	}
521
522	set ldname "LDprelink${ldprelink}debug${ldsepdebug}"
523	set interp $binprefix-$ldname
524
525	# prelink needs to always prelink all the dependencies to do any file
526	# modifications of its files.  ld.so also needs all the dependencies to
527	# be prelinked to omit the relocation process.  In-memory file offsets
528	# are not dependent whether ld.so went the prelink way or through the
529	# relocation process.
530	#
531	# For GDB we are not interested whether prelink succeeds as it is
532	# transparent to GDB.  GDB is being tested for differences of file
533	# offsets vs. in-memory offsets.  So we have to prelink even ld.so for
534	# the BIN modification to happen but we need to restore the original
535	# possibly unprelinked ld.so to test all the combinations for GDB.
536	set interp_saved ${interp}-saved
537
538	set pf_prefix $old_ldprefix
539	lappend pf_prefix "$ldname:"
540
541	if {$ldsepdebug == "NO"} {
542	    file_copy $interp_system $interp
543	    # Never call strip-debug before unprelink:
544	    # prelink: ...: Section .note.gnu.build-id created after prelinking
545	    if ![prelinkNO $interp] {
546		continue
547	    }
548	    strip_debug $interp
549	} elseif {$ldsepdebug == "IN" && $interp_system_debug == ""} {
550	    file_copy $interp_system $interp
551	} elseif {$ldsepdebug == "IN" && $interp_system_debug != ""} {
552	    file_copy $interp_system $interp
553	    file_copy $interp_system_debug "${interp}.debug"
554	    # eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
555	    if {![prelinkNO $interp] || ![prelinkNO "${interp}.debug"]} {
556		continue
557	    }
558	    set test "eu-unstrip unprelinked:[file tail $interp_system] + [file tail $interp_system_debug] to [file tail $interp]"
559	    set command "exec eu-unstrip -o $interp $interp ${interp}.debug"
560	    verbose -log "command is $command"
561	    if [catch $command] {
562		setup_xfail *-*-*
563		fail $test
564		continue
565	    } else {
566		pass $test
567	    }
568	} elseif {$ldsepdebug == "SEP" && $interp_system_debug == ""} {
569	    file_copy $interp_system $interp
570	    # eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
571	    if ![prelinkNO $interp] {
572		continue
573	    }
574	    gdb_gnu_strip_debug $interp
575	} elseif {$ldsepdebug == "SEP" && $interp_system_debug != ""} {
576	    file_copy $interp_system $interp
577	    file_copy $interp_system_debug "${interp}.debug"
578	}
579
580	if {$ldsepdebug == "SEP"} {
581	    if ![prelinkNO "${interp}.debug"] {
582		continue
583	    }
584	} else {
585	    file delete "${interp}.debug"
586	}
587
588	if ![prelink$ldprelink $interp] {
589	    continue
590	}
591	if {$ldprelink == "NO"} {
592	    set displacement "NONZERO"
593	} else {
594	    # x86* kernel loads prelinked PIE binary at its prelinked address
595	    # but ppc* kernel loads it at a random address.  prelink normally
596	    # skips PIE binaries during the system scan.
597	    set displacement "PRESENT"
598	}
599	test_ld $interp 0 [expr {$ldsepdebug == "NO"}] $displacement
600
601	if ![file_copy $interp $interp_saved] {
602	    continue
603	}
604	set old_binprefix $pf_prefix
605	foreach binprelink {NO YES} {
606	    foreach binsepdebug {NO IN SEP} {
607		# "ATTACH" is like "YES" but it is modified during run.
608		# It cannot be used for problem reproducibility after the
609		# testcase ends.
610		foreach binpie {NO YES ATTACH} {
611		    # This combination is not possible, non-PIE (fixed address)
612		    # binary cannot be prelinked to any (other) address.
613		    if {$binprelink == "YES" && $binpie == "NO"} {
614			continue
615		    }
616
617		    set binname "BINprelink${binprelink}debug${binsepdebug}pie${binpie}"
618		    set exec $binprefix-$binname
619
620		    set pf_prefix $old_binprefix
621		    lappend pf_prefix "$binname:"
622
623		    set opts "ldflags=-Wl,$binfile_lib,-rpath,[file dirname $binfile_lib]"
624		    if {$binsepdebug != "NO"} {
625			lappend opts {debug}
626		    }
627		    if {$binpie != "NO"} {
628			lappend opts {additional_flags=-fPIE -pie}
629		    }
630
631		    set dir ${exec}.d
632		    set relink_args [build_executable_own_libs ${test}.exp [file tail $exec] $srcfile $opts $interp $dir]
633		    if {$relink_args == ""} {
634			continue;
635		    }
636
637		    if {$binsepdebug == "SEP"} {
638			gdb_gnu_strip_debug $exec
639		    }
640
641		    if {$binpie == "NO"} {
642			set displacement "NONE"
643		    } elseif {$binprelink == "NO"} {
644			set displacement "NONZERO"
645		    } else {
646			# x86* kernel loads prelinked PIE binary at its
647			# prelinked address but ppc* kernel loads it at
648			# a random address.  prelink normally skips PIE
649			# binaries during the system scan.
650			set displacement "PRESENT"
651		    }
652
653		    if {[prelink$binprelink $relink_args [file tail $exec]]
654		        && [file_copy $interp_saved $interp]} {
655			if {$binpie != "ATTACH"} {
656			    test_ld $exec 1 [expr {$binsepdebug == "NO"}] $displacement
657			} else {
658			    # If the file has been randomly prelinked it must
659			    # be "NONZERO".  We could see "ZERO" only if it was
660			    # unprelinked and it is now running at the same
661			    # address - which is 0 but executable can never run
662			    # at address 0.
663
664			    set displacement "NONZERO"
665			    test_attach $exec $displacement $relink_args
666
667			    # ATTACH means that executables and libraries have
668			    # been modified after they have been run.  They
669			    # cannot be reused for problem reproducibility after
670			    # the testcase ends in the ATTACH case.  Therefore
671			    # they are rather deleted not to confuse after the
672			    # run finishes.
673			    set exec_debug [system_debug_get $exec]
674			    if {$exec_debug != ""} {
675				# `file delete [glob "${exec_debug}*"]' does not work.
676				foreach f [glob "${exec_debug}*"] {
677				    file delete $f
678				}
679			    }
680			    file delete -force $dir
681			    # `file delete [glob "${exec}*"]' does not work.
682			    foreach f [glob "${exec}*"] {
683				file delete $f
684			    }
685			}
686		    }
687		}
688	    }
689	}
690
691	file delete $interp_saved
692    }
693}
694set pf_prefix $old_ldprefix
695