[PATCHv3 5/7] gdb: create address map after parsing all DIE

Andrew Burgess
2025-10-16T17:54:52Z

Continuing the work done in the last two commits, this commit defers
building the addrmap for a blockvector until after all the DIE have
been read, and the line table processed.

The benefit of this is that any changes to a block's ranges done
during line table processing (see the next commit) will be reflected
in the blockvector's addrmap.

The alternative to this is to build the addrmap as we initially see
each block, but then adjust the addrmap if we later decide to modify a
block. I think defering the addrmap creation is cleaner, and is less
work overall.

The addrmap requires that we add the most inner blocks first. I
achieve this by walking the blockvector backward, as we always add
parent blocks before their more inner child blocks.

There should be no user visible changes after this commit.
---
gdb/buildsym.c | 42 +++++++++++++++++++++++++++++++++++++-----
gdb/buildsym.h | 13 ++++---------
2 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 2a8e95e078b..6c46d75621b 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -410,8 +410,6 @@ buildsym_compunit::record_block_range (struct block *block,
if (start != block->start ()
|| end_inclusive + 1 != block->end ())
m_pending_addrmap_interesting = true;
-
- m_pending_addrmap.set_empty (start, end_inclusive, block);
}

struct blockvector *
@@ -447,9 +445,43 @@ buildsym_compunit::make_blockvector ()
/* If we needed an address map for this symtab, record it in the
blockvector. */
if (m_pending_addrmap_interesting)
- blockvector->set_map
- (new (&m_objfile->objfile_obstack) addrmap_fixed
- (&m_objfile->objfile_obstack, &m_pending_addrmap));
+ {
+ struct addrmap_mutable pending_addrmap;
+ int num_blocks = blockvector->num_blocks ();
+
+ /* If M_PENDING_ADDRMAP_INTERESTING is true then we must have seen
+ an interesting block. If we see one block, then we should at a
+ minimum have a global block, and a static block. */
+ gdb_assert (num_blocks > 1);
+
+ /* Assert our understanding of how the blocks are laid out. */
+ gdb_assert (blockvector->block (0)->is_global_block ());
+ gdb_assert (blockvector->block (1)->is_static_block ());
+
+ /* The 'J > 1' here is so that we don't place the global block into
+ the map. For CU with gaps, the static block will reflect the
+ gaps, while the global block will just reflect the full extent of
+ the range. */
+ for (int j = num_blocks; j > 1; )
+ {
+ --j;
+ struct block *b = blockvector->block (j);
+
+ gdb_assert (!b->is_global_block ());
+
+ if (b->is_contiguous ())
+ pending_addrmap.set_empty (b->start (), (b->end () - 1), b);
+ else
+ {
+ for (const auto &br : b->ranges ())
+ pending_addrmap.set_empty (br.start (), (br.end () - 1), b);
+ }
+ }
+
+ blockvector->set_map
+ (new (&m_objfile->objfile_obstack) addrmap_fixed
+ (&m_objfile->objfile_obstack, &pending_addrmap));
+ }
else
blockvector->set_map (nullptr);

diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 5d4b582349a..0ce460b0448 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -421,15 +421,10 @@ struct buildsym_compunit

struct subfile *m_current_subfile = nullptr;

- /* The mutable address map for the compilation unit whose symbols
- we're currently reading. The symtabs' shared blockvector will
- point to a fixed copy of this. */
- struct addrmap_mutable m_pending_addrmap;
-
- /* True if we recorded any ranges in the addrmap that are different
- from those in the blockvector already. We set this to false when
- we start processing a symfile, and if it's still false at the
- end, then we just toss the addrmap. */
+ /* If there are gaps in the address range of any block associated with
+ this buildsym_compunit, then we need to create an address map, this
+ flag is set true to indicate the addrmap must be created. If this
+ remains false, then no addrmap will be created. */
bool m_pending_addrmap_interesting = false;

/* An obstack used for allocating pending blocks. */
--
2.47.1