summaryrefslogtreecommitdiff
path: root/gdb/dwarf2read.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/dwarf2read.c')
-rw-r--r--gdb/dwarf2read.c418
1 files changed, 361 insertions, 57 deletions
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 7f9a02e1d74..b2cffbaf0d9 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -265,6 +265,28 @@ struct dwarf2_cu
struct obstack partial_die_obstack;
struct obstack abbrev_obstack;
+
+ /* When multiple dwarf2_cu structures are living in memory, this field
+ chains them all together, so that they can be released efficiently.
+ We will probably also want a generation counter so that most-recently-used
+ compilation units are cached... */
+ struct dwarf2_per_cu_data *read_in_chain;
+
+ /* Backchain to our per_cu entry if the tree has been built. */
+ struct dwarf2_per_cu_data *per_cu;
+};
+
+static const struct objfile_data *dwarf2_cu_tree;
+
+struct dwarf2_per_cu_data
+{
+ unsigned long offset, length;
+#if 0
+ struct partial_symtab *psymtab;
+#endif
+
+ /* Set iff currently read in. */
+ struct dwarf2_cu *cu;
};
/* The line number information for a compilation unit (found in the
@@ -393,9 +415,8 @@ struct dwarf_block
need this much information. */
struct partial_die_info
{
- enum dwarf_tag tag;
unsigned int offset;
- unsigned int abbrev : 16;
+ unsigned int tag : 16;
unsigned int language : 8;
unsigned int has_children : 1;
unsigned int is_external : 1;
@@ -403,6 +424,7 @@ struct partial_die_info
unsigned int has_type : 1;
unsigned int has_specification : 1;
unsigned int has_pc_info : 1;
+ unsigned int full_name_set : 1;
char *name;
char *full_name;
struct dwarf_block *locdesc;
@@ -687,7 +709,7 @@ static struct abbrev_info *peek_die_abbrev (char *, int *, struct dwarf2_cu *);
static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int,
struct dwarf2_cu *);
-static struct partial_die_info *load_partial_dies (bfd *, char *,
+static struct partial_die_info *load_partial_dies (bfd *, char *, int,
struct dwarf2_cu *);
static char *load_partial_die (struct partial_die_info *,
@@ -695,7 +717,8 @@ static char *load_partial_die (struct partial_die_info *,
bfd *, char *, struct dwarf2_cu *);
static struct partial_die_info *find_partial_die (unsigned long,
- struct dwarf2_cu *);
+ struct dwarf2_cu *,
+ struct dwarf2_cu **);
static void fixup_partial_die (struct partial_die_info *,
struct dwarf2_cu *);
@@ -944,14 +967,17 @@ static void
dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
struct dwarf2_cu *cu);
-#if 0
+static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
+ (unsigned long offset, struct dwarf2_cu *cu);
+
+static void clear_per_cu_pointer (void *data);
+
/* Allocation function for the libiberty splay tree which uses an obstack. */
static void *
splay_tree_obstack_allocate (int size, void *data)
{
return obstack_alloc ((struct obstack *) data, size);
}
-#endif
/* Trivial deallocation function for the libiberty splay tree. */
static void
@@ -1197,6 +1223,37 @@ read_comp_unit_head (struct comp_unit_head *cu_header,
return info_ptr;
}
+static char *
+partial_read_comp_unit_head (struct comp_unit_head *header, char *info_ptr,
+ bfd *abfd)
+{
+ char *beg_of_comp_unit = info_ptr;
+
+ info_ptr = read_comp_unit_head (header, info_ptr, abfd);
+
+ if (header->version != 2)
+ error ("Dwarf Error: wrong version in compilation unit header "
+ "(is %d, should be %d) [in module %s]", header->version,
+ 2, bfd_get_filename (abfd));
+
+ if (header->abbrev_offset >= dwarf_abbrev_size)
+ error ("Dwarf Error: bad offset (0x%lx) in compilation unit header "
+ "(offset 0x%lx + 6) [in module %s]",
+ (long) header->abbrev_offset,
+ (long) (beg_of_comp_unit - dwarf_info_buffer),
+ bfd_get_filename (abfd));
+
+ if (beg_of_comp_unit + header->length + header->initial_length_size
+ > dwarf_info_buffer + dwarf_info_size)
+ error ("Dwarf Error: bad length (0x%lx) in compilation unit header "
+ "(offset 0x%lx + 0) [in module %s]",
+ (long) header->length,
+ (long) (beg_of_comp_unit - dwarf_info_buffer),
+ bfd_get_filename (abfd));
+
+ return info_ptr;
+}
+
/* Build the partial symbol table by doing a quick pass through the
.debug_info and .debug_abbrev sections. */
@@ -1206,15 +1263,15 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
/* Instead of reading this into a big buffer, we should probably use
mmap() on architectures that support it. (FIXME) */
bfd *abfd = objfile->obfd;
- char *info_ptr, *abbrev_ptr;
+ char *info_ptr;
char *beg_of_comp_unit;
struct partial_die_info comp_unit_die;
struct partial_symtab *pst;
struct cleanup *back_to;
CORE_ADDR lowpc, highpc, baseaddr;
+ splay_tree cu_tree = NULL;
info_ptr = dwarf_info_buffer;
- abbrev_ptr = dwarf_abbrev_buffer;
/* We use dwarf2_tmp_obstack for objects that don't need to survive
the partial symbol scan, like attribute values.
@@ -1266,34 +1323,13 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
struct dwarf2_cu cu;
struct abbrev_info *abbrev;
unsigned int bytes_read;
+ struct dwarf2_per_cu_data *this_cu;
beg_of_comp_unit = info_ptr;
cu.objfile = objfile;
- info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+ info_ptr = partial_read_comp_unit_head (&cu.header, info_ptr, abfd);
- if (cu.header.version != 2)
- {
- error ("Dwarf Error: wrong version in compilation unit header (is %d, should be %d) [in module %s]", cu.header.version, 2, bfd_get_filename (abfd));
- return;
- }
- if (cu.header.abbrev_offset >= dwarf_abbrev_size)
- {
- error ("Dwarf Error: bad offset (0x%lx) in compilation unit header (offset 0x%lx + 6) [in module %s]",
- (long) cu.header.abbrev_offset,
- (long) (beg_of_comp_unit - dwarf_info_buffer),
- bfd_get_filename (abfd));
- return;
- }
- if (beg_of_comp_unit + cu.header.length + cu.header.initial_length_size
- > dwarf_info_buffer + dwarf_info_size)
- {
- error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0) [in module %s]",
- (long) cu.header.length,
- (long) (beg_of_comp_unit - dwarf_info_buffer),
- bfd_get_filename (abfd));
- return;
- }
/* Complete the cu_header */
cu.header.offset = beg_of_comp_unit - dwarf_info_buffer;
cu.header.first_die_ptr = info_ptr;
@@ -1343,6 +1379,30 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
/* Store the function that reads in the rest of the symbol table */
pst->read_symtab = dwarf2_psymtab_to_symtab;
+ if (cu_tree == NULL)
+ cu_tree = objfile_data (objfile, dwarf2_cu_tree);
+
+ if (cu_tree != NULL)
+ {
+ splay_tree_node node;
+ struct dwarf2_per_cu_data *per_cu;
+
+ node = splay_tree_lookup (cu_tree, cu.header.offset);
+ gdb_assert (node != NULL);
+ per_cu = (struct dwarf2_per_cu_data *) node->value;
+ cu.per_cu = per_cu;
+
+ /* Note that this is a pointer to our stack frame. It will
+ be cleaned up in clear_per_cu_pointer when we finish with
+ this compilation unit. */
+ per_cu->cu = &cu;
+ }
+ else
+ cu.per_cu = NULL;
+
+ make_cleanup (clear_per_cu_pointer, &cu);
+ cu.read_in_chain = NULL;
+
/* Check if comp unit has_children.
If so, read the rest of the partial symbols from this comp unit.
If not, there's no more debug_info for this comp unit. */
@@ -1363,7 +1423,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
hash_obstack_allocate,
splay_tree_obstack_deallocate);
- first_die = load_partial_dies (abfd, info_ptr, &cu);
+ first_die = load_partial_dies (abfd, info_ptr, 1, &cu);
scan_partial_symbols (first_die, &lowpc, &highpc, &cu, 0);
@@ -1405,6 +1465,127 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
do_cleanups (back_to);
}
+/* Load the DIEs for a secondary CU into memory. */
+
+static void
+load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ char *info_ptr, *beg_of_comp_unit;
+ struct partial_die_info comp_unit_die;
+ struct dwarf2_cu *cu;
+ struct abbrev_info *abbrev;
+ unsigned int bytes_read;
+ struct cleanup *back_to;
+
+ info_ptr = dwarf_info_buffer + this_cu->offset;
+ beg_of_comp_unit = info_ptr;
+
+ cu = xmalloc (sizeof (struct dwarf2_cu));
+ cu->objfile = objfile;
+ info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr, abfd);
+
+ /* Complete the cu_header */
+ cu->header.offset = beg_of_comp_unit - dwarf_info_buffer;
+ cu->header.first_die_ptr = info_ptr;
+ cu->header.cu_head_ptr = beg_of_comp_unit;
+
+ cu->partial_dies = NULL;
+
+ /* Read the abbrevs for this compilation unit into a table */
+ dwarf2_read_abbrevs (abfd, cu);
+ back_to = make_cleanup (dwarf2_empty_abbrev_table, cu);
+
+ /* Read the compilation unit die */
+ abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu);
+ info_ptr = load_partial_die (&comp_unit_die, abbrev, bytes_read,
+ abfd, info_ptr, cu);
+
+ /* Set the language we're debugging */
+ set_cu_language (comp_unit_die.language, cu);
+
+ this_cu->cu = cu;
+ cu->per_cu = this_cu;
+
+ /* Check if comp unit has_children.
+ If so, read the rest of the partial symbols from this comp unit.
+ If not, there's no more debug_info for this comp unit. */
+ if (comp_unit_die.has_children)
+ {
+ struct partial_die_info *first_die;
+
+ obstack_init (&cu->partial_die_obstack);
+ cu->partial_dies
+ = htab_create_alloc_ex (cu->header.length / 12,
+ partial_die_hash,
+ partial_die_eq,
+ NULL,
+ &cu->partial_die_obstack,
+ hash_obstack_allocate,
+ splay_tree_obstack_deallocate);
+
+ first_die = load_partial_dies (abfd, info_ptr, 0, cu);
+ }
+
+ do_cleanups (back_to);
+}
+
+/* Create a tree of all compilation units in OBJFILE. We do this only
+ if an inter-comp-unit reference is found; presumably if there is one,
+ there will be many, and one will occur early in the .debug_info section.
+ So there's no point in building this tree incrementally. */
+
+static splay_tree
+create_comp_unit_tree (struct dwarf2_cu *cu)
+{
+ splay_tree cu_tree;
+ struct objfile *objfile = cu->objfile;
+ char *info_ptr = dwarf_info_buffer;
+
+ /* Initialize the compilation unit tree. */
+ cu_tree = splay_tree_new_with_allocator (splay_tree_compare_ints,
+ NULL, NULL,
+ splay_tree_obstack_allocate,
+ splay_tree_obstack_deallocate,
+ &objfile->objfile_obstack);
+ set_objfile_data (objfile, dwarf2_cu_tree, cu_tree);
+
+ while (info_ptr < dwarf_info_buffer + dwarf_info_size)
+ {
+ struct comp_unit_head cu_header;
+ char *beg_of_comp_unit;
+ struct dwarf2_per_cu_data *this_cu;
+ unsigned long offset;
+
+ beg_of_comp_unit = info_ptr;
+ offset = beg_of_comp_unit - dwarf_info_buffer;
+
+ /* FIXME: Can I read less data here? All we really need is the length
+ and the initial length size. */
+ info_ptr = partial_read_comp_unit_head (&cu_header, info_ptr,
+ objfile->obfd);
+
+ /* Save the compilation unit for later lookup. */
+ this_cu = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_per_cu_data));
+ memset (this_cu, 0, sizeof (*this_cu));
+ this_cu->offset = offset;
+ this_cu->length = cu_header.length;
+ splay_tree_insert (cu_tree, this_cu->offset, (splay_tree_value) this_cu);
+
+ if (this_cu->offset == cu->header.offset)
+ {
+ this_cu->cu = cu;
+ cu->per_cu = this_cu;
+ }
+
+ info_ptr = beg_of_comp_unit + cu_header.length
+ + cu_header.initial_length_size;
+ }
+
+ return cu_tree;
+}
+
/* Read in all interesting dies to the end of the compilation unit or
to the end of the current namespace. NAMESPACE is NULL if we
haven't yet encountered any DW_TAG_namespace entries; otherwise,
@@ -1500,31 +1681,62 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
}
}
+/* Return the fully scoped name associated with PDI, from compilation unit
+ CU. The result will be allocated with malloc, or NULL if PDI->NAME should
+ be used. */
static char *
partial_die_full_name (struct partial_die_info *pdi,
struct dwarf2_cu *cu)
{
- char *parent_name;
- struct partial_die_info *real_parent;
+ char *parent_name, *full_name;
+ struct partial_die_info *real_pdi, *real_parent;
+ struct dwarf2_cu *spec_cu;
+ int free_parent_name = 0;
- /* Note: this code could be micro-optimized. We could avoid redoing
- the hash table lookup, which we've probably already done once,
- and we might be able to use real_pdi->full_name if there is a
- specification. */
+ if (pdi->full_name_set)
+ return pdi->full_name;
- if (pdi->has_specification)
- real_parent = find_partial_die (pdi->spec_offset, cu)->die_parent;
- else
- real_parent = pdi->die_parent;
+ /* Note: this code could probably be micro-optimized. We may be
+ able to avoid redoing the hash table lookup, and we might be able
+ to use real_pdi->full_name if there is a specification. */
+
+ real_pdi = pdi;
+ spec_cu = cu;
+ while (real_pdi->has_specification)
+ real_pdi = find_partial_die (real_pdi->spec_offset, spec_cu, &spec_cu);
+
+ /* NOTE drow/2004-02-22: The following code is a hack. It's only used when
+ visiting the DIEs out of order, i.e. due to DW_AT_specification in another
+ CU or later in this CU. It's correct, but somewhat inefficient. */
+ if (real_pdi->full_name_set)
+ return real_pdi->full_name;
+
+ real_parent = real_pdi->die_parent;
if (real_parent == NULL)
- return NULL;
+ {
+ real_pdi->full_name_set = 1;
+ return NULL;
+ }
+
+ if (!real_parent->full_name_set)
+ {
+ fixup_partial_die (real_parent, spec_cu);
+ parent_name = partial_die_full_name (real_parent, spec_cu);
+ /* Could cache the full name, too. */
+ free_parent_name = 1;
+ }
+
+ /* End hack zone. */
parent_name = real_parent->full_name;
if (parent_name == NULL)
parent_name = real_parent->name;
- return concat (parent_name, "::", pdi->name, NULL);
+ full_name = concat (parent_name, "::", real_pdi->name, NULL);
+ if (free_parent_name)
+ free (parent_name);
+ return full_name;
}
static void
@@ -1542,7 +1754,9 @@ add_partial_symbol (struct partial_die_info *pdi,
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
actual_name = NULL;
- if (pdi_needs_namespace (pdi->tag) && pdi->full_name == NULL)
+ if (!pdi->full_name_set
+ && pdi_needs_namespace (pdi->tag)
+ && pdi->full_name == NULL)
{
actual_name = partial_die_full_name (pdi, cu);
if (actual_name)
@@ -1557,6 +1771,8 @@ add_partial_symbol (struct partial_die_info *pdi,
actual_name = pdi->name;
}
+ pdi->full_name_set = 1;
+
switch (pdi->tag)
{
case DW_TAG_subprogram:
@@ -4511,17 +4727,16 @@ is_type_tag_for_partial (int tag)
/* Load all DIEs that are interesting for partial symbols into memory. */
static struct partial_die_info *
-load_partial_dies (bfd *abfd, char *info_ptr, struct dwarf2_cu *cu)
+load_partial_dies (bfd *abfd, char *info_ptr, int building_psymtab,
+ struct dwarf2_cu *cu)
{
struct partial_die_info *part_die;
struct partial_die_info *parent_die, *last_die, *first_die = NULL;
struct abbrev_info *abbrev;
unsigned int bytes_read;
- /* FIXME: Obviously we need a nesting level passed in for incremental use. */
int nesting_level = 1;
- /* But if we do incremental what do we do with this??? */
parent_die = NULL;
last_die = NULL;
@@ -4586,7 +4801,7 @@ load_partial_dies (bfd *abfd, char *info_ptr, struct dwarf2_cu *cu)
|| part_die->tag == DW_TAG_base_type
|| part_die->tag == DW_TAG_subrange_type))
{
- if (part_die->name != NULL)
+ if (building_psymtab && part_die->name != NULL)
add_psymbol_to_list (part_die->name, strlen (part_die->name),
VAR_DOMAIN, LOC_TYPEDEF,
&cu->objfile->static_psymbols,
@@ -4607,7 +4822,7 @@ load_partial_dies (bfd *abfd, char *info_ptr, struct dwarf2_cu *cu)
{
if (part_die->name == NULL)
complaint (&symfile_complaints, "malformed enumerator DIE ignored");
- else
+ else if (building_psymtab)
add_psymbol_to_list (part_die->name, strlen (part_die->name),
VAR_DOMAIN, LOC_CONST,
cu->language == language_cplus
@@ -4719,7 +4934,6 @@ load_partial_die (struct partial_die_info *part_die,
part_die->tag = abbrev->tag;
part_die->has_children = abbrev->has_children;
- part_die->abbrev = abbrev->number;
for (i = 0; i < abbrev->num_attrs; ++i)
{
@@ -4810,17 +5024,16 @@ load_partial_die (struct partial_die_info *part_die,
return info_ptr;
}
-/* Like load_partial_die, but also patch up the partial DIE's name
- according to its specification if necessary. */
+/* Find a cached partial DIE at OFFSET in CU. */
static struct partial_die_info *
-find_partial_die (unsigned long offset, struct dwarf2_cu *cu)
+find_partial_die_in_comp_unit (unsigned long offset, struct dwarf2_cu *cu)
{
struct partial_die_info *lookup_die = NULL;
struct partial_die_info part_die;
part_die.offset = offset;
lookup_die = htab_find_with_hash (cu->partial_dies, &part_die, offset);
-
+
if (lookup_die == NULL)
internal_error (__FILE__, __LINE__,
"could not find partial DIE in cache\n");
@@ -4828,6 +5041,31 @@ find_partial_die (unsigned long offset, struct dwarf2_cu *cu)
return lookup_die;
}
+/* Find a partial DIE at OFFSET, which may or may not be in CU. */
+static struct partial_die_info *
+find_partial_die (unsigned long offset, struct dwarf2_cu *cu,
+ struct dwarf2_cu **target_cu)
+{
+ struct dwarf2_per_cu_data *per_cu;
+
+ if (offset >= cu->header.offset
+ && offset < cu->header.offset + cu->header.length)
+ return find_partial_die_in_comp_unit (offset, cu);
+
+ per_cu = dwarf2_find_containing_comp_unit (offset, cu);
+ gdb_assert (per_cu != NULL);
+
+ if (per_cu->cu == NULL)
+ {
+ load_comp_unit (per_cu, cu->objfile);
+ per_cu->cu->read_in_chain = cu->read_in_chain;
+ cu->read_in_chain = per_cu;
+ }
+
+ *target_cu = per_cu->cu;
+ return find_partial_die_in_comp_unit (offset, per_cu->cu);
+}
+
static void
fixup_partial_die (struct partial_die_info *part_die,
struct dwarf2_cu *cu)
@@ -4838,10 +5076,11 @@ fixup_partial_die (struct partial_die_info *part_die,
if (part_die->name == NULL && part_die->has_specification)
{
struct partial_die_info *spec_die;
+ struct dwarf2_cu *spec_cu;
- spec_die = find_partial_die (part_die->spec_offset, cu);
+ spec_die = find_partial_die (part_die->spec_offset, cu, &spec_cu);
- fixup_partial_die (spec_die, cu);
+ fixup_partial_die (spec_die, spec_cu);
if (spec_die->name)
{
@@ -8493,3 +8732,68 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
SYMBOL_LOCATION_BATON (sym) = baton;
}
}
+
+/* Locate the compilation unit from CU's objfile which contains the
+ DIE at OFFSET. Returns NULL on failure.
+
+ We assume that OFFSET is not the start of the compilation unit header
+ (it can be the compilation unit DIE, though, which comes after the
+ header). */
+
+static struct dwarf2_per_cu_data *
+dwarf2_find_containing_comp_unit (unsigned long offset,
+ struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct dwarf2_per_cu_data *this_cu;
+ splay_tree cu_tree;
+ splay_tree_node node;
+
+ cu_tree = objfile_data (objfile, dwarf2_cu_tree);
+ if (cu_tree == NULL)
+ cu_tree = create_comp_unit_tree (cu);
+
+ node = splay_tree_predecessor (cu_tree, offset);
+ gdb_assert (node != NULL);
+
+ this_cu = (struct dwarf2_per_cu_data *) node->value;
+ gdb_assert (offset >= this_cu->offset);
+ gdb_assert (offset < this_cu->offset + this_cu->length);
+ return this_cu;
+}
+
+static void
+clear_per_cu_pointer (void *data)
+{
+ struct dwarf2_per_cu_data *this_cu, *per_cu;
+ struct dwarf2_cu *cu = data;
+
+ this_cu = cu->per_cu;
+ if (this_cu == NULL)
+ return;
+
+ per_cu = this_cu->cu->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ obstack_free (&per_cu->cu->partial_die_obstack, NULL);
+
+ next_cu = per_cu->cu->read_in_chain;
+ xfree (per_cu->cu);
+ per_cu->cu = NULL;
+ per_cu = next_cu;
+ }
+
+ /* This compilation unit is on the stack in dwarf2_build_psymtabs_hard,
+ so we should not xfree it. */
+ this_cu->cu = NULL;
+}
+
+void _initialize_dwarf2_read (void);
+
+void
+_initialize_dwarf2_read (void)
+{
+ dwarf2_cu_tree = register_objfile_data ();
+}