/* DWARF 2 abbreviations
- Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Copyright (C) 1994-2023 Free Software Foundation, Inc.
Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
Inc. with support from Florida State University (under contract
hash_abbrev (const void *item)
{
const struct abbrev_info *info = (const struct abbrev_info *) item;
+ /* Warning: if you change this next line, you must also update the
+ other code in this class using the _with_hash functions. */
return info->number;
}
dies from a section we read in all abbreviations and install them
in a hash table. */
-abbrev_table::abbrev_table (sect_offset off)
+abbrev_table::abbrev_table (sect_offset off, struct dwarf2_section_info *sect)
: sect_off (off),
+ section (sect),
m_abbrevs (htab_create_alloc (20, hash_abbrev, eq_abbrev,
nullptr, xcalloc, xfree))
{
}
-/* Allocate space for a struct abbrev_info object in ABBREV_TABLE. */
-
-struct abbrev_info *
-abbrev_table::alloc_abbrev ()
-{
- struct abbrev_info *abbrev;
-
- abbrev = XOBNEW (&m_abbrev_obstack, struct abbrev_info);
- memset (abbrev, 0, sizeof (struct abbrev_info));
-
- return abbrev;
-}
-
/* Add an abbreviation to the table. */
void
-abbrev_table::add_abbrev (unsigned int abbrev_number,
- struct abbrev_info *abbrev)
+abbrev_table::add_abbrev (struct abbrev_info *abbrev)
{
- void **slot = htab_find_slot (m_abbrevs.get (), abbrev, INSERT);
+ void **slot = htab_find_slot_with_hash (m_abbrevs.get (), abbrev,
+ abbrev->number, INSERT);
*slot = abbrev;
}
-/* Look up an abbrev in the table.
- Returns NULL if the abbrev is not found. */
+/* Helper function that returns true if a DIE with the given tag might
+ plausibly be indexed. */
-struct abbrev_info *
-abbrev_table::lookup_abbrev (unsigned int abbrev_number)
+static bool
+tag_interesting_for_index (dwarf_tag tag)
{
- struct abbrev_info search;
- search.number = abbrev_number;
+ switch (tag)
+ {
+ case DW_TAG_array_type:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_enumerator:
+ case DW_TAG_imported_declaration:
+ case DW_TAG_imported_unit:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_interface_type:
+ case DW_TAG_module:
+ case DW_TAG_namespace:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_string_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_subrange_type:
+ case DW_TAG_generic_subrange:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ case DW_TAG_unspecified_type:
+ case DW_TAG_variable:
+ return true;
+ }
- return (struct abbrev_info *) htab_find (m_abbrevs.get (), &search);
+ return false;
}
/* Read in an abbrev table. */
abbrev_table_up
-abbrev_table::read (struct objfile *objfile,
- struct dwarf2_section_info *section,
+abbrev_table::read (struct dwarf2_section_info *section,
sect_offset sect_off)
{
bfd *abfd = section->get_bfd_owner ();
const gdb_byte *abbrev_ptr;
struct abbrev_info *cur_abbrev;
- unsigned int abbrev_number, bytes_read, abbrev_name;
- unsigned int abbrev_form;
- std::vector<struct attr_abbrev> cur_attrs;
- abbrev_table_up abbrev_table (new struct abbrev_table (sect_off));
+ abbrev_table_up abbrev_table (new struct abbrev_table (sect_off, section));
+ struct obstack *obstack = &abbrev_table->m_abbrev_obstack;
- section->read (objfile);
+ /* Caller must ensure this. */
+ gdb_assert (section->readin);
abbrev_ptr = section->buffer + to_underlying (sect_off);
- abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
- /* Loop until we reach an abbrev number of 0. */
- while (abbrev_number)
+ while (true)
{
- cur_attrs.clear ();
- cur_abbrev = abbrev_table->alloc_abbrev ();
+ unsigned int bytes_read;
+ /* Loop until we reach an abbrev number of 0. */
+ unsigned int abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
+ if (abbrev_number == 0)
+ break;
+ abbrev_ptr += bytes_read;
+
+ /* Start without any attrs. */
+ obstack_blank (obstack, offsetof (abbrev_info, attrs));
+ cur_abbrev = (struct abbrev_info *) obstack_base (obstack);
- /* read in abbrev header */
+ /* Read in abbrev header. */
cur_abbrev->number = abbrev_number;
cur_abbrev->tag
- = (enum dwarf_tag) read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ = (enum dwarf_tag) read_unsigned_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
abbrev_ptr += bytes_read;
cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
abbrev_ptr += 1;
- /* now read in declarations */
+ unsigned int size = 0;
+ unsigned int sibling_offset = -1;
+ bool is_csize = true;
+
+ bool has_hardcoded_declaration = false;
+ bool has_specification_or_origin = false;
+ bool has_name = false;
+ bool has_linkage_name = false;
+ bool has_location = false;
+ bool has_external = false;
+
+ /* Now read in declarations. */
+ int num_attrs = 0;
for (;;)
{
- LONGEST implicit_const;
+ struct attr_abbrev cur_attr;
- abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ cur_attr.name
+ = (enum dwarf_attribute) read_unsigned_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
abbrev_ptr += bytes_read;
- abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ cur_attr.form
+ = (enum dwarf_form) read_unsigned_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
abbrev_ptr += bytes_read;
- if (abbrev_form == DW_FORM_implicit_const)
+ if (cur_attr.form == DW_FORM_implicit_const)
{
- implicit_const = read_signed_leb128 (abfd, abbrev_ptr,
- &bytes_read);
+ cur_attr.implicit_const = read_signed_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
abbrev_ptr += bytes_read;
}
else
+ cur_attr.implicit_const = -1;
+
+ if (cur_attr.name == 0)
+ break;
+
+ switch (cur_attr.name)
{
- /* Initialize it due to a false compiler warning. */
- implicit_const = -1;
+ case DW_AT_declaration:
+ if (cur_attr.form == DW_FORM_flag_present)
+ has_hardcoded_declaration = true;
+ break;
+
+ case DW_AT_external:
+ has_external = true;
+ break;
+
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_extension:
+ has_specification_or_origin = true;
+ break;
+
+ case DW_AT_name:
+ has_name = true;
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ has_linkage_name = true;
+ break;
+
+ case DW_AT_const_value:
+ case DW_AT_location:
+ has_location = true;
+ break;
+
+ case DW_AT_sibling:
+ if (is_csize && cur_attr.form == DW_FORM_ref4)
+ sibling_offset = size;
+ break;
}
- if (abbrev_name == 0)
- break;
+ switch (cur_attr.form)
+ {
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_strx1:
+ size += 1;
+ break;
+ case DW_FORM_flag_present:
+ case DW_FORM_implicit_const:
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ case DW_FORM_strx2:
+ size += 2;
+ break;
+ case DW_FORM_strx3:
+ size += 3;
+ break;
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_strx4:
+ size += 4;
+ break;
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ size += 8;
+ break;
+ case DW_FORM_data16:
+ size += 16;
+ break;
+
+ default:
+ is_csize = false;
+ break;
+ }
- cur_attrs.emplace_back ();
- struct attr_abbrev &cur_attr = cur_attrs.back ();
- cur_attr.name = (enum dwarf_attribute) abbrev_name;
- cur_attr.form = (enum dwarf_form) abbrev_form;
- cur_attr.implicit_const = implicit_const;
+ ++num_attrs;
+ obstack_grow (obstack, &cur_attr, sizeof (cur_attr));
}
- cur_abbrev->num_attrs = cur_attrs.size ();
- cur_abbrev->attrs =
- XOBNEWVEC (&abbrev_table->m_abbrev_obstack, struct attr_abbrev,
- cur_abbrev->num_attrs);
- if (!cur_attrs.empty ())
- memcpy (cur_abbrev->attrs, cur_attrs.data (),
- cur_abbrev->num_attrs * sizeof (struct attr_abbrev));
-
- abbrev_table->add_abbrev (abbrev_number, cur_abbrev);
-
- /* Get next abbreviation.
- Under Irix6 the abbreviations for a compilation unit are not
- always properly terminated with an abbrev number of 0.
- Exit loop if we encounter an abbreviation which we have
- already read (which means we are about to read the abbreviations
- for the next compile unit) or if the end of the abbreviation
- table is reached. */
- if ((unsigned int) (abbrev_ptr - section->buffer) >= section->size)
- break;
- abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
- if (abbrev_table->lookup_abbrev (abbrev_number) != NULL)
- break;
+ cur_abbrev = (struct abbrev_info *) obstack_finish (obstack);
+ cur_abbrev->num_attrs = num_attrs;
+
+ if (!has_name && !has_linkage_name && !has_specification_or_origin)
+ {
+ /* Some anonymous DIEs are worth examining. */
+ cur_abbrev->interesting
+ = (cur_abbrev->tag == DW_TAG_namespace
+ || cur_abbrev->tag == DW_TAG_enumeration_type);
+ }
+ else if ((cur_abbrev->tag == DW_TAG_structure_type
+ || cur_abbrev->tag == DW_TAG_class_type
+ || cur_abbrev->tag == DW_TAG_union_type)
+ && cur_abbrev->has_children)
+ {
+ /* We have to record this as interesting, regardless of how
+ DW_AT_declaration is set, so that any subsequent
+ DW_AT_specification pointing at a child of this will get
+ the correct scope. */
+ cur_abbrev->interesting = true;
+ }
+ else if (has_hardcoded_declaration
+ && (cur_abbrev->tag != DW_TAG_variable || !has_external))
+ cur_abbrev->interesting = false;
+ else if (!tag_interesting_for_index (cur_abbrev->tag))
+ cur_abbrev->interesting = false;
+ else if (!has_location && !has_specification_or_origin && !has_external
+ && cur_abbrev->tag == DW_TAG_variable)
+ cur_abbrev->interesting = false;
+ else
+ cur_abbrev->interesting = true;
+
+ /* If there are no children, and the abbrev has a constant size,
+ then we don't care about the sibling offset, because it's
+ simple to just skip the entire DIE without reading a sibling
+ offset. */
+ if ((!cur_abbrev->has_children && is_csize)
+ /* Overflow. */
+ || sibling_offset != (unsigned short) sibling_offset)
+ sibling_offset = -1;
+ cur_abbrev->size_if_constant = is_csize ? size : 0;
+ cur_abbrev->sibling_offset = sibling_offset;
+
+ abbrev_table->add_abbrev (cur_abbrev);
}
return abbrev_table;