[binutils-gdb] gdb/dwarf: use gdb::unordered_map for line headers

Simon Marchi simark@sourceware.org
Tue Mar 10 17:44:21 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=34909f3a1dea81b0b83654c0de9375be20ac3d3b

commit 34909f3a1dea81b0b83654c0de9375be20ac3d3b
Author: Simon Marchi <simon.marchi@efficios.com>
Date:   Sat Feb 21 15:07:34 2026 -0500

    gdb/dwarf: use gdb::unordered_map for line headers
    
    Change htab_t for gdb::unordered_map, more specifically the
    unordered_section_and_offset_map specialization.
    
    It is no longer necessary to keep the section and offset inside the
    line_header structure itself, because it's just used for the map key, so
    remove that.
    
    I tried my best to preserve the logic in decode_line_header_for_cu, but
    I don't fully understand it.
    
    Change-Id: I512652e6da8b25db77ac9974135f9a06ce3d831e
    Approved-By: Tom Tromey <tom@tromey.com>

Diff:
---
 gdb/dwarf2/cu.h          |   2 +-
 gdb/dwarf2/line-header.h |   9 ----
 gdb/dwarf2/read.c        | 105 +++++++++++++++--------------------------------
 gdb/dwarf2/read.h        |   2 +-
 4 files changed, 36 insertions(+), 82 deletions(-)

diff --git a/gdb/dwarf2/cu.h b/gdb/dwarf2/cu.h
index 182871295c8..41c1d5717cd 100644
--- a/gdb/dwarf2/cu.h
+++ b/gdb/dwarf2/cu.h
@@ -342,7 +342,7 @@ public:
   /* Header data from the line table, during full symbol processing.  */
   struct line_header *line_header = nullptr;
   /* Non-NULL if LINE_HEADER is owned by this DWARF_CU.  Otherwise,
-     it's owned by dwarf2_per_bfd::line_header_hash.  If non-NULL,
+     it's owned by dwarf2_per_objfile::line_headers.  If non-NULL,
      this is the DW_TAG_compile_unit die for this CU.  We'll hold on
      to the line header as long as this DIE is being processed.  See
      process_die_scope.  */
diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h
index 6c8d62d6ae2..06ce5f0e124 100644
--- a/gdb/dwarf2/line-header.h
+++ b/gdb/dwarf2/line-header.h
@@ -92,12 +92,6 @@ struct line_header
     : m_comp_dir (comp_dir)
   {}
 
-  /* This constructor should only be used to create line_header instances to do
-     hash table lookups.  */
-  line_header (section_and_offset sect_and_offset)
-    : sect_and_offset (sect_and_offset)
-  {}
-
   /* Add an entry to the include directory table.  */
   void add_include_dir (const char *include_dir);
 
@@ -156,9 +150,6 @@ struct line_header
   const std::vector<file_entry> &file_names () const
   { return m_file_names; }
 
-  /* Section containing this line header, and its offset into that section.  */
-  section_and_offset sect_and_offset;
-
   unsigned short version {};
   unsigned char minimum_instruction_length {};
   unsigned char maximum_ops_per_instruction {};
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index fbe0b0bdbec..2f27a9ac75f 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -1029,36 +1029,6 @@ dwarf2_per_objfile::relocate (unrelocated_addr addr)
   return gdbarch_adjust_dwarf2_addr (objfile->arch (), tem);
 }
 
