From: Andrew Burgess <aburgess@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>
Subject: [PATCH 6/6] gdb: extend .gdb_index tests to skip all data blocks
Date: Sun, 18 Oct 2026 21:50:35 +0100 [thread overview]
Message-ID: <03e5fe9a7996d105cde0aef714392776acf2dcae.1792356284.git.aburgess@redhat.com> (raw)
In-Reply-To: <cover.1792356284.git.aburgess@redhat.com>
We already had a skip-constant-pool test in
gdb.dwarf2/gdb-index-corrupted.exp. I added this early on as I could
see that skipping the constant-pool was going to trigger some bugs, I
added that test and fixed the bugs.
This commit extends the skip_index_part mechanism, that previously
only allowed skipping of the constant pool, to allow skipping of all
the index parts.
There was only a single bug exposed by this set of tests. When the CU
list is missing GDB would still try to use the index, however, thanks
to earlier patches in this series, every symbol in the symbol table
was ignored as its CU index was outside the (non-existent) CU list.
We already have some code in read_gdb_index_from_buffer
(dwarf2/read-gdb-index.c) which clears the symbol table if the
constant pool is empty. This results in GDB ignoring the index. I
have extended this logic to also check the CU list. Now, if either
the CU list or the constant pool are empty, and the symbol table is
not empty, then we clear the symbol table, which results in GDB
ignoring the index.
For every other part of the index, either that part can legitimately
be empty, or GDB already handled that part being empty. But having
the extra testing is a good thing I think.
---
gdb/dwarf2/read-gdb-index.c | 8 +-
.../gdb.dwarf2/gdb-index-corrupted.exp | 79 ++++++++++++++++-
gdb/testsuite/lib/dwarf.exp | 85 ++++++++++++-------
3 files changed, 138 insertions(+), 34 deletions(-)
diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c
index 5959b0ba6bc..d624ba1779c 100644
--- a/gdb/dwarf2/read-gdb-index.c
+++ b/gdb/dwarf2/read-gdb-index.c
@@ -606,10 +606,12 @@ read_gdb_index_from_buffer (const char *filename,
map->constant_pool = buffer.slice (metadata[i]);
- if (map->constant_pool.empty () && !map->symbol_table.empty ())
+ if ((map->constant_pool.empty () || *cu_list_elements == 0)
+ && !map->symbol_table.empty ())
{
- /* An empty constant pool implies that all symbol table entries are
- empty. Make map->symbol_table.empty () == true. */
+ /* An empty constant pool or an empty CU list implies that all symbol
+ table entries are empty. Recreate the symbol table as empty so
+ this index will be ignored. */
map->symbol_table
= offset_view (gdb::array_view<const gdb_byte> (symbol_table,
symbol_table));
diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp b/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp
index 865e5e50f97..56cdf895033 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index-corrupted.exp
@@ -141,6 +141,55 @@ proc run_test { testname } {
cu cu_label
name _start {{cu_label function global}}
}
+ } elseif { $testname eq "skip-cu-list" } {
+ # Create a .gdb_index with an empty CU list, but with a symbol
+ # that refers to a CU. The CU reference is now out of range, so
+ # GDB should ignore this .gdb_index.
+ gdb_index {
+ skip_index_part { cu_list }
+ } {
+ cu cu_label
+ name _start {{cu_label function global}}
+ }
+ } elseif { $testname eq "skip-tu-list" } {
+ # Skip the TU list. The TU list is always empty anyway, so this
+ # produces a perfectly valid .gdb_index; it is a sanity check
+ # that skipping an already-empty part changes nothing.
+ gdb_index {
+ skip_index_part { tu_list }
+ } {
+ cu cu_label
+ name _start {{cu_label function global}}
+ }
+ } elseif { $testname eq "skip-address-table" } {
+ # Skip the address table. An empty address table is valid, so
+ # GDB should still use this .gdb_index.
+ gdb_index {
+ skip_index_part { address_table }
+ } {
+ cu cu_label
+ name _start {{cu_label function global}}
+ }
+ } elseif { $testname eq "skip-symbol-table" } {
+ # Skip the symbol table. GDB treats an index with an empty
+ # symbol table as unusable and should ignore this .gdb_index.
+ gdb_index {
+ skip_index_part { symbol_table }
+ } {
+ cu cu_label
+ name _start {{cu_label function global}}
+ }
+ } elseif { $testname eq "skip-shortcut" } {
+ # Skip the shortcut table, but record a main function. With no
+ # shortcut table GDB cannot find the main function, but the
+ # index is otherwise valid and should still be used.
+ gdb_index {
+ skip_index_part { shortcut }
+ } {
+ cu cu_label
+ name _start {{cu_label function global}}
+ main DW_LANG_C99 _start
+ }
} elseif { $testname eq "long-cu-vector" } {
# Create a .gdb_index containing a CU vector in the
# constant pool where the vector length is invalid.
@@ -386,7 +435,14 @@ proc run_test { testname } {
|| $testname eq "cu-vector-offset-1" \
|| $testname eq "cu-vector-offset-2" \
|| $testname eq "cu-vector-offset-3" \
- || $testname eq "bad-cu-length" } {
+ || $testname eq "bad-cu-length" \
+ || $testname eq "skip-tu-list" \
+ || $testname eq "skip-address-table" \
+ || $testname eq "skip-shortcut" } {
+ # These produce an index that GDB still uses and in which the symbol
+ # _start is visible, but with no recognised main function. For the
+ # skip-shortcut test a main function was recorded, but GDB cannot
+ # find it with the shortcut table missing.
set expect_gdb_index_ignored false
set expect_start true
set expect_method false
@@ -461,7 +517,21 @@ proc run_test { testname } {
set expect_addr_map {}
set expect_warning_re ""
} elseif { $testname eq "no-null"
- || $testname eq "skip-constant-pool" } {
+ || $testname eq "skip-constant-pool"
+ || $testname eq "skip-cu-list"
+ || $testname eq "skip-symbol-table" } {
+ # For the three skip-* cases, these parts of the .gdb_index are
+ # critical. If the symbol table is missing (or empty) then the
+ # index contains no useful symbols, so GDB ignores the index. If
+ # either of the constant pool or the CU list are missing (or empty)
+ # then any symbols in the symbol list cannot be instantiated, so the
+ # symbol table is effectively empty, again GDB ignores the index in
+ # these cases.
+ #
+ # The no-null case means that the constant pool is malformed
+ # (missing its trailing null byte). GDB ignores the constant pool
+ # in this case, effectively making it empty. This renders the
+ # symbol table useless, so GDB ignores the index.
set expect_gdb_index_ignored true
if { $testname eq "no-null" } {
set expect_warning_re "\r\nwarning: skipping .gdb_index in \[^\r\n\]+, null byte at end of constant pool is missing\r\n"
@@ -579,6 +649,11 @@ set tests { empty-component \
main-language \
no-null \
skip-constant-pool \
+ skip-cu-list \
+ skip-tu-list \
+ skip-address-table \
+ skip-symbol-table \
+ skip-shortcut \
long-cu-vector \
name-offset-1 \
name-offset-2 \
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index b2b23167671..d0333c34fc9 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -3820,7 +3820,8 @@ namespace eval Dwarf {
# has zero length. This option is only useful for
# generating invalid .gdb_index sections for testing GDB's
# error handling. The supported part names are:
- # 'constant_pool'.
+ # 'cu_list', 'tu_list', 'address_table', 'symbol_table',
+ # 'shortcut' (version 9 only) and 'constant_pool'.
# (default {} -- no .gdb_index parts are skipped)
# header_override <dict>
# - a dict specifying overrides for header fields. Each
@@ -3955,7 +3956,8 @@ namespace eval Dwarf {
# Validate the names passed to skip_index_part to catch typos in
# tests.
foreach part $skip_index_part {
- if { [lsearch -exact { constant_pool } $part] == -1 } {
+ if { [lsearch -exact { cu_list tu_list address_table symbol_table \
+ shortcut constant_pool } $part] == -1 } {
error "gdb_index: unknown skip_index_part '$part'"
}
}
@@ -4256,31 +4258,44 @@ namespace eval Dwarf {
# CU list.
gdb_index_cu_list:
- foreach cu_rec $_gdb_index_cus {
- lassign $cu_rec cu length
- upvar $cu tmp
- _op_offset 8 $tmp "CU offset"
- # Record the CU's length into the index. In a well formed
- # index the length recorded here must match the actual
- # length of the CU in .debug_info. We allow the length to
- # be overridden, for testing purposes, by passing a bogus
- # length to the 'cu' command. If that was done then use
- # that length instead.
- if { $length ne "" } {
- set cu_length $length
- } elseif { [info exists _cu_lengths($tmp)] } {
- set cu_length $_cu_lengths($tmp)
- } else {
- error "gdb_index: unknown length for CU '$cu'"
+ if { [lsearch -exact $skip_index_part cu_list] != -1 } {
+ # We've been asked to not generate the CU list. This results in
+ # an invalid .gdb_index. We only support this as an option for
+ # error testing.
+ } else {
+ foreach cu_rec $_gdb_index_cus {
+ lassign $cu_rec cu length
+ upvar $cu tmp
+ _op_offset 8 $tmp "CU offset"
+ # Record the CU's length into the index. In a well formed
+ # index the length recorded here must match the actual
+ # length of the CU in .debug_info. We allow the length to
+ # be overridden, for testing purposes, by passing a bogus
+ # length to the 'cu' command. If that was done then use
+ # that length instead.
+ if { $length ne "" } {
+ set cu_length $length
+ } elseif { [info exists _cu_lengths($tmp)] } {
+ set cu_length $_cu_lengths($tmp)
+ } else {
+ error "gdb_index: unknown length for CU '$cu'"
+ }
+ _op_offset 8 "$cu_length" "CU length"
}
- _op_offset 8 "$cu_length" "CU length"
}
- # TU list (empty for now).
+ # TU list. This is always empty for now. Skipping it (via
+ # SKIP_INDEX_PART) is therefore a no-op so we don't even check.
gdb_index_tu_list:
# Address table.
gdb_index_addr_table:
+ if { [lsearch -exact $skip_index_part address_table] != -1 } {
+ # We've been asked to not generate the address table. An empty
+ # address table is actually valid, this exists for completeness
+ # and for error testing.
+ set _gdb_index_addrs {}
+ }
foreach addr_entry $_gdb_index_addrs {
lassign $addr_entry entry_type low high
@@ -4309,6 +4324,12 @@ namespace eval Dwarf {
# Symbol table.
gdb_index_symtab:
+ if { [lsearch -exact $skip_index_part symbol_table] != -1 } {
+ # We've been asked to not generate the symbol table. GDB treats
+ # an index with an empty symbol table as unusable. This exists
+ # for error testing.
+ set table_size 0
+ }
for {set i 0} {$i < $table_size} {incr i} {
if {$slot_occupied($i)} {
set idx $slot_name_idx($i)
@@ -4358,16 +4379,22 @@ namespace eval Dwarf {
# Shortcut table (version 9 only).
if { $version >= 9 } {
gdb_index_shortcut:
- _op .4byte $_gdb_index_main_lang "Language"
- if { $_gdb_index_main_lang == 0 } {
- _op .4byte 0 "Name offset"
- } elseif { $_gdb_index_main_name_idx eq "end" } {
- _op .4byte \
- "$gdb_index_constant_pool_end - $gdb_index_constant_pool" \
- "Name offset"
+ if { [lsearch -exact $skip_index_part shortcut] != -1 } {
+ # We've been asked to not generate the shortcut table. GDB
+ # copes with a missing shortcut table by not recording a
+ # main function. This exists for error testing.
} else {
- _op .4byte "$_gdb_index_main_name_idx" \
- "Name offset"
+ _op .4byte $_gdb_index_main_lang "Language"
+ if { $_gdb_index_main_lang == 0 } {
+ _op .4byte 0 "Name offset"
+ } elseif { $_gdb_index_main_name_idx eq "end" } {
+ _op .4byte \
+ "$gdb_index_constant_pool_end - $gdb_index_constant_pool" \
+ "Name offset"
+ } else {
+ _op .4byte "$_gdb_index_main_name_idx" \
+ "Name offset"
+ }
}
}
--
2.25.4
next prev parent reply other threads:[~2026-10-18 20:52 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-18 20:50 [PATCH 0/6] Improved error handling for .gdb_index parsing Andrew Burgess
2026-10-18 20:50 ` [PATCH 1/6] gdb: a number of fixes " Andrew Burgess
2026-10-20 18:39 ` Simon Marchi
2026-10-18 20:50 ` [PATCH 2/6] gdb: handle incorrect CU size in .gdb_index Andrew Burgess
2026-10-20 18:50 ` Simon Marchi
2026-10-18 20:50 ` [PATCH 3/6] gdb: validate the CU vector offset when loading the .gdb_index Andrew Burgess
2026-10-20 19:00 ` Simon Marchi
2026-10-18 20:50 ` [PATCH 4/6] gdb: address table parsing fixes and tests for .gdb_index Andrew Burgess
2026-10-20 19:09 ` Simon Marchi
2026-10-18 20:50 ` [PATCH 5/6] gdb: handle corrupted .gdb_index header offsets Andrew Burgess
2026-10-20 19:23 ` Simon Marchi
2026-10-18 20:50 ` Andrew Burgess [this message]
2026-10-20 19:32 ` [PATCH 6/6] gdb: extend .gdb_index tests to skip all data blocks Simon Marchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=03e5fe9a7996d105cde0aef714392776acf2dcae.1792356284.git.aburgess@redhat.com \
--to=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox