blob: ee5b6451274b1d11b916fd0dc608edcb13d05934 [file] [log] [blame]
# Copyright 2023-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/>.
# Load the GDB executable, and then 'save gdb-index', and make some
# checks of the generated index file.
load_lib selftest-support.exp
# Can't save an index with readnow.
require !readnow
# A multiplier used to ensure slow tasks are less likely to timeout.
set timeout_factor 20
set filename [selftest_prepare]
if { $filename eq "" } {
unsupported "${gdb_test_file_name}.exp"
return -1
}
# If FILENAME is a libtool wrapper, then we need to get the path of the real
# executable.
set filename [selftest_libtool_get_real_gdb_executable $filename]
if { $filename eq "" } {
return -1
}
with_timeout_factor $timeout_factor {
# Start GDB, load FILENAME.
clean_restart
gdb_load $filename
}
# Record how many worker threads GDB is using.
set worker_threads [gdb_get_worker_threads]
if { $worker_threads eq "UNKNOWN" } {
unresolved "unable to get worker thread count"
return -1
}
# Generate an index file.
set dir1 [standard_output_file "index_1"]
remote_exec host "mkdir -p ${dir1}"
with_timeout_factor $timeout_factor {
set ok 0
gdb_test_multiple "save gdb-index $dir1" "create gdb-index file" {
-re -wrap "Error while writing index for \[^\r\n\]*: No debugging symbols" {
unsupported $gdb_test_name
}
-re -wrap "^" {
pass $gdb_test_name
set ok 1
}
}
if { ! $ok } {
return -1
}
gdb_test_no_output "save gdb-index -dwarf-5 $dir1" \
"create dwarf-index files"
}
# Close GDB.
gdb_exit
# Validate that the index-file FILENAME has made efficient use of its
# symbol hash table. Calculate the number of symbols in the hash
# table and the total hash table size. The hash table starts with
# 1024 entries, and then doubles each time it is filled to 75%. At
# 75% filled, doubling the size takes it to 37.5% filled.
#
# Thus, the hash table is correctly filled if:
# 1. Its size is 1024 (i.e. it has not yet had its first doubling), or
# 2. Its filled percentage is over 37%
#
# We could check that it is not over filled, but I don't as that's not
# really an issue. But we did once have a bug where the table was
# doubled incorrectly, in which case we'd see a filled percentage of
# around 2% in some cases, which is a huge waste of disk space.
proc check_symbol_table_usage { filename } {
# Open the file in binary mode and read-only mode.
set fp [open $filename rb]
# Configure the channel to use binary translation.
fconfigure $fp -translation binary
# Read the first 8 bytes of the file, which contain the header of
# the index section.
set header [read $fp [expr 7 * 4]]
# Scan the header to get the version, the CU list offset, and the
# types CU list offset.
binary scan $header iiiiii version \
_ _ _ symbol_table_offset shortcut_offset
# The length of the symbol hash table (in entries).
set len [expr ($shortcut_offset - $symbol_table_offset) / 8]
# Now walk the hash table and count how many entries are in use.
set offset $symbol_table_offset
set count 0
while { $offset < $shortcut_offset } {
seek $fp $offset
set entry [read $fp 8]
binary scan $entry ii name_ptr flags
if { $name_ptr != 0 } {
incr count
}
incr offset 8
}
# Close the file.
close $fp
# Calculate how full the cache is.
set pct [expr (100 * double($count)) / $len]
# Write our results out to the gdb.log.
verbose -log "Hash table size: $len"
verbose -log "Hash table entries: $count"
verbose -log "Percentage usage: $pct%"
# The minimum fill percentage is actually 37.5%, but we give TCL a
# little flexibility in case the FP maths give a result a little
# off.
gdb_assert { $len == 1024 || $pct > 37 } \
"symbol hash table usage"
}
set index_filename_base [file tail $filename]
check_symbol_table_usage "$dir1/${index_filename_base}.gdb-index"
# If GDB is using more than 1 worker thread then reduce the number of
# worker threads, regenerate the index, and check that we get the same
# index file back. At one point the layout of the index would vary
# based on the number of worker threads used.
if { $worker_threads > 1 } {
# Start GDB, but don't load a file yet.
clean_restart
# Adjust the number of threads to use.
set reduced_threads [expr $worker_threads / 2]
gdb_test_no_output "maint set worker-threads $reduced_threads"
with_timeout_factor $timeout_factor {
# Now load the test binary.
gdb_file_cmd $filename
}
# Generate an index file.
set dir2 [standard_output_file "index_2"]
remote_exec host "mkdir -p ${dir2}"
with_timeout_factor $timeout_factor {
gdb_test_no_output "save gdb-index $dir2" \
"create second gdb-index file"
gdb_test_no_output "save gdb-index -dwarf-5 $dir2" \
"create second dwarf-index files"
}
# Close GDB.
gdb_exit
# Now check that the index files are identical.
foreach suffix { gdb-index debug_names debug_str } {
set result \
[remote_exec host \
"cmp -s \"$dir1/${index_filename_base}.${suffix}\" \"$dir2/${index_filename_base}.${suffix}\""]
gdb_assert { [lindex $result 0] == 0 } \
"$suffix files are identical"
}
}