|  | /* DWARF 2 abbreviations | 
|  |  | 
|  | Copyright (C) 1994-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, | 
|  | Inc.  with support from Florida State University (under contract | 
|  | with the Ada Joint Program Office), and Silicon Graphics, Inc. | 
|  | Initial contribution by Brent Benson, Harris Computer Systems, Inc., | 
|  | based on Fred Fish's (Cygnus Support) implementation of DWARF 1 | 
|  | support. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "dwarf2/abbrev.h" | 
|  | #include "dwarf2/leb.h" | 
|  | #include "dwarf2/section.h" | 
|  | #include "bfd.h" | 
|  |  | 
|  | /* Helper function that returns true if a DIE with the given tag might | 
|  | plausibly be indexed.  */ | 
|  |  | 
|  | static bool | 
|  | tag_interesting_for_index (dwarf_tag tag) | 
|  | { | 
|  | switch (tag) | 
|  | { | 
|  | case DW_TAG_array_type: | 
|  | case DW_TAG_base_type: | 
|  | case DW_TAG_class_type: | 
|  | case DW_TAG_constant: | 
|  | case DW_TAG_entry_point: | 
|  | 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 false; | 
|  | } | 
|  |  | 
|  | /* Read in an abbrev table.  */ | 
|  |  | 
|  | abbrev_table_up | 
|  | 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; | 
|  |  | 
|  | abbrev_table_up abbrev_table (new struct abbrev_table (sect_off, section)); | 
|  | struct obstack *obstack = &abbrev_table->m_abbrev_obstack; | 
|  |  | 
|  | /* Caller must ensure this.  */ | 
|  | gdb_assert (section->readin); | 
|  | abbrev_ptr = section->buffer + to_underlying (sect_off); | 
|  |  | 
|  | while (true) | 
|  | { | 
|  | 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.  */ | 
|  | cur_abbrev->number = abbrev_number; | 
|  | cur_abbrev->tag | 
|  | = (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; | 
|  |  | 
|  | 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_external = false; | 
|  |  | 
|  | /* Now read in declarations.  */ | 
|  | int num_attrs = 0; | 
|  | for (;;) | 
|  | { | 
|  | struct attr_abbrev cur_attr; | 
|  |  | 
|  | cur_attr.name | 
|  | = (enum dwarf_attribute) read_unsigned_leb128 (abfd, abbrev_ptr, | 
|  | &bytes_read); | 
|  | abbrev_ptr += bytes_read; | 
|  | cur_attr.form | 
|  | = (enum dwarf_form) read_unsigned_leb128 (abfd, abbrev_ptr, | 
|  | &bytes_read); | 
|  | abbrev_ptr += bytes_read; | 
|  | if (cur_attr.form == DW_FORM_implicit_const) | 
|  | { | 
|  | 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) | 
|  | { | 
|  | 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_sibling: | 
|  | if (is_csize && cur_attr.form == DW_FORM_ref4) | 
|  | sibling_offset = size; | 
|  | 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; | 
|  | } | 
|  |  | 
|  | ++num_attrs; | 
|  | obstack_grow (obstack, &cur_attr, sizeof (cur_attr)); | 
|  | } | 
|  |  | 
|  | 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->tag == DW_TAG_namespace) | 
|  | && 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 | 
|  | 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; | 
|  | } |