1 # This testcase is part of GDB, the GNU debugger. 2 # 3 # Copyright 2021-2024 Free Software Foundation, Inc. 4 # 5 # This program is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation; either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 # 18 # 19 # Test shared libraries loaded into different namespaces with dlmopen(). 20 # 21 # We test that GDB shows the correct number of instances of the libraries 22 # the test loaded while unloading them one-by-one. 23 24 require allow_dlmopen_tests 25 26 standard_testfile 27 28 set basename_lib dlmopen-lib 29 set srcfile_lib $srcdir/$subdir/$basename_lib.c 30 set binfile_lib1 [standard_output_file $basename_lib.1.so] 31 set binfile_lib2 [standard_output_file $basename_lib.2.so] 32 set srcfile_lib_dep $srcdir/$subdir/$basename_lib-dep.c 33 set binfile_lib_dep [standard_output_file $basename_lib-dep.so] 34 35 if { [gdb_compile_shlib $srcfile_lib_dep $binfile_lib_dep {debug}] != "" } { 36 untested "failed to prepare shlib" 37 return -1 38 } 39 40 if { [gdb_compile_shlib $srcfile_lib $binfile_lib1 \ 41 [list debug shlib_load libs=$binfile_lib_dep]] != "" } { 42 untested "failed to prepare shlib" 43 return -1 44 } 45 46 if { [gdb_compile_shlib $srcfile_lib $binfile_lib2 \ 47 [list debug shlib_load libs=$binfile_lib_dep]] != "" } { 48 untested "failed to prepare shlib" 49 return -1 50 } 51 52 if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ 53 [list additional_flags=-DDSO1_NAME=\"$binfile_lib1\" \ 54 additional_flags=-DDSO2_NAME=\"$binfile_lib2\" \ 55 shlib_load debug]] } { 56 return -1 57 } 58 59 if { ![runto_main] } { 60 return -1 61 } 62 63 # Check that 'info shared' show NUM occurrences of DSO. 64 proc check_dso_count { dso num } { 65 global gdb_prompt hex 66 67 set count 0 68 gdb_test_multiple "info shared" "info shared" { 69 -re "$hex $hex Yes \[^\r\n\]*$dso\r\n" { 70 # use longer form so debug remote does not interfere 71 set count [expr $count + 1] 72 exp_continue 73 } 74 -re "$gdb_prompt " { 75 verbose -log "library: $dso, expected: $num, found: $count" 76 gdb_assert {$count == $num} "$gdb_test_name" 77 } 78 } 79 } 80 81 # The DSO part of the test. We run it once per DSO call. 82 proc test_dlmopen_one { ndso1 ndso2 exp_glob } { 83 global srcfile_lib srcfile_lib basename_lib bp_inc 84 85 # Try to reach the breakpoint in the dynamically loaded library. 86 gdb_continue_to_breakpoint "cont to bp.inc" \ 87 ".*$srcfile_lib:$bp_inc\r\n.*" 88 89 # We opened all DSOs initially and close them one by one. 90 with_test_prefix "dso 1" { check_dso_count $basename_lib.1.so $ndso1 } 91 with_test_prefix "dso 2" { check_dso_count $basename_lib.2.so $ndso2 } 92 93 # This might help debugging. 94 gdb_test "info breakpoints" ".*" 95 gdb_test "print \$pc" ".*" 96 97 # We expect different instances of GDB_DLMOPEN_GLOB per DSO. 98 gdb_test "print amount" "= $exp_glob" 99 gdb_test "print gdb_dlmopen_glob" "= $exp_glob" 100 101 # Modify that DSO's instance, which should leave the others intact. 102 gdb_test "print &gdb_dlmopen_glob" "= .*" 103 gdb_test "print gdb_dlmopen_glob = -1" "= -1" 104 } 105 106 # The actual test. We run it twice. 107 proc test_dlmopen {} { 108 global srcfile basename_lib bp_main 109 110 # Note that when loading dlmopen-lib.1.so and dlmopen-lib.2.so into 111 # the same namespace, dlmopen-lib-dep.so is loaded only once, so in 112 # this case, the changes to gdb_dlmopen_glob inside test_dlmopen_one 113 # will actually be visible. 114 # 115 # Hence, we supply the expected value of this variable as argument to 116 # test_dlmopen_one. 117 with_test_prefix "dlmopen 1" { test_dlmopen_one 3 1 1 } 118 with_test_prefix "dlmopen 2" { test_dlmopen_one 2 1 1 } 119 with_test_prefix "dlmopen 3" { test_dlmopen_one 1 1 1 } 120 with_test_prefix "dlmopen 4" { test_dlmopen_one 0 1 -1 } 121 122 with_test_prefix "main" { 123 # Try to reach the breakpoint in the dynamically loaded library. 124 gdb_continue_to_breakpoint "cont to bp.main" \ 125 ".*$srcfile:$bp_main\r\n.*" 126 127 # The library should not be listed. 128 with_test_prefix "dso 1" { check_dso_count $basename_lib.1.so 0 } 129 with_test_prefix "dso 2" { check_dso_count $basename_lib.2.so 0 } 130 } 131 } 132 133 # Remove the pause. We only need it for the attach test. 134 gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" 135 136 # Break in the to-be-loaded library and at the end of main. 137 set bp_inc [gdb_get_line_number "bp.inc" $srcfile_lib] 138 set bp_main [gdb_get_line_number "bp.main" $srcfile] 139 140 delete_breakpoints 141 gdb_breakpoint $srcfile_lib:$bp_inc allow-pending 142 gdb_breakpoint $srcfile:$bp_main 143 144 test_dlmopen 145 146 # Try the same again when attaching after dlmopen(). 147 require can_spawn_for_attach 148 149 clean_restart $binfile 150 151 # Start the test program. 152 set test_spawn_id [spawn_wait_for_attach $binfile] 153 set testpid [spawn_id_get_pid $test_spawn_id] 154 155 # Attach. 156 if { ![gdb_attach $testpid] } { 157 return 158 } 159 160 with_test_prefix "attach" { 161 # Remove the pause. We no longer need it. 162 gdb_test "print wait_for_gdb = 0" "\\\$1 = 0" 163 164 # Set the same breakpoints again. This time, however, we do not allow the 165 # breakpoint to be pending since the library has already been loaded. 166 gdb_breakpoint $srcfile_lib:$bp_inc 167 gdb_breakpoint $srcfile:$bp_main 168 169 test_dlmopen 170 } 171