1 # Copyright 2023-2024 Free Software Foundation, Inc.
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.
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.
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/>.
16 # Load the GDB executable, and then 'save gdb-index', and make some
17 # checks of the generated index file.
19 load_lib selftest-support.exp
21 # Can't save an index with readnow.
24 # A multiplier used to ensure slow tasks are less likely to timeout.
27 set filename [selftest_prepare]
28 if { $filename eq "" } {
29 unsupported "${gdb_test_file_name}.exp"
33 with_timeout_factor $timeout_factor {
34 # Start GDB, load FILENAME.
35 clean_restart $filename
38 # Record how many worker threads GDB is using.
39 set worker_threads [gdb_get_worker_threads]
41 if { $worker_threads eq "UNKNOWN" } {
42 unresolved "unable to get worker thread count"
46 # Generate an index file.
47 set dir1 [standard_output_file "index_1"]
48 remote_exec host "mkdir -p ${dir1}"
49 with_timeout_factor $timeout_factor {
51 gdb_test_multiple "save gdb-index $dir1" "create gdb-index file" {
52 -re -wrap "Error while writing index for \[^\r\n\]*: No debugging symbols" {
53 unsupported $gdb_test_name
64 gdb_test_no_output "save gdb-index -dwarf-5 $dir1" \
65 "create dwarf-index files"
71 # Validate that the index-file FILENAME has made efficient use of its
72 # symbol hash table. Calculate the number of symbols in the hash
73 # table and the total hash table size. The hash table starts with
74 # 1024 entries, and then doubles each time it is filled to 75%. At
75 # 75% filled, doubling the size takes it to 37.5% filled.
77 # Thus, the hash table is correctly filled if:
78 # 1. Its size is 1024 (i.e. it has not yet had its first doubling), or
79 # 2. Its filled percentage is over 37%
81 # We could check that it is not over filled, but I don't as that's not
82 # really an issue. But we did once have a bug where the table was
83 # doubled incorrectly, in which case we'd see a filled percentage of
84 # around 2% in some cases, which is a huge waste of disk space.
85 proc check_symbol_table_usage { filename } {
86 # Open the file in binary mode and read-only mode.
87 set fp [open $filename rb]
89 # Configure the channel to use binary translation.
90 fconfigure $fp -translation binary
92 # Read the first 8 bytes of the file, which contain the header of
94 set header [read $fp [expr 7 * 4]]
96 # Scan the header to get the version, the CU list offset, and the
97 # types CU list offset.
98 binary scan $header iiiiii version \
99 _ _ _ symbol_table_offset shortcut_offset
101 # The length of the symbol hash table (in entries).
102 set len [expr ($shortcut_offset - $symbol_table_offset) / 8]
104 # Now walk the hash table and count how many entries are in use.
105 set offset $symbol_table_offset
107 while { $offset < $shortcut_offset } {
109 set entry [read $fp 8]
110 binary scan $entry ii name_ptr flags
111 if { $name_ptr != 0 } {
121 # Calculate how full the cache is.
122 set pct [expr (100 * double($count)) / $len]
124 # Write our results out to the gdb.log.
125 verbose -log "Hash table size: $len"
126 verbose -log "Hash table entries: $count"
127 verbose -log "Percentage usage: $pct%"
129 # The minimum fill percentage is actually 37.5%, but we give TCL a
130 # little flexibility in case the FP maths give a result a little
132 gdb_assert { $len == 1024 || $pct > 37 } \
133 "symbol hash table usage"
136 set index_filename_base [file tail $filename]
137 check_symbol_table_usage "$dir1/${index_filename_base}.gdb-index"
139 # If GDB is using more than 1 worker thread then reduce the number of
140 # worker threads, regenerate the index, and check that we get the same
141 # index file back. At one point the layout of the index would vary
142 # based on the number of worker threads used.
143 if { $worker_threads > 1 } {
144 # Start GDB, but don't load a file yet.
147 # Adjust the number of threads to use.
148 set reduced_threads [expr $worker_threads / 2]
149 gdb_test_no_output "maint set worker-threads $reduced_threads"
151 with_timeout_factor $timeout_factor {
152 # Now load the test binary.
153 gdb_file_cmd $filename
156 # Generate an index file.
157 set dir2 [standard_output_file "index_2"]
158 remote_exec host "mkdir -p ${dir2}"
159 with_timeout_factor $timeout_factor {
160 gdb_test_no_output "save gdb-index $dir2" \
161 "create second gdb-index file"
163 gdb_test_no_output "save gdb-index -dwarf-5 $dir2" \
164 "create second dwarf-index files"
170 # Now check that the index files are identical.
171 foreach suffix { gdb-index debug_names debug_str } {
174 "cmp -s \"$dir1/${index_filename_base}.${suffix}\" \"$dir2/${index_filename_base}.${suffix}\""]
175 gdb_assert { [lindex $result 0] == 0 } \
176 "$suffix files are identical"