[5/10] add notion of included symtabs

Tom Tromey
2012-04-25T18:39:14Z

This patch changes symtabs to have a notion of "included" symtabs.

This mostly involved updating the block iterators to do the right thing.

No symtab readers have been updated yet, so this still has no effect
overall.

Tom

From fca0dcbba1f2d581a79a2847408ea1894f2df430 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Fri, 20 Apr 2012 08:49:59 -0600
Subject: [PATCH 05/10] add the notion of included symtabs, and update the
block iterators

* symtab.h (struct symtab) <includes, user>: New fields.
* block.h (struct block_iterator) <d, idx, which>: New fields.
* block.c (initialize_block_iterator, find_iterator_symtab)
(block_iterator_step, block_iter_name_step)
(block_iter_match_step): New functions.
(block_iterator_first, block_iterator_next)
(block_iter_name_first, block_iter_name_next)
(block_iter_match_first, block_iter_match_next): Rewrite.
---
gdb/block.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
gdb/block.h | 22 ++++++
gdb/symtab.h | 17 +++++
3 files changed, 259 insertions(+), 7 deletions(-)

diff --git a/gdb/block.c b/gdb/block.c
index fd87f77..38b64b3 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -408,13 +408,123 @@ get_block_symtab (const struct block *block)

\f

+/* Initialize a block iterator, either to iterate over a single block,
+ or, for static and global blocks, all the included symtabs as
+ well. */
+
+static void
+initialize_block_iterator (const struct block *block,
+ struct block_iterator *iter)
+{
+ enum block_enum which;
+ struct symtab *symtab;
+
+ iter->idx = -1;
+
+ if (BLOCK_SUPERBLOCK (block) == NULL)
+ {
+ which = GLOBAL_BLOCK;
+ symtab = get_block_symtab (block);
+ }
+ else if (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) == NULL)
+ {
+ which = STATIC_BLOCK;
+ symtab = get_block_symtab (BLOCK_SUPERBLOCK (block));
+ }
+ else
+ {
+ iter->d.block = block;
+ /* A signal value meaning that we're iterating over a single
+ block. */
+ iter->which = FIRST_LOCAL_BLOCK;
+ return;
+ }
+
+ /* If this is an included symtab, find the canonical includer and
+ use it instead. */
+ while (symtab->user != NULL)
+ symtab = symtab->user;
+
+ /* Putting this check here simplifies the logic of the iterator
+ functions. If there are no included symtabs, we only need to
+ search a single block, so we might as well just do that
+ directly. */
+ if (symtab->includes == NULL)
+ {
+ iter->d.block = block;
+ /* A signal value meaning that we're iterating over a single
+ block. */
+ iter->which = FIRST_LOCAL_BLOCK;
+ }
+ else
+ {
+ iter->d.symtab = symtab;
+ iter->which = which;
+ }
+}
+
+/* A helper function that finds the current symtab over whose static
+ or global block we should iterate. */
+
+static struct symtab *
+find_iterator_symtab (struct block_iterator *iterator)
+{
+ if (iterator->idx == -1)
+ return iterator->d.symtab;
+ return iterator->d.symtab->includes[iterator->idx];
+}
+
+/* Perform a single step for a plain block iterator, iterating across
+ symbol tables as needed. Returns the next symbol, or NULL when
+ iteration is complete. */
+
+static struct symbol *
+block_iterator_step (struct block_iterator *iterator, int first)
+{
+ struct symbol *sym;
+
+ gdb_assert (iterator->which != FIRST_LOCAL_BLOCK);
+
+ while (1)
+ {
+ if (first)
+ {
+ struct symtab *symtab = find_iterator_symtab (iterator);
+ const struct block *block;
+
+ /* Iteration is complete. */
+ if (symtab == NULL)
+ return NULL;
+
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which);
+ sym = dict_iterator_first (BLOCK_DICT (block), &iterator->dict_iter);
+ }
+ else
+ sym = dict_iterator_next (&iterator->dict_iter);
+
+ if (sym != NULL)
+ return sym;
+
+ /* We have finished iterating the appropriate block of one
+ symtab. Now advance to the next symtab and begin iteration
+ there. */
+ ++iterator->idx;
+ first = 1;
+ }
+}
+
/* See block.h. */

struct symbol *
block_iterator_first (const struct block *block,
struct block_iterator *iterator)
{
- return dict_iterator_first (block->dict, &iterator->dict_iter);
+ initialize_block_iterator (block, iterator);
+
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iterator_first (block->dict, &iterator->dict_iter);
+
+ return block_iterator_step (iterator, 1);
}

/* See block.h. */
@@ -422,7 +532,51 @@ block_iterator_first (const struct block *block,
struct symbol *
block_iterator_next (struct block_iterator *iterator)
{
- return dict_iterator_next (&iterator->dict_iter);
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iterator_next (&iterator->dict_iter);
+
+ return block_iterator_step (iterator, 0);
+}
+
+/* Perform a single step for a "name" block iterator, iterating across
+ symbol tables as needed. Returns the next symbol, or NULL when
+ iteration is complete. */
+
+static struct symbol *
+block_iter_name_step (struct block_iterator *iterator, const char *name,
+ int first)
+{
+ struct symbol *sym;
+
+ gdb_assert (iterator->which != FIRST_LOCAL_BLOCK);
+
+ while (1)
+ {
+ if (first)
+ {
+ struct symtab *symtab = find_iterator_symtab (iterator);
+ const struct block *block;
+
+ /* Iteration is complete. */
+ if (symtab == NULL)
+ return NULL;
+
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which);
+ sym = dict_iter_name_first (BLOCK_DICT (block), name,
+ &iterator->dict_iter);
+ }
+ else
+ sym = dict_iter_name_next (name, &iterator->dict_iter);
+
+ if (sym != NULL)
+ return sym;
+
+ /* We have finished iterating the appropriate block of one
+ symtab. Now advance to the next symtab and begin iteration
+ there. */
+ ++iterator->idx;
+ first = 1;
+ }
}

