Remove OBJF_REORDERED
[binutils-gdb.git] / gdb / dwarf2 / abbrev.c
index f843e32d950b0b279341cee7ee73a0b3163c4338..1ebf8f6eed51b6b18a684684c4f23b9104cf6148 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
@@ -36,6 +36,8 @@ static hashval_t
 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;
 }
 
@@ -56,136 +58,262 @@ eq_abbrev (const void *lhs, const void *rhs)
    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;
-         ++cur_abbrev->num_attrs;
+         ++num_attrs;
+         obstack_grow (obstack, &cur_attr, sizeof (cur_attr));
        }
 
-      cur_abbrev->attrs =
-       XOBNEWVEC (&abbrev_table->m_abbrev_obstack, struct attr_abbrev,
-                  cur_abbrev->num_attrs);
-      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;