From patchwork Sun Jun 18 19:33:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kratochvil X-Patchwork-Id: 21069 Received: (qmail 40206 invoked by alias); 18 Jun 2017 19:33:11 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 40194 invoked by uid 89); 18 Jun 2017 19:33:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_STOCKGEN, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 18 Jun 2017 19:33:01 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A86F1C04B317; Sun, 18 Jun 2017 19:33:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com A86F1C04B317 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=jan.kratochvil@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com A86F1C04B317 Received: from host1.jankratochvil.net (ovpn-116-67.ams2.redhat.com [10.36.116.67]) by smtp.corp.redhat.com (Postfix) with ESMTP id 653CC183E6; Sun, 18 Jun 2017 19:33:03 +0000 (UTC) Subject: [PATCH v2 5/5] DWARF-5: .debug_names index consumer From: Jan Kratochvil To: gdb-patches@sourceware.org Cc: Victor Leschuk Date: Sun, 18 Jun 2017 21:33:02 +0200 Message-ID: <149781438249.10382.13230549403227962191.stgit@host1.jankratochvil.net> In-Reply-To: <149781434459.10382.10368140746387313573.stgit@host1.jankratochvil.net> References: <149781434459.10382.10368140746387313573.stgit@host1.jankratochvil.net> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Hi, it is not regression-free against no-index but it is regression-free against .gdb_index. That is because .gdb_index is not regression-free against no-index. Some testcases needed to be updated as they were missing .debug_aranges. While that does not matter for no-index (as GDB builds the mapping internally during dwarf2_build_psymtabs_hard) and neither for .gdb_index (as GDB uses that internally built mapping which it stores into .gdb_index) it does matter for .debug_names as that simply assumes existing .debug_aranges from GCC. I tried some performance checking but the index handling speed is negligible compared to the CU expansion associated with it. .debug_names looked even as a bit faster to me than .gdb_index which rather surprised me but I did not investigate it more. Jan gdb/ChangeLog 2017-05-26 Jan Kratochvil * defs.h (elf_sym_fns_debug_names): New declaration. * dwarf2read.c (mapped_debug_names): New. (struct dwarf2_per_objfile): Add debug_names, debug_aranges and debug_names_table. (dwarf2_elf_names): Add debug_names and debug_aranges. (struct dwz_file): Add debug_names. (dwarf2_locate_sections): Add debug_names and debug_aranges. (locate_dwz_sections): Add debug_names. (create_signatured_type_table_from_debug_names) (create_addrmap_from_aranges): New. (dwarf2_read_index): Update function comment. (read_debug_names_from_section, create_cus_from_debug_names_list) (create_cus_from_debug_names, dwarf2_read_debug_names): New. (dwarf5_djb_hash): Function renamed from DebugNamesNameTable::djb_hash. (dw2_debug_names_iterator): New. (read_indirect_string_at_offset): New declaration. (mapped_debug_names::namei_to_name) (dw2_debug_names_iterator::find_vec_in_debug_names) (dw2_debug_names_iterator::find_vec_in_debug_names) (dw2_debug_names_iterator::next, dw2_debug_names_lookup_symbol) (dw2_debug_names_dump, dw2_debug_names_expand_symtabs_for_function) (dw2_debug_names_expand_symtabs_matching, dwarf2_debug_names_functions): New. (dwarf2_initialize_objfile): Return also elf_sym_fns_debug_names. (dwarf2_free_objfile): Delete also debug_names_table; (debug_names::djb_hash): Rename it to dwarf5_djb_hash. (debug_names::build): Update djb_hash caller. * elfread.c (elf_sym_fns_debug_names): New. * psymtab.h (dwarf2_debug_names_functions): New declaration. * symfile.h (struct dwarf2_debug_sections): Add debug_names and debug_aranges. * xcoffread.c (dwarf2_xcoff_names): Add debug_names and debug_aranges. gdb/testsuite/ChangeLog 2017-05-26 Jan Kratochvil * gdb.base/maint.exp (check for .gdb_index): Check also for .debug_names. * gdb.dlang/watch-loc.c (.debug_aranges): New. * gdb.dwarf2/dw2-case-insensitive-debug.S: Likewise. * gdb.dwarf2/gdb-index.exp (check if index present, .gdb_index used) (.gdb_index used after symbol reloading): Support also .debug_names. * gdb.mi/dw2-ref-missing-frame-func.c (.debug_aranges): New. --- gdb/defs.h | 1 gdb/dwarf2read.c | 1474 +++++++++++++++++--- gdb/elfread.c | 17 gdb/psymtab.h | 1 gdb/symfile.h | 2 gdb/testsuite/gdb.base/maint.exp | 7 gdb/testsuite/gdb.dlang/watch-loc.c | 19 .../gdb.dwarf2/dw2-case-insensitive-debug.S | 17 gdb/testsuite/gdb.dwarf2/gdb-index.exp | 7 gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c | 20 gdb/xcoffread.c | 2 11 files changed, 1378 insertions(+), 189 deletions(-) diff --git a/gdb/defs.h b/gdb/defs.h index 516c234..7916b99 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -762,6 +762,7 @@ extern void initialize_inferiors (void); extern const struct sym_fns elf_sym_fns_lazy_psyms; extern const struct sym_fns elf_sym_fns_gdb_index; +extern const struct sym_fns elf_sym_fns_debug_names; /* * Special block numbers */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 3137d2f..56aa3ea 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -211,6 +211,41 @@ struct mapped_index const char *constant_pool; }; +/* A description of the mapped .debug_names. + Uninitialized map has CU_COUNT 0. */ +class mapped_debug_names +{ +public: + bfd_endian dwarf5_byte_order; + bool dwarf5_is_dwarf64; + uint8_t offset_size; + uint32_t cu_count = 0; + uint32_t tu_count, bucket_count, name_count; + const gdb_byte *cu_table_reordered, *tu_table_reordered; + const uint32_t *bucket_table_reordered, *hash_table_reordered; + const gdb_byte *name_table_string_offs_reordered; + const gdb_byte *name_table_entry_offs_reordered; + const gdb_byte *entry_pool; + class index_val + { + public: + ULONGEST dwarf_tag; + class attr + { + public: + /* Attribute name DW_IDX_*. */ + ULONGEST dw_idx; + /* Attribute form DW_FORM_*. */ + ULONGEST form; + /* Value if FORM is DW_FORM_implicit_const. */ + LONGEST implicit_const; + }; + std::vector attr_vec; + }; + std::unordered_map abbrev_map; + const char *namei_to_name (uint32_t namei) const; +}; + typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr; DEF_VEC_P (dwarf2_per_cu_ptr); @@ -243,6 +278,8 @@ struct dwarf2_per_objfile struct dwarf2_section_info frame; struct dwarf2_section_info eh_frame; struct dwarf2_section_info gdb_index; + struct dwarf2_section_info debug_names; + struct dwarf2_section_info debug_aranges; VEC (dwarf2_section_info_def) *types; @@ -308,6 +345,9 @@ struct dwarf2_per_objfile /* The mapped index, or NULL if .gdb_index is missing or not being used. */ struct mapped_index *index_table; + /* The mapped index, or NULL if .debug_names is missing or not being used. */ + mapped_debug_names *debug_names_table; + /* When using index_table, this keeps track of all quick_file_names entries. TUs typically share line table entries with a CU, so we maintain a separate table of all line table entries to support the sharing. @@ -358,6 +398,8 @@ static const struct dwarf2_debug_sections dwarf2_elf_names = { ".debug_frame", ".zdebug_frame" }, { ".eh_frame", NULL }, { ".gdb_index", ".zgdb_index" }, + { ".debug_names", ".zdebug_names" }, + { ".debug_aranges", ".zdebug_aranges" }, 23 }; @@ -1019,6 +1061,7 @@ struct dwz_file struct dwarf2_section_info line; struct dwarf2_section_info macro; struct dwarf2_section_info gdb_index; + struct dwarf2_section_info debug_names; /* The dwz's BFD. */ bfd *dwz_bfd; @@ -2424,6 +2467,16 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->gdb_index.s.section = sectp; dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, &names->debug_names)) + { + dwarf2_per_objfile->debug_names.s.section = sectp; + dwarf2_per_objfile->debug_names.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &names->debug_aranges)) + { + dwarf2_per_objfile->debug_aranges.s.section = sectp; + dwarf2_per_objfile->debug_aranges.size = bfd_get_section_size (sectp); + } if ((bfd_get_section_flags (abfd, sectp) & (SEC_LOAD | SEC_ALLOC)) && bfd_section_vma (abfd, sectp) == 0) @@ -2620,6 +2673,11 @@ locate_dwz_sections (bfd *abfd, asection *sectp, void *arg) dwz_file->gdb_index.s.section = sectp; dwz_file->gdb_index.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, &dwarf2_elf_names.debug_names)) + { + dwz_file->debug_names.s.section = sectp; + dwz_file->debug_names.size = bfd_get_section_size (sectp); + } } /* Open the separate '.dwz' debug file, if needed. Return NULL if @@ -3071,6 +3129,66 @@ create_signatured_type_table_from_index (struct objfile *objfile, dwarf2_per_objfile->signatured_types = sig_types_hash; } +/* Create the signatured type hash table from .debug_names. */ + +static void +create_signatured_type_table_from_debug_names (struct objfile *objfile, + const mapped_debug_names &map, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section) +{ + uint32_t i; + htab_t sig_types_hash; + + dwarf2_read_section (objfile, section); + dwarf2_read_section (objfile, abbrev_section); + + dwarf2_per_objfile->n_type_units + = dwarf2_per_objfile->n_allocated_type_units + = map.tu_count; + dwarf2_per_objfile->all_type_units = + XNEWVEC (struct signatured_type *, dwarf2_per_objfile->n_type_units); + + sig_types_hash = allocate_signatured_type_table (objfile); + + for (i = 0; i < map.tu_count; ++i) + { + struct signatured_type *sig_type; + ULONGEST signature; + void **slot; + cu_offset type_offset_in_tu; + + sect_offset sect_off + = (sect_offset) extract_unsigned_integer + (map.tu_table_reordered + i * map.offset_size, map.offset_size, + map.dwarf5_byte_order); + + comp_unit_head cu_header; + read_and_check_comp_unit_head (&cu_header, section, abbrev_section, + section->buffer + to_underlying (sect_off), + rcuh_kind::TYPE); + + sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct signatured_type); + sig_type->signature = cu_header.signature; + sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu; + sig_type->per_cu.is_debug_types = 1; + sig_type->per_cu.section = section; + sig_type->per_cu.sect_off = sect_off; + sig_type->per_cu.objfile = objfile; + sig_type->per_cu.v.quick + = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_per_cu_quick_data); + + slot = htab_find_slot (sig_types_hash, sig_type, INSERT); + *slot = sig_type; + + dwarf2_per_objfile->all_type_units[i] = sig_type; + } + + dwarf2_per_objfile->signatured_types = sig_types_hash; +} + /* Read the address map data from the mapped index, and use it to populate the objfile's psymtabs_addrmap. */ @@ -3129,6 +3247,176 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index) do_cleanups (cleanup); } +/* Read the address map data from DWARF-5 .debug_aranges, and use it to + populate the objfile's psymtabs_addrmap. */ + +static void +create_addrmap_from_aranges (struct objfile *objfile, + struct dwarf2_section_info *section) +{ + bfd *abfd = objfile->obfd; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + const gdb_byte *iter, *end; + struct obstack temp_obstack; + struct addrmap *mutable_map; + struct cleanup *cleanup; + const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile))); + + obstack_init (&temp_obstack); + cleanup = make_cleanup_obstack_free (&temp_obstack); + mutable_map = addrmap_create_mutable (&temp_obstack); + + std::unordered_map debug_info_offset_to_per_cu; + for (int cui = 0; cui < dwarf2_per_objfile->n_comp_units; ++cui) + { + dwarf2_per_cu_data *per_cu (dw2_get_cutu (cui)); + const auto insertpair + (debug_info_offset_to_per_cu.emplace (per_cu->sect_off, per_cu)); + if (!insertpair.second) + { + warning (_("Section .debug_aranges in %s has duplicate " + "debug_info_offset %u, ignoring .debug_aranges."), + objfile_name (objfile), to_underlying (per_cu->sect_off)); + do_cleanups (cleanup); + return; + } + } + + dwarf2_read_section (objfile, section); + + const bfd_endian dwarf5_byte_order + (gdbarch_byte_order (get_objfile_arch (objfile))); + + const gdb_byte *addr (section->buffer); + + while (addr < section->buffer + section->size) + { + const gdb_byte *const entry_addr (addr); + unsigned int bytes_read; + + const LONGEST entry_length (read_initial_length (abfd, addr, + &bytes_read)); + addr += bytes_read; + const gdb_byte *const entry_end (addr + entry_length); + const bool dwarf5_is_dwarf64 (bytes_read != 4); + const uint8_t offset_size (dwarf5_is_dwarf64 ? 8 : 4); + if (addr + entry_length > section->buffer + section->size) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "length %s exceeds section length %s, " + "ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer, + plongest (bytes_read + entry_length), + pulongest (section->size)); + do_cleanups (cleanup); + return; + } + + /* The version number. */ + const uint16_t version (read_2_bytes (abfd, addr)); + addr += 2; + if (version != 2) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "has unsupported version %d, ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer, + version); + do_cleanups (cleanup); + return; + } + + const uint64_t debug_info_offset + (extract_unsigned_integer (addr, offset_size, dwarf5_byte_order)); + addr += offset_size; + const auto per_cu_it + (debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset))); + if (per_cu_it == debug_info_offset_to_per_cu.cend ()) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "debug_info_offset %s does not exists, " + "ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer, + pulongest (debug_info_offset)); + do_cleanups (cleanup); + return; + } + dwarf2_per_cu_data *const per_cu (per_cu_it->second); + + const uint8_t address_size (*addr++); + if (address_size < 1 || address_size > 8) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "address_size %u is invalid, ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer, + address_size); + do_cleanups (cleanup); + return; + } + + const uint8_t segment_selector_size (*addr++); + if (segment_selector_size != 0) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "segment_selector_size %u is not supported, " + "ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer, + segment_selector_size); + do_cleanups (cleanup); + return; + } + + /* Must pad to an alignment boundary that is twice the address size. + It is undocumented by the DWARF standard but GCC does use it. */ + for (size_t padding = ((-(addr - section->buffer)) + & (2 * address_size - 1)); + padding > 0; padding--) + if (*addr++ != 0) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "padding is not zero, ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer); + do_cleanups (cleanup); + return; + } + + for (;;) + { + if (addr + 2 * address_size > entry_end) + { + warning (_("Section .debug_aranges in %s entry at offset %zu " + "address list is not properly terminated, " + "ignoring .debug_aranges."), + objfile_name (objfile), entry_addr - section->buffer); + do_cleanups (cleanup); + return; + } + ULONGEST start (extract_unsigned_integer (addr, address_size, + dwarf5_byte_order)); + addr += address_size; + ULONGEST length (extract_unsigned_integer (addr, address_size, + dwarf5_byte_order)); + addr += address_size; + if (start == 0 && length == 0) + break; + if (start == 0 && !dwarf2_per_objfile->has_section_at_zero) + { + /* Symbol was eliminated due to a COMDAT group. */ + continue; + } + ULONGEST end (start + length); + start = gdbarch_adjust_dwarf2_addr (gdbarch, start + baseaddr); + end = gdbarch_adjust_dwarf2_addr (gdbarch, end + baseaddr); + addrmap_set_empty (mutable_map, start, end - 1, per_cu); + } + } + + objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map, + &objfile->objfile_obstack); + do_cleanups (cleanup); +} + /* The hash function for strings in the mapped index. This is the same as SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the implementation. This is necessary because the hash function is tied to the @@ -3345,8 +3633,7 @@ to use the section anyway."), return 1; } - -/* Read the index file. If everything went ok, initialize the "quick" +/* Read .gdb_index. If everything went ok, initialize the "quick" elements of all the CUs and return 1. Otherwise, return 0. */ static int @@ -3422,97 +3709,408 @@ dwarf2_read_index (struct objfile *objfile) return 1; } -/* A helper for the "quick" functions which sets the global - dwarf2_per_objfile according to OBJFILE. */ +/* A helper function that reads the .debug_names from SECTION and fills + in MAP. FILENAME is the name of the file containing the section; + it is used for error reporting. -static void -dw2_setup (struct objfile *objfile) -{ - dwarf2_per_objfile = ((struct dwarf2_per_objfile *) - objfile_data (objfile, dwarf2_objfile_data_key)); - gdb_assert (dwarf2_per_objfile); -} + CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are + out parameters that are filled in with information about the CU and + TU lists in the section. -/* die_reader_func for dw2_get_file_names. */ + Returns true if all went well, false otherwise. */ -static void -dw2_get_file_names_reader (const struct die_reader_specs *reader, - const gdb_byte *info_ptr, - struct die_info *comp_unit_die, - int has_children, - void *data) +static bool +read_debug_names_from_section (struct objfile *objfile, + const char *filename, + struct dwarf2_section_info *section, + mapped_debug_names &map) { - struct dwarf2_cu *cu = reader->cu; - struct dwarf2_per_cu_data *this_cu = cu->per_cu; - struct objfile *objfile = dwarf2_per_objfile->objfile; - struct dwarf2_per_cu_data *lh_cu; - struct attribute *attr; + const gdb_byte *addr, *abbrev_table_start; + offset_type *metadata; int i; - void **slot; - struct quick_file_names *qfn; + unsigned int bytes_read; + LONGEST length; + uint16_t version, padding; + uint32_t foreign_tu_count; + uint32_t abbrev_table_size, augmentation_string_size; - gdb_assert (! this_cu->is_debug_types); + if (dwarf2_section_empty_p (section)) + return false; - /* Our callers never want to match partial units -- instead they - will match the enclosing full CU. */ - if (comp_unit_die->tag == DW_TAG_partial_unit) + /* Older elfutils strip versions could keep the section in the main + executable while splitting it for the separate debug info file. */ + if ((get_section_flags (section) & SEC_HAS_CONTENTS) == 0) + return false; + + dwarf2_read_section (objfile, section); + + map.dwarf5_byte_order = gdbarch_byte_order (get_objfile_arch (objfile)); + + addr = section->buffer; + + bfd *const abfd (get_section_bfd_owner (section)); + length = read_initial_length (abfd, addr, &bytes_read); + addr += bytes_read; + map.dwarf5_is_dwarf64 = bytes_read != 4; + map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4; + if (bytes_read + length != section->size) + { + /* There may be multiple per-CU indices. */ + warning (_("Section .debug_names in %s length %s does not match " + "section length %s, ignoring .debug_names."), + filename, plongest (bytes_read + length), + pulongest (section->size)); + return false; + } + + /* The version number. */ + version = read_2_bytes (abfd, addr); + addr += 2; + if (version != 5) { - this_cu->v.quick->no_file_data = 1; - return; + warning (_("Section .debug_names in %s has unsupported version %d, " + "ignoring .debug_names."), + filename, version); + return false; } - lh_cu = this_cu; - slot = NULL; + /* Padding. */ + padding = read_2_bytes (abfd, addr); + addr += 2; + if (padding != 0) + { + warning (_("Section .debug_names in %s has unsupported padding %d, " + "ignoring .debug_names."), + filename, padding); + return false; + } - line_header_up lh; - sect_offset line_offset {}; + /* comp_unit_count - The number of CUs in the CU list. */ + map.cu_count = read_4_bytes (abfd, addr); + addr += 4; - attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); - if (attr) + /* local_type_unit_count - The number of TUs + in the local TU list. */ + map.tu_count = read_4_bytes (abfd, addr); + addr += 4; + + /* foreign_type_unit_count - The number of TUs + in the foreign TU list. */ + foreign_tu_count = read_4_bytes (abfd, addr); + addr += 4; + if (foreign_tu_count != 0) { - struct quick_file_names find_entry; + warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, " + "ignoring .debug_names."), + filename, static_cast (foreign_tu_count)); + return false; + } - line_offset = (sect_offset) DW_UNSND (attr); + /* bucket_count - The number of hash buckets + in the hash lookup table. */ + map.bucket_count = read_4_bytes (abfd, addr); + addr += 4; - /* We may have already read in this line header (TU line header sharing). - If we have we're done. */ - find_entry.hash.dwo_unit = cu->dwo_unit; - find_entry.hash.line_sect_off = line_offset; - slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table, - &find_entry, INSERT); - if (*slot != NULL) + /* name_count - The number of unique names in the index. */ + map.name_count = read_4_bytes (abfd, addr); + addr += 4; + + /* abbrev_table_size - The size in bytes + of the abbreviations table. */ + abbrev_table_size = read_4_bytes (abfd, addr); + addr += 4; + + /* augmentation_string_size - The size in bytes of the augmentation + string. This value is rounded up to a multiple of 4. */ + augmentation_string_size = read_4_bytes (abfd, addr); + addr += 4; + augmentation_string_size += (-augmentation_string_size) & 3; + addr += augmentation_string_size; + + /* List of CUs */ + map.cu_table_reordered = addr; + addr += map.cu_count * map.offset_size; + + /* List of Local TUs */ + map.tu_table_reordered = addr; + addr += map.tu_count * map.offset_size; + + /* Hash Lookup Table */ + map.bucket_table_reordered = reinterpret_cast (addr); + addr += map.bucket_count * 4; + map.hash_table_reordered = reinterpret_cast (addr); + addr += map.name_count * 4; + + /* Name Table */ + map.name_table_string_offs_reordered = addr; + addr += map.name_count * map.offset_size; + map.name_table_entry_offs_reordered = addr; + addr += map.name_count * map.offset_size; + + abbrev_table_start = addr; + for (;;) + { + unsigned int bytes_read; + const ULONGEST index_num (read_unsigned_leb128 (abfd, addr, &bytes_read)); + addr += bytes_read; + if (index_num == 0) + break; + + const auto insertpair (map.abbrev_map.emplace (index_num, + mapped_debug_names::index_val ())); + if (!insertpair.second) { - lh_cu->v.quick->file_names = (struct quick_file_names *) *slot; - return; + warning (_("Section .debug_names in %s has duplicate index %s, " + "ignoring .debug_names."), + filename, pulongest (index_num)); + return false; } + mapped_debug_names::index_val &indexval (insertpair.first->second); + indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read); + addr += bytes_read; - lh = dwarf_decode_line_header (line_offset, cu); + for (;;) + { + mapped_debug_names::index_val::attr attr; + attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read); + addr += bytes_read; + attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read); + addr += bytes_read; + if (attr.form == DW_FORM_implicit_const) + { + attr.implicit_const = read_signed_leb128 (abfd, addr, + &bytes_read); + addr += bytes_read; + } + if (attr.dw_idx == 0 && attr.form == 0) + break; + indexval.attr_vec.push_back (std::move (attr)); + } } - if (lh == NULL) + if (addr != abbrev_table_start + abbrev_table_size) { - lh_cu->v.quick->no_file_data = 1; - return; + warning (_("Section .debug_names in %s has abbreviation_table " + "of size %zu vs. written as %u, ignoring .debug_names."), + filename, addr - abbrev_table_start, abbrev_table_size); + return false; } + map.entry_pool = addr; - qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names); - qfn->hash.dwo_unit = cu->dwo_unit; - qfn->hash.line_sect_off = line_offset; - gdb_assert (slot != NULL); - *slot = qfn; - - file_and_directory fnd = find_file_and_directory (comp_unit_die, cu); - - qfn->num_file_names = lh->file_names.size (); - qfn->file_names = - XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ()); - for (i = 0; i < lh->file_names.size (); ++i) - qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir); - qfn->real_names = NULL; - - lh_cu->v.quick->file_names = qfn; + return true; } -/* A helper for the "quick" functions which attempts to read the line +/* A helper for create_cus_from_index that handles a given list of + CUs. */ + +static void +create_cus_from_debug_names_list (struct objfile *objfile, + const mapped_debug_names &map, + dwarf2_section_info §ion, + int is_dwz, int base_offset) +{ + sect_offset sect_off_prev; + for (uint32_t i = 0; i <= map.cu_count; ++i) + { + sect_offset sect_off_next; + if (i < map.cu_count) + sect_off_next = (sect_offset) extract_unsigned_integer + (map.cu_table_reordered + i * map.offset_size, map.offset_size, + map.dwarf5_byte_order); + else + sect_off_next = (sect_offset) section.size; + if (i >= 1) + { + const ULONGEST length (sect_off_next - sect_off_prev); + dwarf2_per_objfile->all_comp_units[base_offset + (i - 1)] = + create_cu_from_index_list (objfile, §ion, is_dwz, + sect_off_prev, length); + } + sect_off_prev = sect_off_next; + } +} + +/* Read the CU list from the mapped index, and use it to create all + the CU objects for this objfile. */ + +static void +create_cus_from_debug_names (struct objfile *objfile, + const mapped_debug_names &map, + const mapped_debug_names &dwz_map) +{ + struct dwz_file *dwz; + + dwarf2_per_objfile->n_comp_units = map.cu_count + dwz_map.cu_count; + dwarf2_per_objfile->all_comp_units = + XOBNEWVEC (&objfile->objfile_obstack, struct dwarf2_per_cu_data *, + dwarf2_per_objfile->n_comp_units); + + create_cus_from_debug_names_list (objfile, map, dwarf2_per_objfile->info, + 0 /* is_dwz */, 0 /* base_offset */); + + if (dwz_map.cu_count == 0) + return; + + dwz = dwarf2_get_dwz_file (); + create_cus_from_debug_names_list (objfile, dwz_map, dwz->info, 1 /* is_dwz */, + map.cu_count /* base_offset */); +} + +/* Read .debug_names. If everything went ok, initialize the "quick" + elements of all the CUs and return true. Otherwise, return false. */ + +static bool +dwarf2_read_debug_names (struct objfile *objfile) +{ + mapped_debug_names local_map, dwz_map; + const gdb_byte *dwz_list = NULL; + offset_type dwz_list_elements = 0; + struct dwz_file *dwz; + + if (!read_debug_names_from_section (objfile, objfile_name (objfile), + &dwarf2_per_objfile->debug_names, + local_map)) + return false; + + /* Don't use the index if it's empty. */ + if (local_map.name_count == 0) + return false; + + /* If there is a .dwz file, read it so we can get its CU list as + well. */ + dwz = dwarf2_get_dwz_file (); + if (dwz != NULL) + { + if (!read_debug_names_from_section (objfile, + bfd_get_filename (dwz->dwz_bfd), + &dwz->debug_names, dwz_map)) + { + warning (_("could not read '.debug_names' section from %s; skipping"), + bfd_get_filename (dwz->dwz_bfd)); + return false; + } + } + + create_cus_from_debug_names (objfile, local_map, dwz_map); + + if (local_map.tu_count != 0) + { + struct dwarf2_section_info *section; + + /* We can only handle a single .debug_types when we have an + index. */ + if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) != 1) + return false; + + section = VEC_index (dwarf2_section_info_def, + dwarf2_per_objfile->types, 0); + + create_signatured_type_table_from_debug_names (objfile, local_map, + section, + &dwarf2_per_objfile->abbrev); + } + + create_addrmap_from_aranges (objfile, &dwarf2_per_objfile->debug_aranges); + + dwarf2_per_objfile->debug_names_table = new mapped_debug_names; + *dwarf2_per_objfile->debug_names_table = std::move (local_map); + dwarf2_per_objfile->using_index = 1; + dwarf2_per_objfile->quick_file_names_table = + create_quick_file_names_table (dwarf2_per_objfile->n_comp_units); + + return true; +} + +/* A helper for the "quick" functions which sets the global + dwarf2_per_objfile according to OBJFILE. */ + +static void +dw2_setup (struct objfile *objfile) +{ + dwarf2_per_objfile = ((struct dwarf2_per_objfile *) + objfile_data (objfile, dwarf2_objfile_data_key)); + gdb_assert (dwarf2_per_objfile); +} + +/* die_reader_func for dw2_get_file_names. */ + +static void +dw2_get_file_names_reader (const struct die_reader_specs *reader, + const gdb_byte *info_ptr, + struct die_info *comp_unit_die, + int has_children, + void *data) +{ + struct dwarf2_cu *cu = reader->cu; + struct dwarf2_per_cu_data *this_cu = cu->per_cu; + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_per_cu_data *lh_cu; + struct attribute *attr; + int i; + void **slot; + struct quick_file_names *qfn; + + gdb_assert (! this_cu->is_debug_types); + + /* Our callers never want to match partial units -- instead they + will match the enclosing full CU. */ + if (comp_unit_die->tag == DW_TAG_partial_unit) + { + this_cu->v.quick->no_file_data = 1; + return; + } + + lh_cu = this_cu; + slot = NULL; + + line_header_up lh; + sect_offset line_offset {}; + + attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); + if (attr) + { + struct quick_file_names find_entry; + + line_offset = (sect_offset) DW_UNSND (attr); + + /* We may have already read in this line header (TU line header sharing). + If we have we're done. */ + find_entry.hash.dwo_unit = cu->dwo_unit; + find_entry.hash.line_sect_off = line_offset; + slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table, + &find_entry, INSERT); + if (*slot != NULL) + { + lh_cu->v.quick->file_names = (struct quick_file_names *) *slot; + return; + } + + lh = dwarf_decode_line_header (line_offset, cu); + } + if (lh == NULL) + { + lh_cu->v.quick->no_file_data = 1; + return; + } + + qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names); + qfn->hash.dwo_unit = cu->dwo_unit; + qfn->hash.line_sect_off = line_offset; + gdb_assert (slot != NULL); + *slot = qfn; + + file_and_directory fnd = find_file_and_directory (comp_unit_die, cu); + + qfn->num_file_names = lh->file_names.size (); + qfn->file_names = + XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ()); + for (i = 0; i < lh->file_names.size (); ++i) + qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir); + qfn->real_names = NULL; + + lh_cu->v.quick->file_names = qfn; +} + +/* A helper for the "quick" functions which attempts to read the line table for THIS_CU. */ static struct quick_file_names * @@ -4232,163 +4830,677 @@ dw2_expand_symtabs_matching if (cu_index >= (dwarf2_per_objfile->n_comp_units + dwarf2_per_objfile->n_type_units)) { - complaint (&symfile_complaints, - _(".gdb_index entry has bad CU index" - " [in module %s]"), objfile_name (objfile)); - continue; + complaint (&symfile_complaints, + _(".gdb_index entry has bad CU index" + " [in module %s]"), objfile_name (objfile)); + continue; + } + + per_cu = dw2_get_cutu (cu_index); + dw2_expand_symtabs_matching_one (per_cu, file_matcher, + expansion_notify); + } + } +} + +/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific + symtab. */ + +static struct compunit_symtab * +recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust, + CORE_ADDR pc) +{ + int i; + + if (COMPUNIT_BLOCKVECTOR (cust) != NULL + && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc)) + return cust; + + if (cust->includes == NULL) + return NULL; + + for (i = 0; cust->includes[i]; ++i) + { + struct compunit_symtab *s = cust->includes[i]; + + s = recursively_find_pc_sect_compunit_symtab (s, pc); + if (s != NULL) + return s; + } + + return NULL; +} + +static struct compunit_symtab * +dw2_find_pc_sect_compunit_symtab (struct objfile *objfile, + struct bound_minimal_symbol msymbol, + CORE_ADDR pc, + struct obj_section *section, + int warn_if_readin) +{ + struct dwarf2_per_cu_data *data; + struct compunit_symtab *result; + + dw2_setup (objfile); + + if (!objfile->psymtabs_addrmap) + return NULL; + + data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap, + pc); + if (!data) + return NULL; + + if (warn_if_readin && data->v.quick->compunit_symtab) + warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"), + paddress (get_objfile_arch (objfile), pc)); + + result + = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data), + pc); + gdb_assert (result != NULL); + return result; +} + +static void +dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun, + void *data, int need_fullname) +{ + int i; + htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree)); + + dw2_setup (objfile); + + /* The rule is CUs specify all the files, including those used by + any TU, so there's no need to scan TUs here. + We can ignore file names coming from already-expanded CUs. */ + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i); + + if (per_cu->v.quick->compunit_symtab) + { + void **slot = htab_find_slot (visited.get (), + per_cu->v.quick->file_names, + INSERT); + + *slot = per_cu->v.quick->file_names; + } + } + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); + struct quick_file_names *file_data; + void **slot; + + /* We only need to look at symtabs not already expanded. */ + if (per_cu->v.quick->compunit_symtab) + continue; + + file_data = dw2_get_file_names (per_cu); + if (file_data == NULL) + continue; + + slot = htab_find_slot (visited.get (), file_data, INSERT); + if (*slot) + { + /* Already visited. */ + continue; + } + *slot = file_data; + + for (j = 0; j < file_data->num_file_names; ++j) + { + const char *this_real_name; + + if (need_fullname) + this_real_name = dw2_get_real_path (objfile, file_data, j); + else + this_real_name = NULL; + (*fun) (file_data->file_names[j], this_real_name, data); + } + } +} + +static int +dw2_has_symbols (struct objfile *objfile) +{ + return 1; +} + +const struct quick_symbol_functions dwarf2_gdb_index_functions = +{ + dw2_has_symbols, + dw2_find_last_source_symtab, + dw2_forget_cached_source_info, + dw2_map_symtabs_matching_filename, + dw2_lookup_symbol, + dw2_print_stats, + dw2_dump, + dw2_relocate, + dw2_expand_symtabs_for_function, + dw2_expand_all_symtabs, + dw2_expand_symtabs_with_fullname, + dw2_map_matching_symbols, + dw2_expand_symtabs_matching, + dw2_find_pc_sect_compunit_symtab, + dw2_map_symbol_filenames +}; + +/* Symbol name hashing function as specified by DWARF-5. */ + +static uint32_t +dwarf5_djb_hash (const unsigned char *str) +{ + uint32_t hash = 5381; + while (int c = *str++) + { + /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ()) + FIXME: Is unicode supported for symbol names by GDB? */ + hash = hash * 33 + tolower (c); + } + return hash; +} + +/* Struct used to manage iterating over all CUs looking for a symbol + for .debug_names. */ + +class dw2_debug_names_iterator +{ +private: + /* The internalized form of .debug_names. */ + const mapped_debug_names ↦ + /* If true, only look for symbols that match BLOCK_INDEX. */ + const bool want_specific_block = false; + /* One of GLOBAL_BLOCK or STATIC_BLOCK. + Unused if !WANT_SPECIFIC_BLOCK - FIRST_LOCAL_BLOCK is an invalid value. */ + const block_enum block_index = FIRST_LOCAL_BLOCK; + /* The kind of symbol we're looking for. */ + const domain_enum domain = UNDEF_DOMAIN; + const search_domain search = ALL_DOMAIN; + /* The list of CUs from the index entry of the symbol, + or NULL if not found. */ + const gdb_byte *addr; + static const gdb_byte *find_vec_in_debug_names + (const mapped_debug_names &map, const char *name); + static const gdb_byte *find_vec_in_debug_names + (const mapped_debug_names &map, uint32_t namei); +public: + + /* If WANT_SPECIFIC_BLOCK is non-zero, only look for symbols + in block BLOCK_INDEX. Otherwise BLOCK_INDEX is ignored. */ + dw2_debug_names_iterator + (const mapped_debug_names &map_, bool want_specific_block_, + block_enum block_index_, domain_enum domain_, const char *name) + : map (map_), want_specific_block (want_specific_block_), + block_index (block_index_), domain (domain_), + addr (find_vec_in_debug_names (map, name)) + { + } + + dw2_debug_names_iterator + (const mapped_debug_names &map_, search_domain search_, uint32_t namei) + : map (map_), search (search_), addr (find_vec_in_debug_names (map, namei)) + { + } + + /* Return the next matching CU or NULL if there are no more. */ + dwarf2_per_cu_data *next (); +}; + +static const char *read_indirect_string_at_offset (bfd *abfd, + LONGEST str_offset); + +const char * +mapped_debug_names::namei_to_name (uint32_t namei) const +{ + const ULONGEST namei_string_offs + (extract_unsigned_integer ((name_table_string_offs_reordered + + namei * offset_size), offset_size, + dwarf5_byte_order)); + return read_indirect_string_at_offset + (dwarf2_per_objfile->objfile->obfd, namei_string_offs); +} + +/* Find a slot in .debug_names for the object named NAME. + If NAME is found, return pointer to its pool data. + If NAME cannot be found, return NULL. */ + +const gdb_byte * +dw2_debug_names_iterator::find_vec_in_debug_names + (const mapped_debug_names &map, const char *name) +{ + struct cleanup *back_to = make_cleanup (null_cleanup, 0); + int (*cmp) (const char *, const char *); + + if (current_language->la_language == language_cplus + || current_language->la_language == language_fortran + || current_language->la_language == language_d) + { + /* NAME is already canonical. Drop any qualifiers as .gdb_index does + not contain any. */ + + if (strchr (name, '(') != NULL) + { + char *without_params = cp_remove_params (name); + + if (without_params != NULL) + { + make_cleanup (xfree, without_params); + name = without_params; + } + } + } + + cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp); + + const uint32_t full_hash + (dwarf5_djb_hash (reinterpret_cast (name))); + uint32_t namei + (extract_unsigned_integer (reinterpret_cast + (map.bucket_table_reordered + + (full_hash % map.bucket_count)), 4, + map.dwarf5_byte_order)); + if (namei == 0) + { + do_cleanups (back_to); + return NULL; + } + --namei; + if (namei >= map.name_count) + { + complaint (&symfile_complaints, + _("Wrong .debug_names with name index %u but name_count=%u " + "[in module %s]"), + namei, map.name_count, + objfile_name (dwarf2_per_objfile->objfile)); + do_cleanups (back_to); + return NULL; + } + for (;;) + { + const uint32_t namei_full_hash + (extract_unsigned_integer (reinterpret_cast + (map.hash_table_reordered + namei), 4, + map.dwarf5_byte_order)); + if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count) + { + do_cleanups (back_to); + return NULL; + } + + if (full_hash == namei_full_hash) + { + const char *const namei_string (map.namei_to_name (namei)); + +#if 0 /* An expensive sanity check. */ + if (namei_full_hash != dwarf5_djb_hash + (reinterpret_cast (namei_string))) + { + complaint (&symfile_complaints, + _("Wrong .debug_names hash for string at index %u " + "[in module %s]"), + namei, objfile_name (dwarf2_per_objfile->objfile)); + do_cleanups (back_to); + return NULL; + } +#endif + + if (cmp (namei_string, name) == 0) + { + const ULONGEST namei_entry_offs + (extract_unsigned_integer ((map.name_table_entry_offs_reordered + + namei * map.offset_size), + map.offset_size, map.dwarf5_byte_order)); + do_cleanups (back_to); + return map.entry_pool + namei_entry_offs; } + } - per_cu = dw2_get_cutu (cu_index); - dw2_expand_symtabs_matching_one (per_cu, file_matcher, - expansion_notify); + ++namei; + if (namei >= map.name_count) + { + do_cleanups (back_to); + return NULL; } } } -/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific - symtab. */ - -static struct compunit_symtab * -recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust, - CORE_ADDR pc) +const gdb_byte * +dw2_debug_names_iterator::find_vec_in_debug_names + (const mapped_debug_names &map, uint32_t namei) { - int i; + if (namei >= map.name_count) + { + complaint (&symfile_complaints, + _("Wrong .debug_names with name index %u but name_count=%u " + "[in module %s]"), + namei, map.name_count, + objfile_name (dwarf2_per_objfile->objfile)); + return NULL; + } + const ULONGEST namei_entry_offs + (extract_unsigned_integer ((map.name_table_entry_offs_reordered + + namei * map.offset_size), + map.offset_size, map.dwarf5_byte_order)); + return map.entry_pool + namei_entry_offs; +} - if (COMPUNIT_BLOCKVECTOR (cust) != NULL - && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc)) - return cust; +/* See dw2_debug_names_iterator. */ - if (cust->includes == NULL) +dwarf2_per_cu_data * +dw2_debug_names_iterator::next () +{ + if (addr == NULL) + return NULL; + bfd *const abfd (dwarf2_per_objfile->objfile->obfd); + unsigned int bytes_read; + const ULONGEST abbrev (read_unsigned_leb128 (abfd, addr, &bytes_read)); + addr += bytes_read; + if (abbrev == 0) return NULL; + const auto indexval_it (map.abbrev_map.find (abbrev)); + if (indexval_it == map.abbrev_map.cend ()) + { + complaint (&symfile_complaints, + _("Wrong .debug_names undefined abbrev code %s " + "[in module %s]"), + pulongest (abbrev), objfile_name (dwarf2_per_objfile->objfile)); + return NULL; + } + const mapped_debug_names::index_val &indexval (indexval_it->second); + bool have_is_static (false); + bool is_static; + dwarf2_per_cu_data *per_cu (NULL); + for (const mapped_debug_names::index_val::attr &attr : indexval.attr_vec) + { + ULONGEST ull; + switch (attr.form) + { + case DW_FORM_implicit_const: + ull = attr.implicit_const; + break; + case DW_FORM_flag_present: + ull = 1; + break; + case DW_FORM_udata: + ull = read_unsigned_leb128 (abfd, addr, &bytes_read); + addr += bytes_read; + break; + default: + complaint (&symfile_complaints, + _("Unsupported .debug_names form %s [in module %s]"), + dwarf_form_name (attr.form), + objfile_name (dwarf2_per_objfile->objfile)); + return NULL; + } + switch (attr.dw_idx) + { + case DW_IDX_compile_unit: + /* Don't crash on bad data. */ + if (ull >= (dwarf2_per_objfile->n_comp_units + + dwarf2_per_objfile->n_type_units)) + { + complaint (&symfile_complaints, + _(".gdb_index entry has bad CU index %s" + " [in module %s]"), + pulongest (ull), + objfile_name (dwarf2_per_objfile->objfile)); + continue; + } + per_cu = dw2_get_cutu (ull); + break; + case DW_IDX_GNU_static: + have_is_static = true; + is_static = true; + break; + case DW_IDX_GNU_external: + have_is_static = true; + is_static = false; + break; + } + } - for (i = 0; cust->includes[i]; ++i) + /* Skip if already read in. */ + if (per_cu->v.quick->compunit_symtab) + return next (); + + /* Check static vs global. */ + if (have_is_static) { - struct compunit_symtab *s = cust->includes[i]; + const bool want_static (block_index != GLOBAL_BLOCK); + if (want_specific_block && want_static != is_static) + return next (); + } - s = recursively_find_pc_sect_compunit_symtab (s, pc); - if (s != NULL) - return s; + /* Match dw2_symtab_iter_next, symbol_kind + and DebugNamesNameTable::psymbol_tag. */ + switch (domain) + { + case VAR_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_variable: + case DW_TAG_subprogram: + /* Some types are also in VAR_DOMAIN. */ + case DW_TAG_typedef: + case DW_TAG_structure_type: + break; + default: + return next (); + } + break; + case STRUCT_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_typedef: + case DW_TAG_structure_type: + break; + default: + return next (); + } + break; + case LABEL_DOMAIN: + switch (indexval.dwarf_tag) + { + case 0: + case DW_TAG_variable: + break; + default: + return next (); + } + break; + default: + break; } - return NULL; + /* Match dw2_expand_symtabs_matching, symbol_kind + and DebugNamesNameTable::psymbol_tag. */ + switch (search) + { + case VARIABLES_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_variable: + break; + default: + return next (); + } + break; + case FUNCTIONS_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_subprogram: + break; + default: + return next (); + } + break; + case TYPES_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_typedef: + case DW_TAG_structure_type: + break; + default: + return next (); + } + break; + default: + break; + } + + return per_cu; } static struct compunit_symtab * -dw2_find_pc_sect_compunit_symtab (struct objfile *objfile, - struct bound_minimal_symbol msymbol, - CORE_ADDR pc, - struct obj_section *section, - int warn_if_readin) +dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int, + const char *name, domain_enum domain) { - struct dwarf2_per_cu_data *data; - struct compunit_symtab *result; - + const block_enum block_index (static_cast (block_index_int)); dw2_setup (objfile); - if (!objfile->psymtabs_addrmap) - return NULL; + const auto &mapp (dwarf2_per_objfile->debug_names_table); + if (!mapp) + { + /* index is NULL if OBJF_READNOW. */ + return NULL; + } + const auto &map (*mapp); - data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap, - pc); - if (!data) - return NULL; + dw2_debug_names_iterator iter (map, 1 /* want_specific_block */, block_index, + domain, name); - if (warn_if_readin && data->v.quick->compunit_symtab) - warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"), - paddress (get_objfile_arch (objfile), pc)); + struct compunit_symtab *stab_best = NULL; + struct dwarf2_per_cu_data *per_cu; + while ((per_cu = iter.next ()) != NULL) + { + struct symbol *sym, *with_opaque = NULL; + struct compunit_symtab *stab = dw2_instantiate_symtab (per_cu); + const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab); + struct block *block = BLOCKVECTOR_BLOCK (bv, block_index); - result - = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data), - pc); - gdb_assert (result != NULL); - return result; + sym = block_find_symbol (block, name, domain, + block_find_non_opaque_type_preferred, + &with_opaque); + + /* Some caution must be observed with overloaded functions + and methods, since the index will not contain any overload + information (but NAME might contain it). */ + + if (sym != NULL + && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0) + return stab; + if (with_opaque != NULL + && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0) + stab_best = stab; + + /* Keep looking through other CUs. */ + } + + return stab_best; } +/* This dumps minimal information about .debug_names. + It is called via "mt print objfiles". + One use is to verify .debug_names has been loaded by the + gdb.dwarf2/gdb-index.exp testcase. */ + static void -dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun, - void *data, int need_fullname) +dw2_debug_names_dump (struct objfile *objfile) { - int i; - htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer, - NULL, xcalloc, xfree)); - dw2_setup (objfile); + gdb_assert (dwarf2_per_objfile->using_index); + printf_filtered (".debug_names:"); + if (dwarf2_per_objfile->debug_names_table) + printf_filtered (" exists\n"); + else + printf_filtered (" faked for \"readnow\"\n"); + printf_filtered ("\n"); +} - /* The rule is CUs specify all the files, including those used by - any TU, so there's no need to scan TUs here. - We can ignore file names coming from already-expanded CUs. */ +static void +dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile, + const char *func_name) +{ + struct mapped_index *index; - for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + dw2_setup (objfile); + + /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW. */ + if (dwarf2_per_objfile->debug_names_table) { - struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i); + const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table); - if (per_cu->v.quick->compunit_symtab) - { - void **slot = htab_find_slot (visited.get (), - per_cu->v.quick->file_names, - INSERT); + /* Note: It doesn't matter what we pass for block_index here. */ + dw2_debug_names_iterator iter (map, 0 /* want_specific_block */, + GLOBAL_BLOCK, VAR_DOMAIN, func_name); - *slot = per_cu->v.quick->file_names; - } + struct dwarf2_per_cu_data *per_cu; + while ((per_cu = iter.next ()) != NULL) + dw2_instantiate_symtab (per_cu); } +} - for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) +static void +dw2_debug_names_expand_symtabs_matching + (struct objfile *objfile, + gdb::function_view file_matcher, + gdb::function_view symbol_matcher, + gdb::function_view expansion_notify, + enum search_domain kind) +{ + dw2_setup (objfile); + + /* debug_names_table is NULL if OBJF_READNOW. */ + if (!dwarf2_per_objfile->debug_names_table) + return; + const mapped_debug_names &map (*dwarf2_per_objfile->debug_names_table); + + dw_expand_symtabs_matching_file_matcher (file_matcher); + + for (uint32_t namei = 0; namei < map.name_count; ++namei) { - int j; - struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i); - struct quick_file_names *file_data; - void **slot; + const char *name; + offset_type *vec, vec_len, vec_idx; + int global_seen = 0; - /* We only need to look at symtabs not already expanded. */ - if (per_cu->v.quick->compunit_symtab) - continue; + QUIT; - file_data = dw2_get_file_names (per_cu); - if (file_data == NULL) + const char *const namei_string (map.namei_to_name (namei)); + if (!symbol_matcher (namei_string)) continue; - slot = htab_find_slot (visited.get (), file_data, INSERT); - if (*slot) - { - /* Already visited. */ - continue; - } - *slot = file_data; - - for (j = 0; j < file_data->num_file_names; ++j) - { - const char *this_real_name; + /* The name was matched, now expand corresponding CUs that were + marked. */ + dw2_debug_names_iterator iter (map, kind, namei); - if (need_fullname) - this_real_name = dw2_get_real_path (objfile, file_data, j); - else - this_real_name = NULL; - (*fun) (file_data->file_names[j], this_real_name, data); - } + struct dwarf2_per_cu_data *per_cu; + while ((per_cu = iter.next ()) != NULL) + dw2_expand_symtabs_matching_one (per_cu, file_matcher, + expansion_notify); } } -static int -dw2_has_symbols (struct objfile *objfile) -{ - return 1; -} - -const struct quick_symbol_functions dwarf2_gdb_index_functions = +const struct quick_symbol_functions dwarf2_debug_names_functions = { dw2_has_symbols, dw2_find_last_source_symtab, dw2_forget_cached_source_info, dw2_map_symtabs_matching_filename, - dw2_lookup_symbol, + dw2_debug_names_lookup_symbol, dw2_print_stats, - dw2_dump, + dw2_debug_names_dump, dw2_relocate, - dw2_expand_symtabs_for_function, + dw2_debug_names_expand_symtabs_for_function, dw2_expand_all_symtabs, dw2_expand_symtabs_with_fullname, dw2_map_matching_symbols, - dw2_expand_symtabs_matching, + dw2_debug_names_expand_symtabs_matching, dw2_find_pc_sect_compunit_symtab, dw2_map_symbol_filenames }; @@ -4428,6 +5540,9 @@ dwarf2_initialize_objfile (struct objfile *objfile) return elf_sym_fns_gdb_index; } + if (dwarf2_read_debug_names (objfile)) + return elf_sym_fns_debug_names; + if (dwarf2_read_index (objfile)) return elf_sym_fns_gdb_index; @@ -22913,6 +24028,8 @@ dwarf2_free_objfile (struct objfile *objfile) htab_delete (dwarf2_per_objfile->line_header_hash); /* Everything else should be on the objfile obstack. */ + + delete dwarf2_per_objfile->debug_names_table; } /* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer. @@ -23881,7 +24998,7 @@ public: const char *const name (it->first); const unsigned char *const nameuc (reinterpret_cast (name)); - const uint32_t hash (djb_hash (nameuc)); + const uint32_t hash (dwarf5_djb_hash (nameuc)); hash_it_pair hashitpair; hashitpair.hash = hash; hashitpair.it = it; @@ -24261,19 +25378,6 @@ private: m_name_table_entry_offs; }; - /* Symbol name hashing function as specified by DWARF-5. */ - static uint32_t djb_hash (const unsigned char *str) - { - uint32_t hash = 5381; - while (int c = *str++) - { - /* FIXME: std::bad_cast for: std::tolower (c, std::locale::classic ()) - FIXME: Is unicode supported for symbol names by GDB? */ - hash = hash * 33 + tolower (c); - } - return hash; - } - /* Try to reconstruct original DWARF tag for given partial_symbol. This function is not DWARF-5 compliant but it is sufficient for GDB as a DWARF-5 index consumer. */ diff --git a/gdb/elfread.c b/gdb/elfread.c index 9ae0432..6f992d7 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -1431,6 +1431,23 @@ const struct sym_fns elf_sym_fns_gdb_index = &dwarf2_gdb_index_functions }; +/* The same as elf_sym_fns, but not registered and uses the + DWARF-specific .debug_names index rather than psymtab. */ +const struct sym_fns elf_sym_fns_debug_names = +{ + elf_new_init, /* init anything gbl to entire symab */ + elf_symfile_init, /* read initial info, setup for sym_red() */ + elf_symfile_read, /* read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ + elf_symfile_finish, /* finished with file, cleanup */ + default_symfile_offsets, /* Translate ext. to int. relocatin */ + elf_symfile_segments, /* Get segment information from a file. */ + NULL, + default_symfile_relocate, /* Relocate a debug section. */ + &elf_probe_fns, /* sym_probe_fns */ + &dwarf2_debug_names_functions +}; + /* STT_GNU_IFUNC resolver vector to be installed to gnu_ifunc_fns_p. */ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns = diff --git a/gdb/psymtab.h b/gdb/psymtab.h index f0c9ae7..17ceb22 100644 --- a/gdb/psymtab.h +++ b/gdb/psymtab.h @@ -33,6 +33,7 @@ extern struct bcache *psymbol_bcache_get_bcache (struct psymbol_bcache *); extern const struct quick_symbol_functions psym_functions; extern const struct quick_symbol_functions dwarf2_gdb_index_functions; +extern const struct quick_symbol_functions dwarf2_debug_names_functions; /* Ensure that the partial symbols for OBJFILE have been loaded. If VERBOSE is non-zero, then this will print a message when symbols diff --git a/gdb/symfile.h b/gdb/symfile.h index 8e51d41..847358f 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -606,6 +606,8 @@ struct dwarf2_debug_sections { struct dwarf2_section_names frame; struct dwarf2_section_names eh_frame; struct dwarf2_section_names gdb_index; + struct dwarf2_section_names debug_names; + struct dwarf2_section_names debug_aranges; /* This field has no meaning, but exists solely to catch changes to this structure which are not reflected in some instance. */ int sentinel; diff --git a/gdb/testsuite/gdb.base/maint.exp b/gdb/testsuite/gdb.base/maint.exp index 782a21c..8e79451 100644 --- a/gdb/testsuite/gdb.base/maint.exp +++ b/gdb/testsuite/gdb.base/maint.exp @@ -91,8 +91,11 @@ if ![runto_main] then { # If we're using .gdb_index there will be no psymtabs. set have_gdb_index 0 -gdb_test_multiple "maint info sections .gdb_index" "check for .gdb_index" { - -re ": .gdb_index.*$gdb_prompt $" { +gdb_test_multiple "maint info sections .gdb_index .debug_names" "check for .gdb_index" { + -re ": \\.gdb_index .*\r\n$gdb_prompt $" { + set have_gdb_index 1 + } + -re ": \\.debug_names .*\r\n$gdb_prompt $" { set have_gdb_index 1 } -re ".*$gdb_prompt $" { diff --git a/gdb/testsuite/gdb.dlang/watch-loc.c b/gdb/testsuite/gdb.dlang/watch-loc.c index 0ffc377..a1f3caa 100644 --- a/gdb/testsuite/gdb.dlang/watch-loc.c +++ b/gdb/testsuite/gdb.dlang/watch-loc.c @@ -34,3 +34,22 @@ main (void) return _Dmain (); } +// .gdb_index contained this map but .debug_names is generated by GDB +// while it depends on .debug_aranges generated by GCC. +asm ( +" .pushsection .debug_aranges,\"\",@progbits \n" +" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info +".Laranges_start: \n" +" .2byte 0x2 \n" // DWARF Version +" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info +" .byte 4 \n" // Size of Address +" .byte 0 \n" // Size of Segment Descriptor +" .2byte 0 \n" // Pad to 16 byte boundary +" .2byte 0 \n" +" .4byte _Dmain \n" // Address +" .4byte 0x1000 \n" // Length +" .4byte 0 \n" +" .4byte 0 \n" +".Laranges_end: \n" +" .popsection \n" +); diff --git a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S index 3bbd725..5a968bd 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S +++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S @@ -57,6 +57,23 @@ .byte 0 /* End of children of CU */ .Lcu1_end: + // .gdb_index contained this map but .debug_names is generated by GDB + // while it depends on .debug_aranges generated by GCC. + .section .debug_aranges,"",@progbits + .4byte .Laranges_end - .Laranges_start // Length of Address Ranges Info +.Laranges_start: + .2byte 0x2 // DWARF Version + .4byte 0 // .Ldebug_info0 - Offset of Compilation Unit Info + .byte PTRBITS / 8 // Size of Address + .byte 0 // Size of Segment Descriptor + .2byte 0 // Pad to 16 byte boundary + .2byte 0 + PTRBYTE cu_text_start // Address + PTRBYTE 0x1000 // cu_text_end - cu_text_start // Length + PTRBYTE 0 + PTRBYTE 0 +.Laranges_end: + /* Abbrev table */ .section .debug_abbrev .Labbrev1_begin: diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index.exp b/gdb/testsuite/gdb.dwarf2/gdb-index.exp index c925b1e..54725cd 100644 --- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp +++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp @@ -67,6 +67,9 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test { -re "gdb_index.*${gdb_prompt} $" { set binfile_with_index $binfile } + -re "debug_names.*${gdb_prompt} $" { + set binfile_with_index $binfile + } -re "Psymtabs.*${gdb_prompt} $" { set binfile_with_index [add_gdb_index $binfile] if { ${binfile_with_index} == "" } { @@ -80,7 +83,7 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test { clean_restart ${binfile_with_index} gdb_test "mt print objfiles ${testfile}" \ - "gdb_index.*" \ + "(gdb_index|debug_names).*" \ ".gdb_index used" # Make gdb re-read symbols and see if .gdb_index still gets used. @@ -98,5 +101,5 @@ if ![runto_main] { return -1 } gdb_test "mt print objfiles ${testfile}" \ - "gdb_index.*" \ + "(gdb_index|debug_names).*" \ ".gdb_index used after symbol reloading" diff --git a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c index 0c2a153..bf1fea6 100644 --- a/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c +++ b/gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c @@ -52,3 +52,23 @@ asm ("func_loopfb_end:"); asm (".globl cu_text_end"); asm ("cu_text_end:"); + +// .gdb_index contained this map but .debug_names is generated by GDB +// while it depends on .debug_aranges generated by GCC. +asm ( +" .pushsection .debug_aranges,\"\",@progbits \n" +" .4byte .Laranges_end - .Laranges_start \n" // Length of Address Ranges Info +".Laranges_start: \n" +" .2byte 0x2 \n" // DWARF Version +" .4byte 0 \n" // .Ldebug_info0 - Offset of Compilation Unit Info +" .byte 4 \n" // Size of Address +" .byte 0 \n" // Size of Segment Descriptor +" .2byte 0 \n" // Pad to 16 byte boundary +" .2byte 0 \n" +" .4byte cu_text_start \n" // Address +" .4byte cu_text_end - cu_text_start \n" // Length +" .4byte 0 \n" +" .4byte 0 \n" +".Laranges_end: \n" +" .popsection \n" +); diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index 138f941..e6298b4 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -174,6 +174,8 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = { { ".dwframe", NULL }, { NULL, NULL }, /* eh_frame */ { NULL, NULL }, /* gdb_index */ + { NULL, NULL }, /* debug_names */ + { NULL, NULL }, /* debug_aranges */ 23 };