aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom de Vries <tdevries@suse.de>2025-10-07 10:25:57 +0200
committerTom de Vries <tdevries@suse.de>2025-10-07 10:25:57 +0200
commitae93841151eb133d6bee75544e15fc6c784b51e1 (patch)
tree1a7bdee5d464a9cdbb6b97f3ea3d43ecf5ad36cc
parent637f25e88675fa47e47f9cc5e2cf37384836b8a2 (diff)
downloadbinutils-ae93841151eb133d6bee75544e15fc6c784b51e1.zip
binutils-ae93841151eb133d6bee75544e15fc6c784b51e1.tar.gz
binutils-ae93841151eb133d6bee75544e15fc6c784b51e1.tar.bz2
[gdb/symtab] Improve invalid range check in create_addrmap_from_gdb_index
When running test-case gdb.tui/tui-missing-src.exp with target board gold-gdb-index (and likewise fission and fission-dwp) on aarch64-linux, I run into: ... FAIL: gdb.tui/tui-missing-src.exp: checking if inside f2 () ... Looking at the gold-gdb-index case, the problem is caused by the address table of the .gdb_index section: ... Address table: 000000000040066c 0000000000400694 0 000000000040053f 0000000000400563 1 ... The address range for f2 is [0x400694, 0x4006b8), but the address table says it's [0x40053f, 0x400563). The address 0x40053f is not even in a section: ... [Nr] Name Type Address Off Size ES Flg Lk Inf Al ... [12] .plt PROGBITS 00000000004004b8 0004b8 000050 10 AX 0 0 8 [13] .text PROGBITS 0000000000400540 000540 000178 00 AX 0 0 64 ... but part of the hole [0x400508, 0x400540) in between .plt and .text. Detect this in the invalid range check in create_addrmap_from_gdb_index. Tested on aarch64-linux. Approved-By: Simon Marchi <simon.marchi@efficios.com>
-rw-r--r--gdb/dwarf2/read-gdb-index.c56
-rw-r--r--gdb/objfiles.h18
-rw-r--r--gdbsupport/common-types.h7
3 files changed, 67 insertions, 14 deletions
diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c
index 5354263..e02340f 100644
--- a/gdb/dwarf2/read-gdb-index.c
+++ b/gdb/dwarf2/read-gdb-index.c
@@ -597,13 +597,46 @@ static bool
create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile,
mapped_gdb_index *index)
{
- const gdb_byte *iter, *end;
+ objfile *objfile = per_objfile->objfile;
addrmap_mutable mutable_map;
- iter = index->address_table.data ();
- end = iter + index->address_table.size ();
+ /* Build an unrelocated address map of the sections in this objfile. */
+ addrmap_mutable sect_map;
+ for (obj_section &s : objfile->sections ())
+ {
+ if (s.addr_unrel () >= s.endaddr_unrel ())
+ continue;
+
+ CORE_ADDR start = CORE_ADDR (s.addr_unrel ());
+ CORE_ADDR end_inclusive = CORE_ADDR (s.endaddr_unrel ()) - 1;
+ sect_map.set_empty (start, end_inclusive, &s);
+ }
+
+ auto find_section
+ = [&] (ULONGEST addr, struct obj_section *&cached_section)
+ {
+ if (cached_section != nullptr
+ && cached_section->contains (unrelocated_addr (addr)))
+ return cached_section;
+
+ cached_section = (struct obj_section *) sect_map.find (addr);
+ return cached_section;
+ };
+
+ auto invalid_range_warning = [&] (ULONGEST lo, ULONGEST hi)
+ {
+ warning (_(".gdb_index address table has invalid range (%s - %s),"
+ " ignoring .gdb_index"),
+ hex_string (lo), hex_string (hi));
+ return false;
+ };
+
+ /* Cache the section for possible re-use on the next entry. */
+ struct obj_section *prev_sect = nullptr;
+ const gdb_byte *iter = index->address_table.data ();
+ const gdb_byte *end = iter + index->address_table.size ();
while (iter < end)
{
ULONGEST hi, lo, cu_index;
@@ -615,12 +648,7 @@ create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile,
iter += 4;
if (lo >= hi)
- {
- warning (_(".gdb_index address table has invalid range (%s - %s),"
- " ignoring .gdb_index"),
- hex_string (lo), hex_string (hi));
- return false;
- }
+ return invalid_range_warning (lo, hi);
if (cu_index >= index->units.size ())
{
@@ -630,8 +658,16 @@ create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile,
return false;
}
+ /* Variable hi is the exclusive upper bound, get the inclusive one. */
+ CORE_ADDR hi_incl = hi - 1;
+
+ struct obj_section *lo_sect = find_section (lo, prev_sect);
+ struct obj_section *hi_sect = find_section (hi_incl, prev_sect);
+ if (lo_sect == nullptr || hi_sect == nullptr)
+ return invalid_range_warning (lo, hi);
+
bool full_range_p
- = mutable_map.set_empty (lo, hi - 1, index->units[cu_index]);
+ = mutable_map.set_empty (lo, hi_incl, index->units[cu_index]);
if (!full_range_p)
{
warning (_(".gdb_index address table has a range (%s - %s) that"
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 1ce5092..118f1cd 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -382,6 +382,12 @@ struct obj_section
return bfd_section_vma (this->the_bfd_section) + this->offset ();
}
+ /* As addr, but returns an unrelocated address. */
+ unrelocated_addr addr_unrel () const
+ {
+ return unrelocated_addr (bfd_section_vma (this->the_bfd_section));
+ }
+
/* The one-passed-the-end memory address of the section
(vma + size + offset). */
CORE_ADDR endaddr () const
@@ -389,12 +395,24 @@ struct obj_section
return this->addr () + bfd_section_size (this->the_bfd_section);
}
+ /* As endaddr, but returns an unrelocated address. */
+ unrelocated_addr endaddr_unrel () const
+ {
+ return this->addr_unrel () + bfd_section_size (this->the_bfd_section);
+ }
+
/* True if ADDR is in this obj_section, false otherwise. */
bool contains (CORE_ADDR addr) const
{
return addr >= this->addr () && addr < endaddr ();
}
+ /* As contains (CORE_ADDR), but for an unrelocated address. */
+ bool contains (unrelocated_addr addr) const
+ {
+ return addr >= this->addr_unrel () && addr < endaddr_unrel ();
+ }
+
/* BFD section pointer. This is nullptr if the corresponding BFD section is
not allocatable (!SEC_ALLOC), in which case this obj_section can be
considered NULL / empty. */
diff --git a/gdbsupport/common-types.h b/gdbsupport/common-types.h
index 210e09b..d849ea8 100644
--- a/gdbsupport/common-types.h
+++ b/gdbsupport/common-types.h
@@ -21,6 +21,7 @@
#define GDBSUPPORT_COMMON_TYPES_H
#include <inttypes.h>
+#include "gdbsupport/offset-type.h"
/* * A byte from the program being debugged. */
typedef unsigned char gdb_byte;
@@ -29,10 +30,8 @@ typedef unsigned char gdb_byte;
typedef uint64_t CORE_ADDR;
/* Like a CORE_ADDR, but not directly convertible. This is used to
- represent an unrelocated CORE_ADDR. DEFINE_OFFSET_TYPE is not used
- here because there's no need to add or subtract values of this
- type. */
-enum class unrelocated_addr : CORE_ADDR { };
+ represent an unrelocated CORE_ADDR. */
+DEFINE_OFFSET_TYPE (unrelocated_addr, CORE_ADDR);
/* LONGEST must be at least as big as CORE_ADDR. */