+ /* Process the dies in the type unit. */
+ if (die->child == NULL)
+ {
+ dump_die_for_error (die);
+ error (_("Dwarf Error: Missing children for type unit [in module %s]"),
+ bfd_get_filename (abfd));
+ }
+
+ child_die = die->child;
+
+ while (child_die && child_die->tag)
+ {
+ process_die (child_die, cu);
+
+ child_die = sibling_die (child_die);
+ }
+
+ do_cleanups (back_to);
+}
+\f
+/* DWO files. */
+
+static hashval_t
+hash_dwo_file (const void *item)
+{
+ const struct dwo_file *dwo_file = item;
+
+ return htab_hash_string (dwo_file->dwo_name);
+}
+
+static int
+eq_dwo_file (const void *item_lhs, const void *item_rhs)
+{
+ const struct dwo_file *lhs = item_lhs;
+ const struct dwo_file *rhs = item_rhs;
+
+ return strcmp (lhs->dwo_name, rhs->dwo_name) == 0;
+}
+
+/* Allocate a hash table for DWO files. */
+
+static htab_t
+allocate_dwo_file_hash_table (void)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+
+ return htab_create_alloc_ex (41,
+ hash_dwo_file,
+ eq_dwo_file,
+ NULL,
+ &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+}
+
+static hashval_t
+hash_dwo_unit (const void *item)
+{
+ const struct dwo_unit *dwo_unit = item;
+
+ /* This drops the top 32 bits of the id, but is ok for a hash. */
+ return dwo_unit->signature;
+}
+
+static int
+eq_dwo_unit (const void *item_lhs, const void *item_rhs)
+{
+ const struct dwo_unit *lhs = item_lhs;
+ const struct dwo_unit *rhs = item_rhs;
+
+ /* The signature is assumed to be unique within the DWO file.
+ So while object file CU dwo_id's always have the value zero,
+ that's OK, assuming each object file DWO file has only one CU,
+ and that's the rule for now. */
+ return lhs->signature == rhs->signature;
+}
+
+/* Allocate a hash table for DWO CUs,TUs.
+ There is one of these tables for each of CUs,TUs for each DWO file. */
+
+static htab_t
+allocate_dwo_unit_table (struct objfile *objfile)
+{
+ /* Start out with a pretty small number.
+ Generally DWO files contain only one CU and maybe some TUs. */
+ return htab_create_alloc_ex (3,
+ hash_dwo_unit,
+ eq_dwo_unit,
+ NULL,
+ &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+}
+
+/* This function is mapped across the sections and remembers the offset and
+ size of each of the DWO debugging sections we are interested in. */
+
+static void
+dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_file_ptr)
+{
+ struct dwo_file *dwo_file = dwo_file_ptr;
+ const struct dwo_section_names *names = &dwo_section_names;
+
+ if (section_is_p (sectp->name, &names->abbrev_dwo))
+ {
+ dwo_file->sections.abbrev.asection = sectp;
+ dwo_file->sections.abbrev.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->info_dwo))
+ {
+ dwo_file->sections.info.asection = sectp;
+ dwo_file->sections.info.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->line_dwo))
+ {
+ dwo_file->sections.line.asection = sectp;
+ dwo_file->sections.line.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->loc_dwo))
+ {
+ dwo_file->sections.loc.asection = sectp;
+ dwo_file->sections.loc.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->str_dwo))
+ {
+ dwo_file->sections.str.asection = sectp;
+ dwo_file->sections.str.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->str_offsets_dwo))
+ {
+ dwo_file->sections.str_offsets.asection = sectp;
+ dwo_file->sections.str_offsets.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->types_dwo))
+ {
+ struct dwarf2_section_info type_section;
+
+ memset (&type_section, 0, sizeof (type_section));
+ type_section.asection = sectp;
+ type_section.size = bfd_get_section_size (sectp);
+ VEC_safe_push (dwarf2_section_info_def, dwo_file->sections.types,
+ &type_section);
+ }
+}
+
+/* Structure used to pass data to create_debug_info_hash_table_reader. */
+
+struct create_dwo_info_table_data
+{
+ struct dwo_file *dwo_file;
+ htab_t cu_htab;
+};
+
+/* die_reader_func for create_debug_info_hash_table. */
+
+static void
+create_debug_info_hash_table_reader (const struct die_reader_specs *reader,
+ gdb_byte *info_ptr,
+ struct die_info *comp_unit_die,
+ int has_children,
+ void *datap)
+{
+ struct dwarf2_cu *cu = reader->cu;
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ sect_offset offset = cu->per_cu->offset;
+ struct dwarf2_section_info *section = cu->per_cu->info_or_types_section;
+ struct create_dwo_info_table_data *data = datap;
+ struct dwo_file *dwo_file = data->dwo_file;
+ htab_t cu_htab = data->cu_htab;
+ void **slot;
+ struct attribute *attr;
+ struct dwo_unit *dwo_unit;
+
+ attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);
+ if (attr == NULL)
+ {
+ error (_("Dwarf Error: debug entry at offset 0x%x is missing"
+ " its dwo_id [in module %s]"),
+ offset.sect_off, dwo_file->dwo_name);
+ return;
+ }
+
+ dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+ dwo_unit->dwo_file = dwo_file;
+ dwo_unit->signature = DW_UNSND (attr);
+ dwo_unit->info_or_types_section = section;
+ dwo_unit->offset = offset;
+ dwo_unit->length = cu->per_cu->length;
+
+ slot = htab_find_slot (cu_htab, dwo_unit, INSERT);
+ gdb_assert (slot != NULL);
+ if (*slot != NULL)
+ {
+ const struct dwo_unit *dup_dwo_unit = *slot;
+
+ complaint (&symfile_complaints,
+ _("debug entry at offset 0x%x is duplicate to the entry at"
+ " offset 0x%x, dwo_id 0x%s [in module %s]"),
+ offset.sect_off, dup_dwo_unit->offset.sect_off,
+ phex (dwo_unit->signature, sizeof (dwo_unit->signature)),
+ dwo_file->dwo_name);
+ }
+ else
+ *slot = dwo_unit;
+
+ if (dwarf2_die_debug)
+ fprintf_unfiltered (gdb_stdlog, " offset 0x%x, dwo_id 0x%s\n",
+ offset.sect_off,
+ phex (dwo_unit->signature,
+ sizeof (dwo_unit->signature)));
+}
+
+/* Create a hash table to map DWO IDs to their CU entry in .debug_info.dwo. */
+
+static htab_t
+create_debug_info_hash_table (struct dwo_file *dwo_file)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwarf2_section_info *section = &dwo_file->sections.info;
+ bfd *abfd;
+ htab_t cu_htab;
+ gdb_byte *info_ptr, *end_ptr;
+ struct create_dwo_info_table_data create_dwo_info_table_data;
+
+ dwarf2_read_section (objfile, section);
+ info_ptr = section->buffer;
+
+ if (info_ptr == NULL)
+ return NULL;
+
+ /* We can't set abfd until now because the section may be empty or
+ not present, in which case section->asection will be NULL. */
+ abfd = section->asection->owner;
+
+ if (dwarf2_die_debug)
+ fprintf_unfiltered (gdb_stdlog, "Reading .debug_info.dwo for %s:\n",
+ bfd_get_filename (abfd));
+
+ cu_htab = allocate_dwo_unit_table (objfile);
+
+ create_dwo_info_table_data.dwo_file = dwo_file;
+ create_dwo_info_table_data.cu_htab = cu_htab;
+
+ end_ptr = info_ptr + section->size;
+ while (info_ptr < end_ptr)
+ {
+ struct dwarf2_per_cu_data per_cu;
+
+ memset (&per_cu, 0, sizeof (per_cu));
+ per_cu.objfile = objfile;
+ per_cu.is_debug_types = 0;
+ per_cu.offset.sect_off = info_ptr - section->buffer;
+ per_cu.info_or_types_section = section;
+
+ init_cutu_and_read_dies_no_follow (&per_cu,
+ &dwo_file->sections.abbrev,
+ dwo_file,
+ create_debug_info_hash_table_reader,
+ &create_dwo_info_table_data);
+
+ info_ptr += per_cu.length;
+ }
+
+ return cu_htab;
+}
+
+/* Subroutine of open_dwo_file to simplify it.
+ Open the file specified by FILE_NAME and hand it off to BFD for
+ preliminary analysis. Return a newly initialized bfd *, which
+ includes a canonicalized copy of FILE_NAME.
+ In case of trouble, return NULL.
+ NOTE: This function is derived from symfile_bfd_open. */
+
+static bfd *
+try_open_dwo_file (const char *file_name)
+{
+ bfd *sym_bfd;
+ int desc;
+ char *absolute_name;
+
+ desc = openp (debug_file_directory, OPF_TRY_CWD_FIRST, file_name,
+ O_RDONLY | O_BINARY, &absolute_name);
+ if (desc < 0)
+ return NULL;
+
+ sym_bfd = bfd_fopen (absolute_name, gnutarget, FOPEN_RB, desc);
+ if (!sym_bfd)
+ {
+ xfree (absolute_name);
+ return NULL;
+ }
+ bfd_set_cacheable (sym_bfd, 1);
+
+ if (!bfd_check_format (sym_bfd, bfd_object))
+ {
+ bfd_close (sym_bfd); /* This also closes desc. */
+ xfree (absolute_name);
+ return NULL;
+ }
+
+ /* bfd_usrdata exists for applications and libbfd must not touch it. */
+ gdb_assert (bfd_usrdata (sym_bfd) == NULL);
+
+ return sym_bfd;
+}
+
+/* Try to open DWO file DWO_NAME.
+ COMP_DIR is the DW_AT_comp_dir attribute.
+ The result is the bfd handle of the file.
+ If there is a problem finding or opening the file, return NULL.
+ Upon success, the canonicalized path of the file is stored in the bfd,
+ same as symfile_bfd_open. */
+
+static bfd *
+open_dwo_file (const char *dwo_name, const char *comp_dir)
+{
+ bfd *abfd;
+
+ if (IS_ABSOLUTE_PATH (dwo_name))
+ return try_open_dwo_file (dwo_name);
+
+ /* Before trying the search path, try DWO_NAME in COMP_DIR. */
+
+ if (comp_dir != NULL)
+ {
+ char *path_to_try = concat (comp_dir, SLASH_STRING, dwo_name, NULL);
+
+ /* NOTE: If comp_dir is a relative path, this will also try the
+ search path, which seems useful. */
+ abfd = try_open_dwo_file (path_to_try);
+ xfree (path_to_try);
+ if (abfd != NULL)
+ return abfd;
+ }
+
+ /* That didn't work, try debug-file-directory, which, despite its name,
+ is a list of paths. */
+
+ if (*debug_file_directory == '\0')
+ return NULL;
+
+ return try_open_dwo_file (dwo_name);
+}
+
+/* Initialize the use of the DWO file specified by DWO_NAME. */
+
+static struct dwo_file *
+init_dwo_file (const char *dwo_name, const char *comp_dir)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwo_file *dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwo_file);
+ bfd *abfd;
+ struct cleanup *cleanups;
+
+ if (dwarf2_die_debug)
+ fprintf_unfiltered (gdb_stdlog, "Reading DWO file %s:\n", dwo_name);
+
+ abfd = open_dwo_file (dwo_name, comp_dir);
+ if (abfd == NULL)
+ return NULL;
+ dwo_file->dwo_name = dwo_name;
+ dwo_file->dwo_bfd = abfd;
+
+ cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file);
+
+ bfd_map_over_sections (abfd, dwarf2_locate_dwo_sections, dwo_file);
+
+ dwo_file->cus = create_debug_info_hash_table (dwo_file);
+
+ dwo_file->tus = create_debug_types_hash_table (dwo_file,
+ dwo_file->sections.types);
+
+ discard_cleanups (cleanups);
+
+ return dwo_file;
+}
+
+/* Lookup DWO file DWO_NAME. */
+
+static struct dwo_file *
+lookup_dwo_file (char *dwo_name, const char *comp_dir)
+{
+ struct dwo_file *dwo_file;
+ struct dwo_file find_entry;
+ void **slot;
+
+ if (dwarf2_per_objfile->dwo_files == NULL)
+ dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table ();
+
+ /* Have we already seen this DWO file? */
+ find_entry.dwo_name = dwo_name;
+ slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT);
+
+ /* If not, read it in and build a table of the DWOs it contains. */
+ if (*slot == NULL)
+ *slot = init_dwo_file (dwo_name, comp_dir);
+
+ /* NOTE: This will be NULL if unable to open the file. */
+ dwo_file = *slot;
+
+ return dwo_file;
+}
+
+/* Lookup the DWO CU referenced from THIS_CU in DWO file DWO_NAME.
+ If non-NULL, comp_dir is the DW_AT_comp_dir attribute.
+ SIGNATURE is the "dwo_id" of the CU (for consistency we use the same
+ nomenclature as TUs).
+ The result is the DWO CU or NULL if we didn't find it
+ (dwo_id mismatch or couldn't find the DWO file). */
+
+static struct dwo_unit *
+lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu,
+ char *dwo_name, const char *comp_dir,
+ ULONGEST signature)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwo_file *dwo_file;
+
+ dwo_file = lookup_dwo_file (dwo_name, comp_dir);
+ if (dwo_file == NULL)
+ return NULL;
+
+ /* Look up the DWO using its signature(dwo_id). */
+
+ if (dwo_file->cus != NULL)
+ {
+ struct dwo_unit find_dwo_cu, *dwo_cu;
+
+ find_dwo_cu.signature = signature;
+ dwo_cu = htab_find (dwo_file->cus, &find_dwo_cu);
+
+ if (dwo_cu != NULL)
+ return dwo_cu;
+ }
+
+ /* We didn't find it. This must mean a dwo_id mismatch. */
+
+ complaint (&symfile_complaints,
+ _("Could not find DWO CU referenced by CU at offset 0x%x"
+ " [in module %s]"),
+ this_cu->offset.sect_off, objfile->name);
+ return NULL;
+}
+
+/* Lookup the DWO TU referenced from THIS_TU in DWO file DWO_NAME.
+ If non-NULL, comp_dir is the DW_AT_comp_dir attribute.
+ The result is the DWO CU or NULL if we didn't find it
+ (dwo_id mismatch or couldn't find the DWO file). */
+
+static struct dwo_unit *
+lookup_dwo_type_unit (struct signatured_type *this_tu,
+ char *dwo_name, const char *comp_dir)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwo_file *dwo_file;
+
+ dwo_file = lookup_dwo_file (dwo_name, comp_dir);
+ if (dwo_file == NULL)
+ return NULL;
+
+ /* Look up the DWO using its signature(dwo_id). */
+
+ if (dwo_file->tus != NULL)
+ {
+ struct dwo_unit find_dwo_tu, *dwo_tu;
+
+ find_dwo_tu.signature = this_tu->signature;
+ dwo_tu = htab_find (dwo_file->tus, &find_dwo_tu);
+
+ if (dwo_tu != NULL)
+ return dwo_tu;
+ }
+
+ /* We didn't find it. This must mean a dwo_id mismatch. */
+
+ complaint (&symfile_complaints,
+ _("Could not find DWO TU referenced by TU at offset 0x%x"
+ " [in module %s]"),
+ this_tu->per_cu.offset.sect_off, objfile->name);
+ return NULL;
+}
+
+/* Free all resources associated with DWO_FILE.
+ Close the DWO file and munmap the sections.
+ All memory should be on the objfile obstack. */
+
+static void
+free_dwo_file (struct dwo_file *dwo_file, struct objfile *objfile)
+{
+ int ix;
+ struct dwarf2_section_info *section;
+
+ gdb_assert (dwo_file->dwo_bfd != objfile->obfd);
+ bfd_close (dwo_file->dwo_bfd);
+
+ munmap_section_buffer (&dwo_file->sections.abbrev);
+ munmap_section_buffer (&dwo_file->sections.info);
+ munmap_section_buffer (&dwo_file->sections.line);
+ munmap_section_buffer (&dwo_file->sections.loc);
+ munmap_section_buffer (&dwo_file->sections.str);
+ munmap_section_buffer (&dwo_file->sections.str_offsets);
+
+ for (ix = 0;
+ VEC_iterate (dwarf2_section_info_def, dwo_file->sections.types,
+ ix, section);
+ ++ix)
+ munmap_section_buffer (section);
+
+ VEC_free (dwarf2_section_info_def, dwo_file->sections.types);
+}
+
+/* Wrapper for free_dwo_file for use in cleanups. */
+
+static void
+free_dwo_file_cleanup (void *arg)
+{
+ struct dwo_file *dwo_file = (struct dwo_file *) arg;
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+
+ free_dwo_file (dwo_file, objfile);
+}
+
+/* Traversal function for free_dwo_files. */