-/* Hash function for line_header_hash.  */
-
-static hashval_t
-line_header_hash (const struct line_header *ofs)
-{
-  return section_and_offset_hash () (ofs->sect_and_offset);
-}
-
-/* Hash function for htab_create_alloc_ex for line_header_hash.  */
-
-static hashval_t
-line_header_hash_voidp (const void *item)
-{
-  const struct line_header *ofs = (const struct line_header *) item;
-
-  return line_header_hash (ofs);
-}
-
-/* Equality function for line_header_hash.  */
-
-static int
-line_header_eq_voidp (const void *item_lhs, const void *item_rhs)
-{
-  const struct line_header *ofs_lhs = (const struct line_header *) item_lhs;
-  const struct line_header *ofs_rhs = (const struct line_header *) item_rhs;
-
-  return section_and_offset_eq () (ofs_lhs->sect_and_offset,
-				   ofs_rhs->sect_and_offset);
-}
-
 /* See declaration.  */
 
 dwarf2_per_bfd::dwarf2_per_bfd (bfd *obfd, const dwarf2_debug_sections *names,
@@ -5792,32 +5762,22 @@ decode_line_header_for_cu (struct die_info *die, struct dwarf2_cu *cu,
      compile_unit, then use the line header hash table if it's already
      created, but don't create one just yet.  */
 
-  if (per_objfile->line_header_hash == NULL
+  if (!per_objfile->line_headers.has_value ()
       && die->tag == DW_TAG_partial_unit)
-    {
-      per_objfile->line_header_hash
-	.reset (htab_create_alloc (127, line_header_hash_voidp,
-				   line_header_eq_voidp,
-				   htab_delete_entry<line_header>,
-				   xcalloc, xfree));
-    }
+    per_objfile->line_headers.emplace ();
 
-  void **slot;
-  line_header line_header_local ({ get_debug_line_section (cu), line_offset });
-  hashval_t line_header_local_hash = line_header_hash (&line_header_local);
-  if (per_objfile->line_header_hash != NULL)
-    {
-      slot = htab_find_slot_with_hash (per_objfile->line_header_hash.get (),
-				       &line_header_local,
-				       line_header_local_hash, NO_INSERT);
+  section_and_offset sao {get_debug_line_section (cu), line_offset};
 
-      /* For DW_TAG_compile_unit we need info like symtab::linetable which
-	 is not present in *SLOT (since if there is something in *SLOT then
-	 it will be for a partial_unit).  */
-      if (die->tag == DW_TAG_partial_unit && slot != NULL)
+  /* For DW_TAG_compile_unit we need info like symtab::linetable which is not
+     present in the LINE_HEADERS hash table (since if there is something in the
+     hash table, it will be for a partial_unit).  */
+  if (die->tag == DW_TAG_partial_unit
+      && per_objfile->line_headers.has_value ())
+    {
+      if (auto line_header_it = per_objfile->line_headers->find (sao);
+	  line_header_it != per_objfile->line_headers->end ())
 	{
-	  gdb_assert (*slot != NULL);
-	  cu->line_header = (struct line_header *) *slot;
+	  cu->line_header = line_header_it->second.get ();
 	  return;
 	}
     }
@@ -5832,29 +5792,32 @@ decode_line_header_for_cu (struct die_info *die, struct dwarf2_cu *cu,
   cu->line_header = lh.release ();
   cu->line_header_die_owner = die;
 
-  if (per_objfile->line_header_hash == NULL)
-    slot = NULL;
-  else
-    {
-      slot = htab_find_slot_with_hash (per_objfile->line_header_hash.get (),
-				       &line_header_local,
-				       line_header_local_hash, INSERT);
-      gdb_assert (slot != NULL);
-    }
-  if (slot != NULL && *slot == NULL)
+  bool inserted = false;
+
+  if (per_objfile->line_headers.has_value ())
     {
-      /* This newly decoded line number information unit will be owned
-	 by line_header_hash hash table.  */
-      *slot = cu->line_header;
-      cu->line_header_die_owner = NULL;
+      auto [_, inserted_]
+	= per_objfile->line_headers->try_emplace (sao, cu->line_header);
+      inserted = inserted_;
+
+      if (inserted)
+	{
+	  /* There was no existing entry for this key.  The new line_header
+	     will be owned by the line_headers hash table.  */
+	  cu->line_header_die_owner = nullptr;
+	}
     }
-  else
+
+  if (!inserted)
     {
-      /* We cannot free any current entry in (*slot) as that struct line_header
-	 may be already used by multiple CUs.  Create only temporary decoded
+      /* There is already an existing line table with this key, or we're not
+	 using the line_headers hash table.
+
+	 We cannot free an existing entry, as that struct line_header may
+	 be already used by multiple CUs.  Create only temporary decoded
 	 line_header for this CU - it may happen at most once for each line
-	 number information unit.  And if we're not using line_header_hash
-	 then this is what we want as well.  */
+	 number information unit.  And if we're not using the line_headers
+	 hash table then this is what we want as well.  */
       gdb_assert (die->tag != DW_TAG_partial_unit);
     }
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 5dd7a0993a3..e2d75e16146 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -952,7 +952,7 @@ struct dwarf2_per_objfile
     die_type_hash;
 
   /* Table containing line_header indexed by (section, offset-in-section).  */
-  htab_up line_header_hash;
+  std::optional<unordered_section_and_offset_map<line_header_up>> line_headers;
 
   /* The CU containing the m_builder in scope.  */
   dwarf2_cu *sym_cu = nullptr;


More information about the Gdb-cvs mailing list