aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/dlmopen.exp
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/gdb.base/dlmopen.exp')
-rw-r--r--gdb/testsuite/gdb.base/dlmopen.exp244
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