]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/symtab] Improve invalid range check in create_addrmap_from_gdb_index
authorTom de Vries <tdevries@suse.de>
Tue, 7 Oct 2025 08:25:57 +0000 (10:25 +0200)
committerTom de Vries <tdevries@suse.de>
Tue, 7 Oct 2025 08:25:57 +0000 (10:25 +0200)
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>
gdb/dwarf2/read-gdb-index.c
gdb/objfiles.h
gdbsupport/common-types.h

index 5354263e6775020615dc94ab582062e92e2aee1a..e02340ff2cd673026dd099f109cba844249dd666 100644 (file)
@@ -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"
index 1ce509229e7bdd43b80a2182d6551594d5dd58a6..118f1cd98289f0bf2f88e436073fec676f34378a 100644 (file)
@@ -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.  */
index 210e09b8de7dd352676db89414a22b524e5f0284..d849ea85c99e2a007ac9287fba6ca1c7dc60ecf1 100644 (file)
@@ -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.  */