diff options
Diffstat (limited to 'gdb/testsuite/gdb.base/dlmopen.exp')
-rw-r--r-- | gdb/testsuite/gdb.base/dlmopen.exp | 244 |
1 files changed, 214 insertions, 30 deletions
diff --git a/gdb/testsuite/gdb.base/dlmopen.exp b/gdb/testsuite/gdb.base/dlmopen.exp index dee046a..14f9084 100644 --- a/gdb/testsuite/gdb.base/dlmopen.exp +++ b/gdb/testsuite/gdb.base/dlmopen.exp @@ -77,15 +77,27 @@ if { [build_executable "build shlib" $binfile_lib2 $srcfile_lib \ return } -if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ +if { [build_executable "failed to build" $testfile $srcfile \ [list additional_flags=-DDSO1_NAME=\"$binfile_lib1\" \ additional_flags=-DDSO2_NAME=\"$binfile_lib2\" \ shlib_load debug]] } { - return -1 + return +} + +# Some locations needed by the tests. +set bp_inc [gdb_get_line_number "bp.inc" $srcfile_lib] +set bp_main [gdb_get_line_number "bp.main" $srcfile] + +# Figure out the file name for the dynamic linker. +set dyln_name [section_get $binfile .interp] +if { $dyln_name eq "" } { + unsupported "couldn't find dynamic linker name" + return } -if { ![runto_main] } { - return -1 +# Return true if FILENAME is the dynamic linker. Otherwise return false. +proc is_dyln { filename } { + return [expr {$filename eq $::dyln_name}] } # Check that 'info shared' show NUM occurrences of DSO. @@ -158,41 +170,213 @@ proc test_dlmopen {} { } } -# Remove the pause. We only need it for the attach test. -gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" +# Setup for calling 'test_dlmopen', this is the version of the test +# that doesn't use 'attach'. +proc test_dlmopen_no_attach {} { + clean_restart $::binfile -# Break in the to-be-loaded library and at the end of main. -set bp_inc [gdb_get_line_number "bp.inc" $srcfile_lib] -set bp_main [gdb_get_line_number "bp.main" $srcfile] + if { ![runto_main] } { + return + } -delete_breakpoints -gdb_breakpoint $srcfile_lib:$bp_inc allow-pending -gdb_breakpoint $srcfile:$bp_main + # Remove the pause. We only need it for the attach test. + gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" -test_dlmopen + # Break in the to-be-loaded library and at the end of main. + delete_breakpoints + gdb_breakpoint $::srcfile_lib:$::bp_inc allow-pending + gdb_breakpoint $::srcfile:$::bp_main -# Try the same again when attaching after dlmopen(). -require can_spawn_for_attach + test_dlmopen +} -clean_restart $binfile +# Setup for calling 'test_dlmopen', this is the version of the test +# that does use 'attach'. +proc test_dlmopen_with_attach {} { + if { ![can_spawn_for_attach] } { + unsupported "cannot run attach tests" + return + } -# Start the test program. -set test_spawn_id [spawn_wait_for_attach $binfile] -set testpid [spawn_id_get_pid $test_spawn_id] + clean_restart $::binfile -# Attach. -if { ![gdb_attach $testpid] } { - return + # Start the test program. + set test_spawn_id [spawn_wait_for_attach $::binfile] + set testpid [spawn_id_get_pid $test_spawn_id] + + # Attach. + if { ![gdb_attach $testpid] } { + return + } + + with_test_prefix "attach" { + # Remove the pause. We no longer need it. + gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" + + # Set the same breakpoints again. This time, however, we do not allow the + # breakpoint to be pending since the library has already been loaded. + gdb_breakpoint $::srcfile_lib:$::bp_inc + gdb_breakpoint $::srcfile:$::bp_main + + test_dlmopen + } } -with_test_prefix "attach" { - # Remove the pause. We no longer need it. - gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" +# Run 'info sharedlibrary' and count the number of mappings that look +# like they might be the dynamic linker. This will only work for +# Linux right now. +proc get_dyld_info {} { + if { ![istarget *-linux*] } { + return [list 0 ""] + } - # Set the same breakpoints again. This time, however, we do not allow the - # breakpoint to be pending since the library has already been loaded. - gdb_breakpoint $srcfile_lib:$bp_inc - gdb_breakpoint $srcfile:$bp_main + set dyld_count 0 + set dyld_start_addr "" + gdb_test_multiple "info sharedlibrary" "" { + -re "From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library\r\n" { + exp_continue + } + -re "^($::hex)\\s+$::hex\\s+\[^/\]+(/\[^\r\n\]+)\r\n" { + set addr $expect_out(1,string) + set lib $expect_out(2,string) + + if { [is_dyln $lib] } { + # This looks like it might be the dynamic linker. + incr dyld_count + if { $dyld_start_addr eq "" } { + set dyld_start_addr $addr + } elseif { $dyld_start_addr ne $addr } { + set dyld_start_addr "MULTIPLE" + } + } - test_dlmopen + exp_continue + } + -re "\\(\\*\\): Shared library is missing debugging information\\.\r\n" { + exp_continue + } + -re "^$::gdb_prompt $" { + } + } + + if { $dyld_start_addr eq "MULTIPLE" } { + set dyld_start_addr "" + } + + return [list $dyld_count $dyld_start_addr] } + +# The inferior for this test causes the dynamic linker to be appear +# multiple times in the inferior's shared library list, but (at least +# with glibc), the dynamic linker is really only mapped in once. That +# is, each of the dynamic linker instances that appear in the 'info +# sharedlibrary' output, will have the same address range. +# +# This test creates a user breakpoint in the dynamic linker, and then +# runs over the dlcose calls, which unmap all but one of the dynamic +# linker instances. +# +# The expectation is that the user breakpoint in the dynamic linker +# should still be active. Older versions of GDB had a bug where the +# breakpoint would become pending. +proc_with_prefix test_solib_unmap_events { } { + + # This test relies on finding the dynamic linker library, and is + # currently written assuming Linux. + if { ![istarget *-linux*] } { + unsupport "cannot find dynamic linker library on this target" + return + } + + clean_restart $::binfile + + if { ![runto_main] } { + return + } + + # Check that before any of our dlopen/dlmopen calls, we can find a + # single copy of the dynamic linker in the shared library list. + set dyld_info [get_dyld_info] + set dyld_count [lindex $dyld_info 0] + if { $dyld_count != 1 } { + unsupported "initial dyld state appears strange" + return + } + + # Continue the inferior until all solib are loaded. + set alarm_lineno [gdb_get_line_number "alarm" $::srcfile] + gdb_breakpoint ${::srcfile}:${alarm_lineno} + gdb_continue_to_breakpoint "all solib are now loaded" + + # Check that we have multiple copies of dynamic linker loaded, and + # that the dynamic linker is only loaded at a single address. + set dyld_info [get_dyld_info] + set dyld_count [lindex $dyld_info 0] + set dyld_start_addr [lindex $dyld_info 1] + + # If we didn't find a suitable dynamic linker address, or we + # didn't find multiple copies of the dynamic linker, then + # something has gone wrong with the test setup. + if { $dyld_count < 2 } { + unsupported "multiple copies of the dynamic linker not found" + return + } + if { $dyld_start_addr eq "" } { + unsupported "unable to find suitable dynamic linker start address" + return + } + + # Check the address we found is (likely) writable. + gdb_test_multiple "x/1i $dyld_start_addr" "check b/p address" { + -re -wrap "Cannot access memory at address \[^\r\n\]+" { + unsupported "dynamic linker address is not accessible" + return + } + -re -wrap "" { + } + } + + # Create a breakpoint within the dynamic linker. It is pretty unlikely + # that this breakpoint will ever be hit, but just in case it is, make it + # conditional, with a condition that will never be true. All we really + # care about for this test is whether the breakpoint will be made + # pending or not (it should not). + gdb_test "break *$dyld_start_addr if (0)" \ + "Breakpoint $::decimal at $::hex\[^\r\n\]+" \ + "create breakpoint within dynamic linker" + set bpnum [get_integer_valueof "\$bpnum" INVALID "get bpnum"] + + # Now continue until the 'bp.main' location, this will unload some + # copies, but not all copies, of the dynamic linker. + gdb_test "print wait_for_gdb = 0" " = 0" + set bp_main [gdb_get_line_number "bp.main" $::srcfile] + + gdb_breakpoint $::srcfile:$bp_main + gdb_continue_to_breakpoint "stop at bp.main" + + # At one point, GDB would incorrectly mark the breakpoints in the + # dynamic linker as pending when some instances of the library were + # unloaded, despite there really only being one copy of the dynamic + # linker actually loaded into the inferior's address space. + gdb_test_multiple "info breakpoints $bpnum" "check b/p status" { + -re -wrap "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+\\*$::hex\\s*\r\n\\s+stop only if \\(0\\)" { + fail $gdb_test_name + } + + -re -wrap "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex\\s*\[^\r\n\]+\r\n\\s+stop only if \\(0\\)" { + pass $gdb_test_name + } + } + + # With all the dlclose calls now complete, we should be back to a + # single copy of the dynamic linker. + set dyld_info [get_dyld_info] + set dyld_count [lindex $dyld_info 0] + gdb_assert { $dyld_count == 1 } \ + "one dynamic linker found after dlclose calls" +} + +# Run the actual tests. +test_dlmopen_no_attach +test_dlmopen_with_attach +test_solib_unmap_events |