1# Copyright 2010-2024 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. 17require !use_gdb_stub isnative allow_shlib_tests 18require {!is_remote host} 19require {istarget *-linux*} 20 21load_lib prelink-support.exp 22 23standard_testfile .c 24set genfile [standard_output_file ${testfile}-gen.h] 25set executable $testfile 26 27if {[build_executable_own_libs ${testfile}.exp $executable $srcfile \ 28 {pie}] == ""} { 29 return -1 30} 31 32# Program Headers: 33# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 34# LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x134f5ec 0x134f5ec R E 0x200000 35# LOAD 0x134f5f0 0x000000000194f5f0 0x000000000194f5f0 0x1dbc60 0x214088 RW 0x200000 36# DYNAMIC 0x134f618 0x000000000194f618 0x000000000194f618 0x000200 0x000200 RW 0x8 37# 38proc read_phdr {binfile test} { 39 set readelf_program [gdb_find_readelf] 40 set command "exec $readelf_program -Wl $binfile" 41 verbose -log "command is $command" 42 set result [catch $command output] 43 verbose -log "result is $result" 44 verbose -log "output is $output" 45 if {$result != 0} { 46 fail $test 47 return 48 } 49 if ![regexp {\nProgram Headers:\n *Type [^\n]* Align\n(.*?)\n\n} $output trash phdr] { 50 fail "$test (no Program Headers)" 51 return 52 } 53 if ![regexp -line {^ *DYNAMIC +0x[0-9a-f]+ +(0x[0-9a-f]+) } $phdr trash dynamic_vaddr] { 54 fail "$test (no DYNAMIC found)" 55 return 56 } 57 verbose -log "dynamic_vaddr is $dynamic_vaddr" 58 set align_max -1 59 foreach {trash align} [regexp -line -all -inline {^ *LOAD .* (0x[0-9]+)$} $phdr] { 60 if {$align_max < $align} { 61 set align_max $align 62 } 63 } 64 verbose -log "align_max is $align_max" 65 if {$align_max == -1} { 66 fail "$test (no LOAD found)" 67 return 68 } 69 pass $test 70 return [list $dynamic_vaddr $align_max] 71} 72 73set phdr [read_phdr $binfile "readelf initial scan"] 74set dynamic_vaddr [lindex $phdr 0] 75set align_max [lindex $phdr 1] 76 77set stub_size [format 0x%x [expr "2 * $align_max - ($dynamic_vaddr & ($align_max - 1))"]] 78verbose -log "stub_size is $stub_size" 79 80# On x86_64 it is commonly about 4MB. 81if {$stub_size > 25000000} { 82 xfail "stub size $stub_size is too large" 83 return 84} 85 86set test "generate stub" 87set command "exec $binfile $stub_size >$genfile" 88verbose -log "command is $command" 89set result [catch $command output] 90verbose -log "result is $result" 91verbose -log "output is $output" 92if {$result == 0} { 93 pass $test 94} else { 95 fail $test 96} 97 98with_test_prefix "rebuild with DGEN defined" { 99 set prelink_args [build_executable_own_libs ${testfile}.exp $executable $srcfile \ 100 [list pie "additional_flags=-DGEN=\"$genfile\""]] 101 if {$prelink_args == ""} { 102 return -1 103 } 104} 105 106# x86_64 file has 25MB, no need to keep it. 107file delete -- $genfile 108 109set phdr [read_phdr $binfile "readelf rebuilt with stub_size"] 110set dynamic_vaddr_prelinkno [lindex $phdr 0] 111 112if ![prelink_yes $prelink_args] { 113 return -1 114} 115 116set phdr [read_phdr $binfile "readelf with prelink -R"] 117set dynamic_vaddr_prelinkyes [lindex $phdr 0] 118 119set first_offset [format 0x%x [expr $dynamic_vaddr_prelinkyes - $dynamic_vaddr_prelinkno]] 120verbose -log "first_offset is $first_offset" 121 122set test "first offset is non-zero" 123if {$first_offset == 0} { 124 fail "$test (failing because PIE is not effect?)" 125} else { 126 pass $test 127} 128 129set test "start inferior" 130gdb_exit 131 132set test_spawn_id [remote_spawn host $binfile] 133if { $test_spawn_id < 0 || $test_spawn_id == "" } { 134 perror "Spawning $binfile failed." 135 fail $test 136 return 137} 138set testpid [spawn_id_get_pid $test_spawn_id] 139gdb_expect { 140 -re "sleeping\r\n" { 141 pass $test 142 } 143 eof { 144 fail "$test (eof)" 145 wait -i $test_spawn_id 146 return 147 } 148 timeout { 149 fail "$test (timeout)" 150 kill_wait_spawned_process $test_spawn_id 151 return 152 } 153} 154 155# Due to alignments it was reproducible with 1 on x86_64 but 2 on i686. 156foreach align_mult {1 2} { with_test_prefix "shift-by-$align_mult" { 157 158 # FIXME: We believe there is enough room under FIRST_OFFSET. 159 set shifted_offset [format 0x%x [expr "$first_offset - $align_mult * $align_max"]] 160 verbose -log "shifted_offset is $shifted_offset" 161 162 # For normal prelink (prelink_yes call), we need to supply $prelink_args. 163 # For the prelink `-r' option below, $prelink_args is not required. 164 # Moreover, if it was used, the problem would not longer be reproducible 165 # as the libraries would also get relocated. 166 set command "exec /usr/sbin/prelink -q -N --no-exec-shield -r $shifted_offset $binfile" 167 verbose -log "command is $command" 168 set result [catch $command output] 169 verbose -log "result is $result" 170 verbose -log "output is $output" 171 172 set test "prelink -r" 173 if {$result == 0 && $output == ""} { 174 pass $test 175 } else { 176 fail $test 177 } 178 179 clean_restart $executable 180 181 set test "attach" 182 gdb_test_multiple "attach $testpid" $test { 183 -re "Attaching to program: .*, process $testpid\r\n" { 184 # Missing "$gdb_prompt $" is intentional. 185 pass $test 186 } 187 } 188 189 set test "error on Cannot access memory at address" 190 gdb_test_multiple "" $test { 191 -re "\r\nCannot access memory at address .*$gdb_prompt $" { 192 fail $test 193 } 194 -re "$gdb_prompt $" { 195 pass $test 196 } 197 } 198 199 gdb_test "detach" "Detaching from program: .*" 200}} 201 202kill_wait_spawned_process $test_spawn_id 203