[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