/* See block.h. */
@@ -432,7 +586,12 @@ block_iter_name_first (const struct block *block,
const char *name,
struct block_iterator *iterator)
{
- return dict_iter_name_first (block->dict, name, &iterator->dict_iter);
+ initialize_block_iterator (block, iterator);
+
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iter_name_first (block->dict, name, &iterator->dict_iter);
+
+ return block_iter_name_step (iterator, name, 1);
}

/* See block.h. */
@@ -440,7 +599,53 @@ block_iter_name_first (const struct block *block,
struct symbol *
block_iter_name_next (const char *name, struct block_iterator *iterator)
{
- return dict_iter_name_next (name, &iterator->dict_iter);
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iter_name_next (name, &iterator->dict_iter);
+
+ return block_iter_name_step (iterator, name, 0);
+}
+
+/* Perform a single step for a "match" block iterator, iterating
+ across symbol tables as needed. Returns the next symbol, or NULL
+ when iteration is complete. */
+
+static struct symbol *
+block_iter_match_step (struct block_iterator *iterator,
+ const char *name,
+ symbol_compare_ftype *compare,
+ int first)
+{
+ struct symbol *sym;
+
+ gdb_assert (iterator->which != FIRST_LOCAL_BLOCK);
+
+ while (1)
+ {
+ if (first)
+ {
+ struct symtab *symtab = find_iterator_symtab (iterator);
+ const struct block *block;
+
+ /* Iteration is complete. */
+ if (symtab == NULL)
+ return NULL;
+
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), iterator->which);
+ sym = dict_iter_match_first (BLOCK_DICT (block), name,
+ compare, &iterator->dict_iter);
+ }
+ else
+ sym = dict_iter_match_next (name, compare, &iterator->dict_iter);
+
+ if (sym != NULL)
+ return sym;
+
+ /* We have finished iterating the appropriate block of one
+ symtab. Now advance to the next symtab and begin iteration
+ there. */
+ ++iterator->idx;
+ first = 1;
+ }
}

/* See block.h. */
@@ -451,8 +656,13 @@ block_iter_match_first (const struct block *block,
symbol_compare_ftype *compare,
struct block_iterator *iterator)
{
- return dict_iter_match_first (block->dict, name, compare,
- &iterator->dict_iter);
+ initialize_block_iterator (block, iterator);
+
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iter_match_first (block->dict, name, compare,
+ &iterator->dict_iter);
+
+ return block_iter_match_step (iterator, name, compare, 1);
}

/* See block.h. */
@@ -462,5 +672,8 @@ block_iter_match_next (const char *name,
symbol_compare_ftype *compare,
struct block_iterator *iterator)
{
- return dict_iter_match_next (name, compare, &iterator->dict_iter);
+ if (iterator->which == FIRST_LOCAL_BLOCK)
+ return dict_iter_match_next (name, compare, &iterator->dict_iter);
+
+ return block_iter_match_step (iterator, name, compare, 0);
}
diff --git a/gdb/block.h b/gdb/block.h
index de674a8..d6c47c9 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -186,6 +186,28 @@ extern void set_block_symtab (struct block *, struct symtab *);

struct block_iterator
{
+ /* If we're iterating over a single block, this holds the block.
+ Otherwise, it holds the canonical symtab. */
+
+ union
+ {
+ struct symtab *symtab;
+ const struct block *block;
+ } d;
+
+ /* If we're iterating over a single block, this is always -1.
+ Otherwise, it holds the index of the current "included" symtab in
+ the canonical symtab, with -1 meaning the canonical symtab
+ itself. */
+
+ int idx;
+
+ /* Which block, either static or global, to iterate over. If this
+ is FIRST_LOCAL_BLOCK, then we are iterating over a single block.
+ This is used to select which field of 'd' is in use. */
+
+ enum block_enum which;
+
/* The underlying dictionary iterator. */

struct dict_iterator dict_iter;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 6933c0c..3f7bab5 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -832,6 +832,23 @@ struct symtab
/* struct call_site entries for this compilation unit or NULL. */

htab_t call_site_htab;
+
+ /* If non-NULL, then this points to a NULL-terminated vector of
+ included symbol tables. When searching the static or global
+ block of this symbol table, the corresponding block of all
+ included symbol tables will also be searched. Note that this
+ list must be flattened -- the symbol reader is responsible for
+ ensuring that this vector contains the transitive closure of all
+ included symbol tables. */
+
+ struct symtab **includes;
+
+ /* If this is an included symbol table, this points to one includer
+ of the table. This user is considered the canonical symbol table
+ containing this one. An included symbol table may itself be
+ included by another. */
+
+ struct symtab *user;
};

#define BLOCKVECTOR(symtab) (symtab)->blockvector
--
1.7.7.6