mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 23:23:09 +00:00
This is the result of: ... $ git rm -rf gdb/testsuite $ git commit -a -m tmp $ git revert HEAD $ git rebase --whitespace=fix HEAD^ ... Tested on x86_64-linux. PR build/33616 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33616
183 lines
6.6 KiB
Plaintext
183 lines
6.6 KiB
Plaintext
# Copyright 2022-2025 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/>.
|
|
|
|
# Tools which use the BFD library will output error messages of the
|
|
# form "BFD: some messsage" when a problem with the file upon which it
|
|
# operating is found. E.g. an actual message (modulo some shortening
|
|
# of the pathname) from this test is:
|
|
#
|
|
# BFD: bfd-errors-lib.so: invalid string offset 1154 >= 154 for section `.dynstr'
|
|
#
|
|
# For some problems with executable files or libraries, BFD will
|
|
# attempt to output many identical messages. Code has been added to
|
|
# GDB to suppress messages which are identical to earlier messages
|
|
# that have already been printed.
|
|
#
|
|
# This test makes sure that (all but the first) identical BFD messages
|
|
# are suppresssed and also that differing messages are output at least
|
|
# once.
|
|
#
|
|
# To accomplish this, a shared object with at least four symbols is
|
|
# created. The .dynsym section is extracted and offsets which should
|
|
# refer to strings in the .dynstr section are changed to be
|
|
# larger than the size of the .dynstr section. Only two (different)
|
|
# offsets are used; thus BFD will attempt to output at least two pairs
|
|
# of identical messages. (And it would do this too if not intercepted
|
|
# by the hook placed by GDB.) After modifying the extracted section,
|
|
# the mangled section is placed back into the shared object.
|
|
#
|
|
# This test then loads the shared library's symbol table (and other
|
|
# debug info) using the 'add-symbol-file' command. While doing this,
|
|
# the test observes and records the BFD errors that were output.
|
|
# Finally, data collected while adding the shared library symbols are
|
|
# examined to make sure that identical messages were suppressed while
|
|
# also making sure that at least two messages have been printed.
|
|
|
|
# This test can't be run on targets lacking shared library support
|
|
# or for non-ELF targets.
|
|
require allow_shlib_tests is_elf_target
|
|
|
|
# Library file names and flags:
|
|
set lib_basename ${::gdb_test_file_name}-lib
|
|
set srcfile_lib ${srcdir}/${subdir}/${lib_basename}.c
|
|
set binfile_lib [standard_output_file ${lib_basename}.so]
|
|
set lib_flags debug
|
|
|
|
# Compile shared library:
|
|
if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != "" } {
|
|
untested "failed to compile"
|
|
return -1
|
|
}
|
|
|
|
# Open the shared library and determine some basic facts. The key
|
|
# things that we need to learn are 1) whether the solib is 32-bit or
|
|
# 64-bit ELF file, and 2) the endianness.
|
|
set solib_fp [open ${binfile_lib} r]
|
|
fconfigure $solib_fp -translation binary
|
|
|
|
# Read and check EI_MAG to verify that it's really an ELF file.
|
|
set data [read $solib_fp 4]
|
|
if { ![string equal $data "\x7fELF"] } {
|
|
close $solib_fp
|
|
untested "shared library is not an ELF file"
|
|
return -1
|
|
}
|
|
|
|
# Read EI_CLASS for ELF32 versus ELF64.
|
|
set data [read $solib_fp 1]
|
|
set is_elf64 [string equal $data "\x02"]
|
|
|
|
# Read EI_DATA to determine data encoding (byte order).
|
|
set data [read $solib_fp 1]
|
|
set is_big_endian [string equal $data "\x02"]
|
|
|
|
close $solib_fp
|
|
|
|
set objcopy_program [gdb_find_objcopy]
|
|
|
|
# Extract the .dynsym and .dynstr section from the shared object.
|
|
if { [catch {exec $objcopy_program \
|
|
--dump-section .dynsym=${binfile_lib}.dynsym \
|
|
--dump-section .dynstr=${binfile_lib}.dynstr \
|
|
${binfile_lib}} output] } {
|
|
untested "failed objcopy dump-section"
|
|
verbose -log "objcopy output: $output"
|
|
return -1
|
|
}
|
|
|
|
# Determine length of .dynstr. We'll use the length for creating invalid
|
|
# offsets into .dynstr.
|
|
set dynstr_len [file size ${binfile_lib}.dynstr]
|
|
|
|
# Open the file containing .dynsym and determine its length. In this
|
|
# case, we want to know the length in order to compute the total number
|
|
# of symbols that it contains. We also leave the file open for a
|
|
# while so that we can write invalid offsets to it.
|
|
set dynsym_fp [open ${binfile_lib}.dynsym r+]
|
|
fconfigure $dynsym_fp -translation binary
|
|
set dynsym_len [string length [read $dynsym_fp]]
|
|
|
|
# SZ is the size of the Elf32_Sym / Elf64_Sym struct. OFF is the
|
|
# offset into the file. CNT is one greater than the number of symbols
|
|
# left to mangle. Note that, in the loop below, the first symbol is
|
|
# skipped. This is intentional since the first symbol is defined by
|
|
# the ELF specification to be the undefined symbol.
|
|
set off 0
|
|
if { $is_elf64 } {
|
|
set sz 24
|
|
} else {
|
|
set sz 16
|
|
}
|
|
set cnt [expr {$dynsym_len / $sz}]
|
|
|
|
# Create 32-bit patterns (bad offsets) to write into the st_name area.
|
|
if { $is_big_endian } {
|
|
set pat(0) [binary format I [expr {$dynstr_len + 1000}]]
|
|
set pat(1) [binary format I [expr {$dynstr_len + 2000}]]
|
|
} else {
|
|
set pat(0) [binary format i [expr {$dynstr_len + 1000}]]
|
|
set pat(1) [binary format i [expr {$dynstr_len + 2000}]]
|
|
}
|
|
|
|
# Mangle st_name for the symbols following the first (STN_UNDEF) entry.
|
|
while { [incr cnt -1] > 0 } {
|
|
seek $dynsym_fp [incr off $sz]
|
|
puts $dynsym_fp $pat([expr {$cnt % 2}])
|
|
}
|
|
|
|
close $dynsym_fp
|
|
|
|
# Replace .dynsym section in shared object with the mangled version.
|
|
if { [catch {exec $objcopy_program \
|
|
--update-section .dynsym=${binfile_lib}.dynsym \
|
|
${binfile_lib}} output] } {
|
|
untested "failed objcopy update-section"
|
|
verbose -log "objcopy output: $output"
|
|
return -1
|
|
}
|
|
|
|
clean_restart
|
|
|
|
# Count number of distinct BFD error messages via 'bfd_error_count'
|
|
# array while using add-symbol-file to "load" the shared library.
|
|
gdb_test_multiple "add-symbol-file -readnow $binfile_lib" \
|
|
"load library with add-symbol-file" {
|
|
-re "add symbol table from file.*\(y or n\)" {
|
|
send_gdb "y\n" answer
|
|
exp_continue
|
|
}
|
|
-re "(BFD:\[^\r\n\]*)\[\r\n\]+" {
|
|
incr bfd_error_count($expect_out(1,string))
|
|
exp_continue
|
|
}
|
|
-re "Expanding full symbols from.*$gdb_prompt $" {
|
|
pass $gdb_test_name
|
|
}
|
|
}
|
|
|
|
# Examine counts recorded in the 'bfd_error_count' array to see if any
|
|
# message was printed multiple times.
|
|
set more_than_one 0
|
|
foreach index [array names bfd_error_count] {
|
|
if { $bfd_error_count($index) > 1 } {
|
|
incr more_than_one
|
|
}
|
|
}
|
|
gdb_assert { $more_than_one == 0 } "consolidated bfd errors"
|
|
|
|
# There should have been at least two distinct BFD errors printed.
|
|
gdb_assert { [array size bfd_error_count] >= 2 } "print all unique bfd errors"
|
|
|
|
gdb_exit
|