+/* Returns nonzero if TAG represents a type that we might generate a partial
+ symbol for. */
+
+static int
+is_type_tag_for_partial (int tag)
+{
+ switch (tag)
+ {
+#if 0
+ /* Some types that would be reasonable to generate partial symbols for,
+ that we don't at present. */
+ case DW_TAG_array_type:
+ case DW_TAG_file_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+#endif
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Load all DIEs that are interesting for partial symbols into memory. */
+
+static struct partial_die_info *
+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;
+
+ int nesting_level = 1;
+
+ parent_die = NULL;
+ last_die = NULL;
+
+ cu->partial_dies
+ = htab_create_alloc_ex (cu->header.length / 12,
+ partial_die_hash,
+ partial_die_eq,
+ NULL,
+ &cu->comp_unit_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+
+ part_die = obstack_alloc (&cu->comp_unit_obstack,
+ sizeof (struct partial_die_info));
+
+ while (1)
+ {
+ abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu);
+
+ /* A NULL abbrev means the end of a series of children. */
+ if (abbrev == NULL)
+ {
+ if (--nesting_level == 0)
+ {
+ /* PART_DIE was probably the last thing allocated on the
+ comp_unit_obstack, so we could call obstack_free
+ here. We don't do that because the waste is small,
+ and will be cleaned up when we're done with this
+ compilation unit. This way, we're also more robust
+ against other users of the comp_unit_obstack. */
+ return first_die;
+ }
+ info_ptr += bytes_read;
+ last_die = parent_die;
+ parent_die = parent_die->die_parent;
+ continue;
+ }
+
+ /* Check whether this DIE is interesting enough to save. */
+ if (!is_type_tag_for_partial (abbrev->tag)
+ && abbrev->tag != DW_TAG_enumerator
+ && abbrev->tag != DW_TAG_subprogram
+ && abbrev->tag != DW_TAG_variable
+ && abbrev->tag != DW_TAG_namespace)
+ {
+ /* Otherwise we skip to the next sibling, if any. */
+ info_ptr = skip_one_die (info_ptr + bytes_read, abbrev, cu);
+ continue;
+ }
+
+ info_ptr = read_partial_die (part_die, abbrev, bytes_read,
+ abfd, info_ptr, cu);
+
+ /* This two-pass algorithm for processing partial symbols has a
+ high cost in cache pressure. Thus, handle some simple cases
+ here which cover the majority of C partial symbols. DIEs
+ which neither have specification tags in them, nor could have
+ specification tags elsewhere pointing at them, can simply be
+ processed and discarded.
+
+ This segment is also optional; scan_partial_symbols and
+ add_partial_symbol will handle these DIEs if we chain
+ them in normally. When compilers which do not emit large
+ quantities of duplicate debug information are more common,
+ this code can probably be removed. */
+
+ /* Any complete simple types at the top level (pretty much all
+ of them, for a language without namespaces), can be processed
+ directly. */
+ if (parent_die == NULL
+ && part_die->has_specification == 0
+ && part_die->is_declaration == 0
+ && (part_die->tag == DW_TAG_typedef
+ || part_die->tag == DW_TAG_base_type
+ || part_die->tag == DW_TAG_subrange_type))
+ {
+ 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,
+ 0, (CORE_ADDR) 0, cu->language, cu->objfile);
+ info_ptr = locate_pdi_sibling (part_die, info_ptr, abfd, cu);
+ continue;
+ }
+
+ /* If we're at the second level, and we're an enumerator, and
+ our parent has no specification (meaning possibly lives in a
+ namespace elsewhere), then we can add the partial symbol now
+ instead of queueing it. */
+ if (part_die->tag == DW_TAG_enumerator
+ && parent_die != NULL
+ && parent_die->die_parent == NULL
+ && parent_die->tag == DW_TAG_enumeration_type
+ && parent_die->has_specification == 0)
+ {
+ if (part_die->name == NULL)
+ complaint (&symfile_complaints, "malformed enumerator DIE ignored");
+ else if (building_psymtab)
+ add_psymbol_to_list (part_die->name, strlen (part_die->name),
+ VAR_DOMAIN, LOC_CONST,
+ cu->language == language_cplus
+ ? &cu->objfile->global_psymbols
+ : &cu->objfile->static_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, cu->objfile);
+
+ info_ptr = locate_pdi_sibling (part_die, info_ptr, abfd, cu);
+ continue;
+ }
+
+ /* We'll save this DIE so link it in. */
+ part_die->die_parent = parent_die;
+ part_die->die_sibling = NULL;
+ part_die->die_child = NULL;
+
+ if (last_die && last_die == parent_die)
+ last_die->die_child = part_die;
+ else if (last_die)
+ last_die->die_sibling = part_die;
+
+ last_die = part_die;
+
+ if (first_die == NULL)
+ first_die = part_die;
+
+ /* Maybe add the DIE to the hash table. Not all DIEs that we
+ find interesting need to be in the hash table, because we
+ also have the parent/sibling/child chains; only those that we
+ might refer to by offset later during partial symbol reading.
+
+ For now this means things that might have be the target of a
+ DW_AT_specification, DW_AT_abstract_origin, or
+ DW_AT_extension. DW_AT_extension will refer only to
+ namespaces; DW_AT_abstract_origin refers to functions (and
+ many things under the function DIE, but we do not recurse
+ into function DIEs during partial symbol reading) and
+ possibly variables as well; DW_AT_specification refers to
+ declarations. Declarations ought to have the DW_AT_declaration
+ flag. It happens that GCC forgets to put it in sometimes, but
+ only for functions, not for types.
+
+ Adding more things than necessary to the hash table is harmless
+ except for the performance cost. Adding too few will result in
+ internal errors in find_partial_die. */
+
+ if (abbrev->tag == DW_TAG_subprogram
+ || abbrev->tag == DW_TAG_variable
+ || abbrev->tag == DW_TAG_namespace
+ || part_die->is_declaration)
+ {
+ void **slot;
+
+ slot = htab_find_slot_with_hash (cu->partial_dies, part_die,
+ part_die->offset, INSERT);
+ *slot = part_die;
+ }
+
+ part_die = obstack_alloc (&cu->comp_unit_obstack,
+ sizeof (struct partial_die_info));
+
+ /* For some DIEs we want to follow their children (if any). For C
+ we have no reason to follow the children of structures; for other
+ languages we have to, both so that we can get at method physnames
+ to infer fully qualified class names, and for DW_AT_specification. */
+ if (last_die->has_children
+ && (last_die->tag == DW_TAG_namespace
+ || last_die->tag == DW_TAG_enumeration_type
+ || (cu->language != language_c
+ && (last_die->tag == DW_TAG_class_type
+ || last_die->tag == DW_TAG_structure_type
+ || last_die->tag == DW_TAG_union_type))))
+ {
+ nesting_level++;
+ parent_die = last_die;
+ continue;
+ }
+
+ /* Otherwise we skip to the next sibling, if any. */
+ info_ptr = locate_pdi_sibling (last_die, info_ptr, abfd, cu);
+
+ /* Back to the top, do it again. */
+ }
+}
+