1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
# Copyright 2023-2024 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
}
with_timeout_factor $timeout_factor {
# Start GDB, load FILENAME.
clean_restart $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"
}
}
|