2c8c5d375e
The buildbots show that attach-many-short-lived-thread.exp is racy. But after staring at debug logs and playing with SystemTap scripts for a (long) while, I figured out that neither GDB, nor the kernel nor the test's program itself are at fault. The problem is simply that the testsuite machinery is currently subject to PID-reuse races. The attach-many-short-lived-threads.c test program just happens to be much more susceptible to trigger this race because threads and processes share the same number space on Linux, and the test spawns many many short lived threads in succession, thus enlarging the race window a lot. Part of the problem is that several tests spawn processes with "exec&" (in order to test the "attach" command) , and then at the end of the test, to make sure things are cleaned up, issue a 'remote_spawn "kill -p $testpid"'. Since with tcl's "exec&", tcl itself is responsible for reaping the process's exit status, when we go kill the process, testpid may have already exited _and_ its status may have (and often has) been reaped already. Thus it can happen that another process meanwhile reuses $testpid, and that "kill" command kills the wrong process... Frequently, that happens to be attach-many-short-lived-thread, but this explains other test's races as well. In the attach-many-short-lived-threads test, it sometimes manifests like this: (gdb) file /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-many-short-lived-threads Reading symbols from /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-many-short-lived-threads...done. (gdb) Loaded /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-many-short-lived-threads into /home/pedro/gdb/mygit/build/gdb/testsuite/../../gdb/gdb attach 5940 Attaching to program: /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/attach-many-short-lived-threads, process 5940 warning: process 5940 is a zombie - the process has already terminated ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptrace: Operation not permitted. (gdb) PASS: gdb.threads/attach-many-short-lived-threads.exp: iter 1: attach info threads No threads. (gdb) PASS: gdb.threads/attach-many-short-lived-threads.exp: iter 1: no new threads set breakpoint always-inserted on (gdb) PASS: gdb.threads/attach-many-short-lived-threads.exp: iter 1: set breakpoint always-inserted on Other times the process dies while the test is ongoing (the process is ptrace-stopped): (gdb) print again = 1 Cannot access memory at address 0x6020cc (gdb) FAIL: gdb.threads/attach-many-short-lived-threads.exp: iter 2: reset timer in the inferior (Recall that on Linux, SIGKILL is not interceptable) And other times it dies just while we're detaching: $4 = 319 (gdb) PASS: gdb.threads/attach-many-short-lived-threads.exp: iter 2: print seconds_left detach Can't detach Thread 0x7fb13b7de700 (LWP 1842): No such process (gdb) FAIL: gdb.threads/attach-many-short-lived-threads.exp: iter 2: detach GDB mishandles the latter (it should ignore ESRCH while detaching just like when continuing), but that's another story. The fix here is to change spawn_wait_for_attach to use Expect's 'spawn' command instead of Tcl's 'exec&' to spawn programs, because with spawn we control when to wait for/reap the process. That allows killing the process by PID without being subject to pid-reuse races, because even if the process is already dead, the kernel won't reuse the process's PID until the zombie is reaped. The other part of the problem lies in DejaGnu itself, unfortunately. I have occasionally seen tests (attach-many-short-lived-threads included, but not only that one) die with a random inexplicable SIGTERM too, and that too is caused by the same reason, except that in that case, the rogue SIGTERM is sent from this bit in DejaGnu's remote.exp: exec sh -c "exec > /dev/null 2>&1 && (kill -2 $pgid || kill -2 $pid) && sleep 5 && (kill $pgid || kill $pid) && sleep 5 && (kill -9 $pgid || kill -9 $pid) &" ... catch "wait -i $shell_id" Even if the program exits promptly, that whole cascade of kills carries on in the background, thus potentially killing the poor process that manages to reuse $pid... I sent a fix for that to the DejaGnu list: http://lists.gnu.org/archive/html/dejagnu/2015-07/msg00000.html With both patches in place, I haven't seen attach-many-short-lived-threads.exp fail again. Tested on x86_64 Fedora 20, native, gdbserver and extended-gdbserver. gdb/testsuite/ChangeLog: 2015-07-31 Pedro Alves <palves@redhat.com> * gdb.base/attach-pie-misread.exp: Rename $res to $test_spawn_id. Use spawn_id_get_pid. Wait for spawn id after eof. Use kill_wait_spawned_process instead of explicit "kill -9". * gdb.base/attach-pie-noexec.exp: Adjust to spawn_wait_for_attach returning a spawn id instead of a pid. Use spawn_id_get_pid and kill_wait_spawned_process. * gdb.base/attach-twice.exp: Likewise. * gdb.base/attach.exp: Likewise. (do_command_attach_tests): Use gdb_spawn_with_cmdline_opts and gdb_test_multiple. * gdb.base/solib-overlap.exp: Adjust to spawn_wait_for_attach returning a spawn id instead of a pid. Use spawn_id_get_pid and kill_wait_spawned_process. * gdb.base/valgrind-infcall.exp: Likewise. * gdb.multi/multi-attach.exp: Likewise. * gdb.python/py-prompt.exp: Likewise. * gdb.python/py-sync-interp.exp: Likewise. * gdb.server/ext-attach.exp: Likewise. * gdb.threads/attach-into-signal.exp (corefunc): Use spawn_wait_for_attach, spawn_id_get_pid and kill_wait_spawned_process. * gdb.threads/attach-many-short-lived-threads.exp: Adjust to spawn_wait_for_attach returning a spawn id instead of a pid. Use spawn_id_get_pid and kill_wait_spawned_process. * gdb.threads/attach-stopped.exp (corefunc): Use spawn_wait_for_attach, spawn_id_get_pid and kill_wait_spawned_process. * gdb.base/break-interp.exp: Rename $res to $test_spawn_id. Use spawn_id_get_pid. Wait for spawn id after eof. Use kill_wait_spawned_process instead of explicit "kill -9". * lib/gdb.exp (can_spawn_for_attach): Adjust comment. (kill_wait_spawned_process, spawn_id_get_pid): New procedures. (spawn_wait_for_attach): Use spawn instead of exec to spawn processes. Don't map cygwin/windows pids here. Now returns a spawn id list.
692 lines
21 KiB
Text
692 lines
21 KiB
Text
# Copyright 2010-2015 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 only works on GNU/Linux.
|
|
if { ![isnative] || [is_remote host] || [target_info exists use_gdb_stub]
|
|
|| ![istarget *-linux*] || [skip_shlib_tests]} {
|
|
continue
|
|
}
|
|
|
|
load_lib prelink-support.exp
|
|
|
|
set test "break-interp"
|
|
set binprefix [standard_output_file ${test}]
|
|
# Only to get the $interp_system name.
|
|
set srcfile_test "start.c"
|
|
set binfile_test ${test}-test
|
|
set binfile_lib ${binprefix}.so
|
|
set srcfile "${test}-main.c"
|
|
set srcfile_lib "${test}-lib.c"
|
|
|
|
if [get_compiler_info] {
|
|
return -1
|
|
}
|
|
|
|
# Use -soname so that the new library gets copied by build_executable_own_libs.
|
|
|
|
if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} [list debug ldflags=-Wl,-soname,${test}.so]] != ""} {
|
|
return -1
|
|
}
|
|
|
|
if {[build_executable ${test}.exp $binfile_test ${srcfile_test} {}] == -1} {
|
|
return -1
|
|
}
|
|
|
|
# Note: The separate debug info file content build-id/crc32 are not verified
|
|
# contrary to the GDB search algorithm skipping non-matching ones.
|
|
proc system_debug_get {exec} {
|
|
global debug_root
|
|
|
|
set exec_build_id_debug [build_id_debug_filename_get $exec]
|
|
set debug_base "[file tail $exec].debug"
|
|
set exec_dir [file dirname $exec]
|
|
|
|
# isfile returns 1 even for symlinks to files.
|
|
set retval $debug_root/$exec_build_id_debug
|
|
if [file isfile $retval] {
|
|
return $retval
|
|
}
|
|
set retval $exec_dir/$debug_base
|
|
if [file isfile $retval] {
|
|
return $retval
|
|
}
|
|
set retval $exec_dir/.debug/$debug_base
|
|
if [file isfile $retval] {
|
|
return $retval
|
|
}
|
|
set retval $debug_root/$exec_dir/$debug_base
|
|
if [file isfile $retval] {
|
|
return $retval
|
|
}
|
|
return ""
|
|
}
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
set debug_root ""
|
|
set test "show debug-file-directory"
|
|
gdb_test_multiple $test $test {
|
|
-re "The directory where separate debug symbols are searched for is \"(.*)\".\r\n$gdb_prompt $" {
|
|
set debug_root $expect_out(1,string)
|
|
}
|
|
}
|
|
|
|
set interp_system [section_get [standard_output_file $binfile_test] .interp]
|
|
set interp_system_debug [system_debug_get $interp_system]
|
|
verbose -log "$interp_system has debug $interp_system_debug"
|
|
|
|
proc prelinkNO {arg {name ""}} {
|
|
return [prelink_no $arg $name]
|
|
}
|
|
|
|
proc prelinkYES {arg {name ""}} {
|
|
return [prelink_yes $arg $name]
|
|
}
|
|
|
|
proc strip_debug {dest} {
|
|
set test "strip [file tail $dest]"
|
|
set strip_program [transform strip]
|
|
set command "exec $strip_program --strip-debug $dest"
|
|
verbose -log "command is $command"
|
|
if [catch $command] {
|
|
fail $test
|
|
return 0
|
|
} else {
|
|
pass $test
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# The marker function for the standard runtime linker interface is
|
|
# _dl_debug_state. The probes-based interface has no specific marker
|
|
# function; the probe we will stop on (init_start) is in dl_main so we
|
|
# check for that.
|
|
|
|
set solib_bp {(_dl_debug_state|dl_main)}
|
|
|
|
# Implementation of reach.
|
|
|
|
proc reach_1 {func command displacement} {
|
|
global gdb_prompt expect_out solib_bp
|
|
|
|
if {$func == $solib_bp} {
|
|
# Breakpoint on _dl_debug_state can have problems due to its overlap
|
|
# with the existing internal breakpoint from GDB.
|
|
gdb_test_no_output "set stop-on-solib-events 1"
|
|
} elseif {! [gdb_breakpoint $func allow-pending]} {
|
|
return
|
|
}
|
|
|
|
set test "reach"
|
|
set test_displacement "seen displacement message as $displacement"
|
|
set debug_state_count 0
|
|
gdb_test_multiple $command $test {
|
|
-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
|
|
# Missing "$gdb_prompt $" is intentional.
|
|
if {$expect_out(1,string) == "0x0"} {
|
|
set case "ZERO"
|
|
} else {
|
|
set case "NONZERO"
|
|
}
|
|
if {$displacement == $case || $displacement == "PRESENT"} {
|
|
pass $test_displacement
|
|
set displacement "FOUND-$displacement"
|
|
} else {
|
|
fail $test_displacement
|
|
}
|
|
exp_continue
|
|
}
|
|
-re "Breakpoint \[0-9\]+, \\.?(__GI_)?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
|
|
if {$func == $solib_bp} {
|
|
fail $test
|
|
} else {
|
|
pass $test
|
|
}
|
|
}
|
|
-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?(__GI_)?$func \\(\\).*\r\n$gdb_prompt $" {
|
|
if {$func == $solib_bp} {
|
|
fail $test
|
|
} else {
|
|
pass $test
|
|
}
|
|
}
|
|
-re "Stopped due to (spurious )?shared library event.*\r\n$gdb_prompt $" {
|
|
if {$func == $solib_bp} {
|
|
if {$debug_state_count == 0} {
|
|
# First stop does not yet relocate the _start function
|
|
# descriptor on ppc64.
|
|
set debug_state_count 1
|
|
send_gdb "continue\n"
|
|
exp_continue
|
|
} else {
|
|
pass $test
|
|
}
|
|
} else {
|
|
fail $test
|
|
}
|
|
}
|
|
}
|
|
if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
|
|
fail $test_displacement
|
|
}
|
|
|
|
if {$func == $solib_bp} {
|
|
gdb_test_no_output "set stop-on-solib-events 0"
|
|
}
|
|
}
|
|
|
|
# `runto' does not check we stopped really at the function we specified.
|
|
# DISPLACEMENT can be "NONE" for no message to be present, "ZERO" for
|
|
# displacement of 0 bytes to be present, "NONZERO" for displacement of non-0
|
|
# bytes to be present and "PRESENT" if both "ZERO" and "NONZERO" are valid.
|
|
proc reach {func command displacement} {
|
|
with_test_prefix "reach-$func" {
|
|
reach_1 $func $command $displacement
|
|
}
|
|
}
|
|
|
|
proc test_core {file displacement} {
|
|
with_test_prefix "core" {
|
|
global srcdir subdir gdb_prompt expect_out
|
|
|
|
set corefile [core_find $file {} "segv"]
|
|
if {$corefile == ""} {
|
|
return
|
|
}
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
# Clear it to never find any separate debug infos in $debug_root.
|
|
gdb_test_no_output "set debug-file-directory" \
|
|
"set debug-file-directory for core"
|
|
gdb_reinitialize_dir $srcdir/$subdir
|
|
gdb_load $file
|
|
|
|
# Print the "PIE (Position Independent Executable) displacement" message.
|
|
gdb_test_no_output "set verbose on"
|
|
|
|
set test "core loaded"
|
|
set test_displacement "seen displacement message as $displacement"
|
|
gdb_test_multiple "core-file $corefile" $test {
|
|
-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
|
|
# Missing "$gdb_prompt $" is intentional.
|
|
if {$expect_out(1,string) == "0x0"} {
|
|
set case "ZERO"
|
|
} else {
|
|
set case "NONZERO"
|
|
}
|
|
if {$displacement == $case || $displacement == "PRESENT"} {
|
|
pass $test_displacement
|
|
set displacement "FOUND-$displacement"
|
|
} else {
|
|
fail $test_displacement
|
|
}
|
|
exp_continue
|
|
}
|
|
-re "Core was generated by .*\r\n#0 .*$gdb_prompt $" {
|
|
# Do not check the binary filename as it may be truncated.
|
|
pass $test
|
|
}
|
|
}
|
|
if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
|
|
fail $test_displacement
|
|
}
|
|
|
|
gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain\\M.*" "core main bt"
|
|
}
|
|
}
|
|
|
|
proc test_attach_gdb {file pid displacement prefix} {
|
|
with_test_prefix "$prefix" {
|
|
global gdb_prompt expect_out
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
|
|
# Print the "PIE (Position Independent Executable) displacement" message.
|
|
gdb_test_no_output "set verbose on"
|
|
|
|
gdb_test "file $file" "Reading symbols from .*done\\." "file"
|
|
|
|
set test "attach"
|
|
gdb_test_multiple "attach $pid" $test {
|
|
-re "Attaching to (program: .*, )?process $pid\r\n" {
|
|
# Missing "$gdb_prompt $" is intentional.
|
|
pass $test
|
|
}
|
|
}
|
|
|
|
set test "attach final prompt"
|
|
set test_displacement "seen displacement message as $displacement"
|
|
gdb_test_multiple "" $test {
|
|
-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
|
|
# Missing "$gdb_prompt $" is intentional.
|
|
if {$expect_out(1,string) == "0x0"} {
|
|
set case "ZERO"
|
|
} else {
|
|
set case "NONZERO"
|
|
}
|
|
if {$displacement == $case || $displacement == "PRESENT"} {
|
|
pass $test_displacement
|
|
set displacement "FOUND-$displacement"
|
|
} else {
|
|
fail $test_displacement
|
|
}
|
|
exp_continue
|
|
}
|
|
-re "$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
|
|
fail $test_displacement
|
|
}
|
|
|
|
gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain\\M.*" "attach main bt"
|
|
gdb_exit
|
|
}
|
|
}
|
|
|
|
proc test_attach {file displacement {relink_args ""}} {
|
|
global board_info
|
|
global exec
|
|
|
|
gdb_exit
|
|
|
|
set test "sleep function started"
|
|
|
|
set command "${file} sleep"
|
|
set test_spawn_id [remote_spawn host $command]
|
|
if { $test_spawn_id < 0 || $test_spawn_id == "" } {
|
|
perror "Spawning $command failed."
|
|
fail $test
|
|
return
|
|
}
|
|
set pid [spawn_id_get_pid $test_spawn_id]
|
|
gdb_expect {
|
|
-re "sleeping\r\n" {
|
|
pass $test
|
|
}
|
|
eof {
|
|
fail "$test (eof)"
|
|
wait -i $test_spawn_id
|
|
return
|
|
}
|
|
timeout {
|
|
fail "$test (timeout)"
|
|
kill_wait_spawned_process $test_spawn_id
|
|
return
|
|
}
|
|
}
|
|
|
|
if {$relink_args == ""} {
|
|
test_attach_gdb $exec $pid $displacement "attach"
|
|
} else {
|
|
# These could be rather passed as arguments.
|
|
global interp_saved interp
|
|
|
|
foreach relink {YES NO} {
|
|
# Formerly this test was testing only prelinking of $EXEC. As the
|
|
# prelink command automatically prelinks all of $EXEC's libraries,
|
|
# even $INTERP got prelinked. Therefore, we formerly had to
|
|
# `[file_copy $interp_saved $interp]' to make $INTERP not affected
|
|
# by this prelinking of $EXEC.
|
|
#
|
|
# But now we need to test even prelinking of $INTERP. We could
|
|
# create a separate test to test just the $INTERP prelinking. For
|
|
# test simplicity, we merged this test and the test above by not
|
|
# restoring $INTERP after $EXEC prelink. $INTERP gets restored
|
|
# later below.
|
|
#
|
|
# `(wrong library or version mismatch?)' messages are printed for
|
|
# $binfile_lib on platforms converting REL->RELA relocations by
|
|
# prelink (such as on i386). There is no reliable way to verify
|
|
# the library file matches the running library in such case but
|
|
# GDB at least attempts to set the right displacement. We test
|
|
# `libfunc' is present in the backtrace and therefore the
|
|
# displacement has been guessed right.
|
|
|
|
if [prelink$relink $relink_args [file tail $exec]] {
|
|
# /proc/PID/exe cannot be loaded as it is "EXECNAME (deleted)".
|
|
test_attach_gdb $exec $pid $displacement "attach-relink$relink"
|
|
}
|
|
}
|
|
file_copy $interp_saved $interp
|
|
}
|
|
|
|
kill_wait_spawned_process $test_spawn_id
|
|
}
|
|
|
|
proc test_ld {file ifmain trynosym displacement} {
|
|
global srcdir subdir gdb_prompt expect_out inferior_exited_re solib_bp
|
|
|
|
# First test normal `file'-command loaded $FILE with symbols.
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
# Clear it to never find any separate debug infos in $debug_root.
|
|
gdb_test_no_output "set debug-file-directory"
|
|
gdb_reinitialize_dir $srcdir/$subdir
|
|
gdb_load $file
|
|
|
|
# Print the "PIE (Position Independent Executable) displacement" message.
|
|
gdb_test_no_output "set verbose on"
|
|
|
|
# We want to test the re-run of a PIE in the case where the executable
|
|
# is loaded with a different displacement, but disable-randomization
|
|
# prevents that from happening. So turn it off.
|
|
gdb_test "set disable-randomization off"
|
|
|
|
if $ifmain {
|
|
gdb_test_no_output "set args segv"
|
|
} else {
|
|
global binfile_test
|
|
|
|
# ld.so needs some executable to run to reach _dl_debug_state.
|
|
gdb_test_no_output "set args [standard_output_file $binfile_test]" \
|
|
"set args OBJDIR/${subdir}/$binfile_test"
|
|
}
|
|
|
|
reach $solib_bp "run" $displacement
|
|
|
|
gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?$solib_bp\\M.*" "dl bt"
|
|
|
|
if $ifmain {
|
|
reach "main" continue "NONE"
|
|
|
|
reach "libfunc" continue "NONE"
|
|
|
|
gdb_test "bt" "#0 +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#1 +\[^\r\n\]*\\mmain\\M.*" "main bt"
|
|
}
|
|
|
|
# Try re-run if the new PIE displacement takes effect.
|
|
gdb_test "kill" "" "kill" {Kill the program being debugged\? \(y or n\) } "y"
|
|
reach $solib_bp "run" $displacement
|
|
|
|
if $ifmain {
|
|
test_core $file $displacement
|
|
|
|
test_attach $file $displacement
|
|
}
|
|
|
|
if !$trynosym {
|
|
return
|
|
}
|
|
|
|
with_test_prefix "symbol-less" {
|
|
# Test also `exec-file'-command loaded $FILE - therefore
|
|
# without symbols. SYMBOL_OBJFILE is not available and only
|
|
# EXEC_BFD must be used.
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
# Clear it to never find any separate debug infos in $debug_root.
|
|
gdb_test_no_output "set debug-file-directory"
|
|
gdb_reinitialize_dir $srcdir/$subdir
|
|
|
|
# Print the "PIE (Position Independent Executable)
|
|
# displacement" message.
|
|
gdb_test_no_output "set verbose on"
|
|
|
|
# Test no (error) message has been printed by `exec-file'.
|
|
set escapedfile [string_to_regexp $file]
|
|
gdb_test "exec-file $file" "exec-file $escapedfile" "load"
|
|
|
|
if $ifmain {
|
|
reach $solib_bp run $displacement
|
|
|
|
# Use two separate gdb_test_multiple statements to avoid timeouts due
|
|
# to slow processing of wildcard capturing long output
|
|
set test "info files"
|
|
set entrynohex ""
|
|
gdb_test_multiple $test $test {
|
|
-re "\r\n\[\t \]*Entry point:\[\t \]*0x(\[0-9a-f\]+)\r\n" {
|
|
set entrynohex $expect_out(1,string)
|
|
gdb_test_multiple "" $test {
|
|
-re "\r\n$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# `info sym' cannot be tested for .opd as the binary may not have
|
|
# symbols.
|
|
if {[istarget powerpc64-*] && [is_lp64_target]} {
|
|
set test "convert entry point"
|
|
gdb_test_multiple "p *(void(*)(void) *) 0x$entrynohex" $test {
|
|
-re " =( \\(\[^0-9\]*\\))? 0x(\[0-9a-f\]+)( < \[^\r\n\]*)?\r\n$gdb_prompt $" {
|
|
set entrynohex $expect_out(2,string)
|
|
pass $test
|
|
}
|
|
}
|
|
}
|
|
if {$entrynohex != ""} {
|
|
gdb_test "break *0x$entrynohex" "" "break at entry point"
|
|
gdb_test "continue" "\r\nBreakpoint \[0-9\]+, 0x0*$entrynohex in .*" "entry point reached"
|
|
}
|
|
} else {
|
|
# There is no symbol to break at ld.so. Moreover it can
|
|
# exit with an error code.
|
|
|
|
set test "ld.so exit"
|
|
set test_displacement "seen displacement message as $displacement"
|
|
gdb_test_multiple "run" $test {
|
|
-re "Using PIE \\(Position Independent Executable\\) displacement (0x\[0-9a-f\]+) " {
|
|
# Missing "$gdb_prompt $" is intentional.
|
|
if {$expect_out(1,string) == "0x0"} {
|
|
set case "ZERO"
|
|
} else {
|
|
set case "NONZERO"
|
|
}
|
|
if {$displacement == $case || $displacement == "PRESENT"} {
|
|
pass $test_displacement
|
|
set displacement "FOUND-$displacement"
|
|
} else {
|
|
fail $test_displacement
|
|
}
|
|
exp_continue
|
|
}
|
|
-re "$inferior_exited_re (normally|with code \[0-9\]+).\r\n$gdb_prompt $" {
|
|
# Do not check the binary filename as it may be truncated.
|
|
pass $test
|
|
}
|
|
}
|
|
if ![regexp {^(NONE|FOUND-.*)$} $displacement] {
|
|
fail $test_displacement
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create separate binaries for each testcase - to make the possible reported
|
|
# problem reproducible after the whole test run finishes.
|
|
|
|
foreach ldprelink {NO YES} {
|
|
foreach ldsepdebug {NO IN SEP} {
|
|
# Skip running the ldsepdebug test if we do not have system separate
|
|
# debug info available.
|
|
if {$interp_system_debug == "" && $ldsepdebug == "SEP"} {
|
|
continue
|
|
}
|
|
|
|
set ldname "LDprelink${ldprelink}debug${ldsepdebug}"
|
|
set interp $binprefix-$ldname
|
|
|
|
# prelink needs to always prelink all the dependencies to do any file
|
|
# modifications of its files. ld.so also needs all the dependencies to
|
|
# be prelinked to omit the relocation process. In-memory file offsets
|
|
# are not dependent whether ld.so went the prelink way or through the
|
|
# relocation process.
|
|
#
|
|
# For GDB we are not interested whether prelink succeeds as it is
|
|
# transparent to GDB. GDB is being tested for differences of file
|
|
# offsets vs. in-memory offsets. So we have to prelink even ld.so for
|
|
# the BIN modification to happen but we need to restore the original
|
|
# possibly unprelinked ld.so to test all the combinations for GDB.
|
|
set interp_saved ${interp}-saved
|
|
|
|
with_test_prefix "$ldname" {
|
|
if {$ldsepdebug == "NO"} {
|
|
file_copy $interp_system $interp
|
|
# Never call strip-debug before unprelink:
|
|
# prelink: ...: Section .note.gnu.build-id created after prelinking
|
|
if ![prelinkNO $interp] {
|
|
continue
|
|
}
|
|
strip_debug $interp
|
|
} elseif {$ldsepdebug == "IN" && $interp_system_debug == ""} {
|
|
file_copy $interp_system $interp
|
|
} elseif {$ldsepdebug == "IN" && $interp_system_debug != ""} {
|
|
file_copy $interp_system $interp
|
|
file_copy $interp_system_debug "${interp}.debug"
|
|
# eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
|
|
if {![prelinkNO $interp] || ![prelinkNO "${interp}.debug"]} {
|
|
continue
|
|
}
|
|
set test "eu-unstrip unprelinked:[file tail $interp_system] + [file tail $interp_system_debug] to [file tail $interp]"
|
|
set command "exec eu-unstrip -o $interp $interp ${interp}.debug"
|
|
verbose -log "command is $command"
|
|
if [catch $command] {
|
|
setup_xfail *-*-*
|
|
fail $test
|
|
continue
|
|
} else {
|
|
pass $test
|
|
}
|
|
} elseif {$ldsepdebug == "SEP" && $interp_system_debug == ""} {
|
|
file_copy $interp_system $interp
|
|
# eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
|
|
if ![prelinkNO $interp] {
|
|
continue
|
|
}
|
|
gdb_gnu_strip_debug $interp
|
|
} elseif {$ldsepdebug == "SEP" && $interp_system_debug != ""} {
|
|
file_copy $interp_system $interp
|
|
file_copy $interp_system_debug "${interp}.debug"
|
|
}
|
|
|
|
if {$ldsepdebug == "SEP"} {
|
|
if ![prelinkNO "${interp}.debug"] {
|
|
continue
|
|
}
|
|
} else {
|
|
file delete "${interp}.debug"
|
|
}
|
|
|
|
if ![prelink$ldprelink $interp] {
|
|
continue
|
|
}
|
|
if {$ldprelink == "NO"} {
|
|
set displacement "NONZERO"
|
|
} else {
|
|
# x86* kernel loads prelinked PIE binary at its
|
|
# prelinked address but ppc* kernel loads it at a
|
|
# random address. prelink normally skips PIE binaries
|
|
# during the system scan.
|
|
set displacement "PRESENT"
|
|
}
|
|
test_ld $interp 0 [expr {$ldsepdebug == "NO"}] $displacement
|
|
|
|
if ![file_copy $interp $interp_saved] {
|
|
continue
|
|
}
|
|
|
|
foreach binprelink {NO YES} {
|
|
foreach binsepdebug {NO IN SEP} {
|
|
# "ATTACH" is like "YES" but it is modified during
|
|
# run. It cannot be used for problem
|
|
# reproducibility after the testcase ends.
|
|
foreach binpie {NO YES ATTACH} {
|
|
# This combination is not possible, non-PIE (fixed address)
|
|
# binary cannot be prelinked to any (other) address.
|
|
if {$binprelink == "YES" && $binpie == "NO"} {
|
|
continue
|
|
}
|
|
|
|
set binname "BINprelink${binprelink}debug${binsepdebug}pie${binpie}"
|
|
set exec $binprefix-$binname
|
|
|
|
with_test_prefix "$binname" {
|
|
set opts "ldflags=-Wl,$binfile_lib,-rpath,[file dirname $binfile_lib]"
|
|
if {$binsepdebug != "NO"} {
|
|
lappend opts {debug}
|
|
}
|
|
if {$binpie != "NO"} {
|
|
lappend opts {additional_flags=-fPIE -pie}
|
|
}
|
|
|
|
set dir ${exec}.d
|
|
set relink_args [build_executable_own_libs ${test}.exp [file tail $exec] $srcfile $opts $interp $dir]
|
|
if {$relink_args == ""} {
|
|
continue
|
|
}
|
|
|
|
if {$binsepdebug == "SEP"} {
|
|
gdb_gnu_strip_debug $exec
|
|
}
|
|
|
|
if {$binpie == "NO"} {
|
|
set displacement "NONE"
|
|
} elseif {$binprelink == "NO"} {
|
|
set displacement "NONZERO"
|
|
} else {
|
|
# x86* kernel loads prelinked PIE binary at its prelinked
|
|
# address but ppc* kernel loads it at a random address.
|
|
# prelink normally skips PIE binaries during the system scan.
|
|
set displacement "PRESENT"
|
|
}
|
|
|
|
if {[prelink$binprelink $relink_args [file tail $exec]]
|
|
&& [file_copy $interp_saved $interp]} {
|
|
if {$binpie != "ATTACH"} {
|
|
test_ld $exec 1 [expr {$binsepdebug == "NO"}] $displacement
|
|
} else {
|
|
# If the file has been randomly prelinked it must be
|
|
# "NONZERO". We could see "ZERO" only if it was unprelinked
|
|
# and it is now running at the same address - which is 0 but
|
|
# executable can never run at address 0.
|
|
|
|
set displacement "NONZERO"
|
|
test_attach $exec $displacement $relink_args
|
|
|
|
# ATTACH means that executables and libraries have been
|
|
# modified after they have been run. They cannot be reused
|
|
# for problem reproducibility after the testcase ends in
|
|
# the ATTACH case. Therefore they are rather deleted not
|
|
# to confuse after the run finishes.
|
|
set exec_debug [system_debug_get $exec]
|
|
if {$exec_debug != ""} {
|
|
# `file delete [glob "${exec_debug}*"]' does not work.
|
|
foreach f [glob "${exec_debug}*"] {
|
|
file delete $f
|
|
}
|
|
}
|
|
file delete -force $dir
|
|
# `file delete [glob "${exec}*"]' does not work.
|
|
foreach f [glob "${exec}*"] {
|
|
file delete $f
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
file delete $interp_saved
|
|
}
|
|
}
|
|
}
|