From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 7C6E4385781F for ; Tue, 14 Feb 2023 19:55:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7C6E4385781F Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=efficios.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=efficios.com Received: from smarchi-efficios.internal.efficios.com (192-222-180-24.qc.cable.ebox.net [192.222.180.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 1CB011E221; Tue, 14 Feb 2023 14:55:59 -0500 (EST) From: Simon Marchi To: gdb-patches@sourceware.org Cc: Simon Marchi , Tom Tromey Subject: [PATCH v2 3/3] gdb/dwarf2: split .debug_names reading code to own file Date: Tue, 14 Feb 2023 14:55:58 -0500 Message-Id: <20230214195558.341695-3-simon.marchi@efficios.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230214195558.341695-1-simon.marchi@efficios.com> References: <20230214195558.341695-1-simon.marchi@efficios.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3497.6 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_NONE,KAM_DMARC_STATUS,KAM_SHORT,SPF_HELO_PASS,SPF_SOFTFAIL,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Move everything related to reading .debug_names from read.c to read-debug-names.c. The only entry point exposed by read-debug-names.{c,h} is dwarf2_read_debug_names. Change-Id: I18b23f3c7a61b14abc3a46e4bf559bc2d078e8bc Approved-By: Tom Tromey --- gdb/Makefile.in | 2 + gdb/dwarf2/read-debug-names.c | 1052 +++++++++++++++++++++++++++++++++ gdb/dwarf2/read-debug-names.h | 30 + gdb/dwarf2/read.c | 1031 +------------------------------- 4 files changed, 1087 insertions(+), 1028 deletions(-) create mode 100644 gdb/dwarf2/read-debug-names.c create mode 100644 gdb/dwarf2/read-debug-names.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5a0b3c856d30..ace507cded80 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1082,6 +1082,7 @@ COMMON_SFILES = \ dwarf2/loc.c \ dwarf2/macro.c \ dwarf2/read.c \ + dwarf2/read-debug-names.c \ dwarf2/read-gdb-index.c \ dwarf2/section.c \ dwarf2/stringify.c \ @@ -1326,6 +1327,7 @@ HFILES_NO_SRCDIR = \ dwarf2/index-common.h \ dwarf2/loc.h \ dwarf2/read.h \ + dwarf2/read-debug-names.h \ dwarf2/read-gdb-index.h \ event-top.h \ exceptions.h \ diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c new file mode 100644 index 000000000000..3d96bf476f80 --- /dev/null +++ b/gdb/dwarf2/read-debug-names.c @@ -0,0 +1,1052 @@ +/* Reading code for .debug_names + + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "read-debug-names.h" + +#include "complaints.h" +#include "cp-support.h" +#include "dwz.h" +#include "mapped-index.h" +#include "read.h" +#include "stringify.h" + +/* A description of the mapped .debug_names. + Uninitialized map has CU_COUNT 0. */ + +struct mapped_debug_names final : public mapped_index_base +{ + bfd_endian dwarf5_byte_order; + bool dwarf5_is_dwarf64; + bool augmentation_is_gdb; + 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; + + struct index_val + { + ULONGEST dwarf_tag; + struct attr + { + /* 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, dwarf2_per_objfile *per_objfile) const; + + /* Implementation of the mapped_index_base virtual interface, for + the name_components cache. */ + + const char *symbol_name_at + (offset_type idx, dwarf2_per_objfile *per_objfile) const override + { return namei_to_name (idx, per_objfile); } + + size_t symbol_name_count () const override + { return this->name_count; } + + quick_symbol_functions_up make_quick_functions () const override; +}; + +struct dwarf2_debug_names_index : public dwarf2_base_index_functions +{ + void dump (struct objfile *objfile) override; + + void expand_matching_symbols + (struct objfile *, + const lookup_name_info &lookup_name, + domain_enum domain, + int global, + symbol_compare_ftype *ordered_compare) override; + + bool expand_symtabs_matching + (struct objfile *objfile, + gdb::function_view file_matcher, + const lookup_name_info *lookup_name, + gdb::function_view symbol_matcher, + gdb::function_view expansion_notify, + block_search_flags search_flags, + domain_enum domain, + enum search_domain kind) override; +}; + +quick_symbol_functions_up +mapped_debug_names::make_quick_functions () const +{ + return quick_symbol_functions_up (new dwarf2_debug_names_index); +} + +/* Create the signatured type hash table from .debug_names. */ + +static void +create_signatured_type_table_from_debug_names + (dwarf2_per_objfile *per_objfile, + const mapped_debug_names &map, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section) +{ + struct objfile *objfile = per_objfile->objfile; + + section->read (objfile); + abbrev_section->read (objfile); + + htab_up sig_types_hash = allocate_signatured_type_table (); + + for (uint32_t i = 0; i < map.tu_count; ++i) + { + signatured_type_up sig_type; + void **slot; + + 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 (per_objfile, &cu_header, section, + abbrev_section, + section->buffer + to_underlying (sect_off), + rcuh_kind::TYPE); + + sig_type = per_objfile->per_bfd->allocate_signatured_type + (cu_header.signature); + sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu; + sig_type->section = section; + sig_type->sect_off = sect_off; + + slot = htab_find_slot (sig_types_hash.get (), sig_type.get (), INSERT); + *slot = sig_type.get (); + + per_objfile->per_bfd->all_units.emplace_back (sig_type.release ()); + } + + per_objfile->per_bfd->signatured_types = std::move (sig_types_hash); +} + +/* Read the address map data from DWARF-5 .debug_aranges, and use it to + populate the index_addrmap. */ + +static void +create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile, + struct dwarf2_section_info *section) +{ + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; + + addrmap_mutable mutable_map; + + if (read_addrmap_from_aranges (per_objfile, section, &mutable_map)) + per_bfd->index_addrmap + = new (&per_bfd->obstack) addrmap_fixed (&per_bfd->obstack, + &mutable_map); +} + +/* DWARF-5 debug_names reader. */ + +/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */ +static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 }; + +/* A helper function that reads the .debug_names section in SECTION + and fills in MAP. FILENAME is the name of the file containing the + section; it is used for error reporting. + + Returns true if all went well, false otherwise. */ + +static bool +read_debug_names_from_section (struct objfile *objfile, + const char *filename, + struct dwarf2_section_info *section, + mapped_debug_names &map) +{ + if (section->empty ()) + return false; + + /* Older elfutils strip versions could keep the section in the main + executable while splitting it for the separate debug info file. */ + if ((section->get_flags () & SEC_HAS_CONTENTS) == 0) + return false; + + section->read (objfile); + + map.dwarf5_byte_order = gdbarch_byte_order (objfile->arch ()); + + const gdb_byte *addr = section->buffer; + + bfd *const abfd = section->get_bfd_owner (); + + unsigned int bytes_read; + LONGEST 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. */ + uint16_t version = read_2_bytes (abfd, addr); + addr += 2; + if (version != 5) + { + warning (_("Section .debug_names in %s has unsupported version %d, " + "ignoring .debug_names."), + filename, version); + return false; + } + + /* Padding. */ + uint16_t 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; + } + + /* comp_unit_count - The number of CUs in the CU list. */ + map.cu_count = read_4_bytes (abfd, addr); + addr += 4; + + /* 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. */ + uint32_t foreign_tu_count = read_4_bytes (abfd, addr); + addr += 4; + if (foreign_tu_count != 0) + { + warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, " + "ignoring .debug_names."), + filename, static_cast (foreign_tu_count)); + return false; + } + + /* bucket_count - The number of hash buckets in the hash lookup + table. */ + map.bucket_count = read_4_bytes (abfd, addr); + addr += 4; + + /* 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. */ + uint32_t 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. */ + uint32_t augmentation_string_size = read_4_bytes (abfd, addr); + addr += 4; + map.augmentation_is_gdb = ((augmentation_string_size + == sizeof (dwarf5_augmentation)) + && memcmp (addr, dwarf5_augmentation, + sizeof (dwarf5_augmentation)) == 0); + 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; + + const gdb_byte *abbrev_table_start = addr; + for (;;) + { + 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) + { + 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; + + 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 (addr != abbrev_table_start + abbrev_table_size) + { + warning (_("Section .debug_names in %s has abbreviation_table " + "of size %s vs. written as %u, ignoring .debug_names."), + filename, plongest (addr - abbrev_table_start), + abbrev_table_size); + return false; + } + map.entry_pool = addr; + + return true; +} + +/* A helper for create_cus_from_debug_names that handles the MAP's CU + list. */ + +static bool +create_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, + const mapped_debug_names &map, + dwarf2_section_info §ion, + bool is_dwz) +{ + if (!map.augmentation_is_gdb) + { + for (uint32_t i = 0; i < map.cu_count; ++i) + { + sect_offset sect_off + = (sect_offset) (extract_unsigned_integer + (map.cu_table_reordered + i * map.offset_size, + map.offset_size, + map.dwarf5_byte_order)); + /* We don't know the length of the CU, because the CU list in a + .debug_names index can be incomplete, so we can't use the start + of the next CU as end of this CU. We create the CUs here with + length 0, and in cutu_reader::cutu_reader we'll fill in the + actual length. */ + dwarf2_per_cu_data_up per_cu + = create_cu_from_index_list (per_bfd, §ion, is_dwz, + sect_off, 0); + per_bfd->all_units.push_back (std::move (per_cu)); + } + return true; + } + + 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) + { + if (sect_off_next == sect_off_prev) + { + warning (_("Section .debug_names has duplicate entry in CU table," + " ignoring .debug_names.")); + return false; + } + if (sect_off_next < sect_off_prev) + { + warning (_("Section .debug_names has non-ascending CU table," + " ignoring .debug_names.")); + return false; + } + /* Note: we're not using length = sect_off_next - sect_off_prev, + to gracefully handle an incomplete CU list. */ + const ULONGEST length = 0; + dwarf2_per_cu_data_up per_cu + = create_cu_from_index_list (per_bfd, §ion, is_dwz, + sect_off_prev, length); + per_bfd->all_units.push_back (std::move (per_cu)); + } + sect_off_prev = sect_off_next; + } + + return true; +} + +/* Read the CU list from the mapped index, and use it to create all + the CU objects for this dwarf2_per_objfile. */ + +static bool +create_cus_from_debug_names (dwarf2_per_bfd *per_bfd, + const mapped_debug_names &map, + const mapped_debug_names &dwz_map) +{ + gdb_assert (per_bfd->all_units.empty ()); + per_bfd->all_units.reserve (map.cu_count + dwz_map.cu_count); + + if (!create_cus_from_debug_names_list (per_bfd, map, per_bfd->info, + false /* is_dwz */)) + return false; + + if (dwz_map.cu_count == 0) + return true; + + dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); + return create_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info, + true /* is_dwz */); +} + +/* See read-debug-names.h. */ + +bool +dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) +{ + std::unique_ptr map (new mapped_debug_names); + mapped_debug_names dwz_map; + struct objfile *objfile = per_objfile->objfile; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; + + if (!read_debug_names_from_section (objfile, objfile_name (objfile), + &per_bfd->debug_names, *map)) + return false; + + /* Don't use the index if it's empty. */ + if (map->name_count == 0) + return false; + + /* If there is a .dwz file, read it so we can get its CU list as + well. */ + dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); + if (dwz != NULL) + { + if (!read_debug_names_from_section (objfile, + bfd_get_filename (dwz->dwz_bfd.get ()), + &dwz->debug_names, dwz_map)) + { + warning (_("could not read '.debug_names' section from %s; skipping"), + bfd_get_filename (dwz->dwz_bfd.get ())); + return false; + } + } + + if (!create_cus_from_debug_names (per_bfd, *map, dwz_map)) + { + per_bfd->all_units.clear (); + return false; + } + + if (map->tu_count != 0) + { + /* We can only handle a single .debug_types when we have an + index. */ + if (per_bfd->types.size () > 1) + { + per_bfd->all_units.clear (); + return false; + } + + dwarf2_section_info *section + = (per_bfd->types.size () == 1 + ? &per_bfd->types[0] + : &per_bfd->info); + + create_signatured_type_table_from_debug_names + (per_objfile, *map, section, &per_bfd->abbrev); + } + + finalize_all_units (per_bfd); + + create_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges); + + per_bfd->index_table = std::move (map); + per_bfd->quick_file_names_table = + create_quick_file_names_table (per_bfd->all_units.size ()); + + return true; +} + +/* Type used to manage iterating over all CUs looking for a symbol for + .debug_names. */ + +class dw2_debug_names_iterator +{ +public: + dw2_debug_names_iterator (const mapped_debug_names &map, + block_search_flags block_index, + domain_enum domain, + const char *name, dwarf2_per_objfile *per_objfile) + : m_map (map), m_block_index (block_index), m_domain (domain), + m_addr (find_vec_in_debug_names (map, name, per_objfile)), + m_per_objfile (per_objfile) + {} + + dw2_debug_names_iterator (const mapped_debug_names &map, + search_domain search, uint32_t namei, + dwarf2_per_objfile *per_objfile, + domain_enum domain = UNDEF_DOMAIN) + : m_map (map), + m_domain (domain), + m_search (search), + m_addr (find_vec_in_debug_names (map, namei, per_objfile)), + m_per_objfile (per_objfile) + {} + + dw2_debug_names_iterator (const mapped_debug_names &map, + block_search_flags block_index, domain_enum domain, + uint32_t namei, dwarf2_per_objfile *per_objfile) + : m_map (map), m_block_index (block_index), m_domain (domain), + m_addr (find_vec_in_debug_names (map, namei, per_objfile)), + m_per_objfile (per_objfile) + {} + + /* Return the next matching CU or NULL if there are no more. */ + dwarf2_per_cu_data *next (); + +private: + static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map, + const char *name, + dwarf2_per_objfile *per_objfile); + static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map, + uint32_t namei, + dwarf2_per_objfile *per_objfile); + + /* The internalized form of .debug_names. */ + const mapped_debug_names &m_map; + + /* Restrict the search to these blocks. */ + block_search_flags m_block_index = (SEARCH_GLOBAL_BLOCK + | SEARCH_STATIC_BLOCK); + + /* The kind of symbol we're looking for. */ + const domain_enum m_domain = UNDEF_DOMAIN; + const search_domain m_search = ALL_DOMAIN; + + /* The list of CUs from the index entry of the symbol, or NULL if + not found. */ + const gdb_byte *m_addr; + + dwarf2_per_objfile *m_per_objfile; +}; + +const char * +mapped_debug_names::namei_to_name + (uint32_t namei, dwarf2_per_objfile *per_objfile) 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 (per_objfile, 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, + dwarf2_per_objfile *per_objfile) +{ + int (*cmp) (const char *, const char *); + + gdb::unique_xmalloc_ptr without_params; + 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 + .debug_names does not contain any. */ + + if (strchr (name, '(') != NULL) + { + without_params = cp_remove_params (name); + if (without_params != NULL) + name = without_params.get (); + } + } + + cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp); + + const uint32_t full_hash = dwarf5_djb_hash (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) + return NULL; + --namei; + if (namei >= map.name_count) + { + complaint (_("Wrong .debug_names with name index %u but name_count=%u " + "[in module %s]"), + namei, map.name_count, + objfile_name (per_objfile->objfile)); + 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) + return NULL; + + if (full_hash == namei_full_hash) + { + const char *const namei_string = map.namei_to_name (namei, per_objfile); + +#if 0 /* An expensive sanity check. */ + if (namei_full_hash != dwarf5_djb_hash (namei_string)) + { + complaint (_("Wrong .debug_names hash for string at index %u " + "[in module %s]"), + namei, objfile_name (dwarf2_per_objfile->objfile)); + 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); + return map.entry_pool + namei_entry_offs; + } + } + + ++namei; + if (namei >= map.name_count) + return NULL; + } +} + +const gdb_byte * +dw2_debug_names_iterator::find_vec_in_debug_names + (const mapped_debug_names &map, uint32_t namei, dwarf2_per_objfile *per_objfile) +{ + if (namei >= map.name_count) + { + complaint (_("Wrong .debug_names with name index %u but name_count=%u " + "[in module %s]"), + namei, map.name_count, + objfile_name (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; +} + +/* See dw2_debug_names_iterator. */ + +dwarf2_per_cu_data * +dw2_debug_names_iterator::next () +{ + if (m_addr == NULL) + return NULL; + + dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; + struct objfile *objfile = m_per_objfile->objfile; + bfd *const abfd = objfile->obfd.get (); + + again: + + unsigned int bytes_read; + const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read); + m_addr += bytes_read; + if (abbrev == 0) + return NULL; + + const auto indexval_it = m_map.abbrev_map.find (abbrev); + if (indexval_it == m_map.abbrev_map.cend ()) + { + complaint (_("Wrong .debug_names undefined abbrev code %s " + "[in module %s]"), + pulongest (abbrev), objfile_name (objfile)); + return NULL; + } + const mapped_debug_names::index_val &indexval = indexval_it->second; + enum class symbol_linkage { + unknown, + static_, + extern_, + } symbol_linkage_ = symbol_linkage::unknown; + 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, m_addr, &bytes_read); + m_addr += bytes_read; + break; + case DW_FORM_ref4: + ull = read_4_bytes (abfd, m_addr); + m_addr += 4; + break; + case DW_FORM_ref8: + ull = read_8_bytes (abfd, m_addr); + m_addr += 8; + break; + case DW_FORM_ref_sig8: + ull = read_8_bytes (abfd, m_addr); + m_addr += 8; + break; + default: + complaint (_("Unsupported .debug_names form %s [in module %s]"), + dwarf_form_name (attr.form), + objfile_name (objfile)); + return NULL; + } + switch (attr.dw_idx) + { + case DW_IDX_compile_unit: + { + /* Don't crash on bad data. */ + if (ull >= per_bfd->all_comp_units.size ()) + { + complaint (_(".debug_names entry has bad CU index %s" + " [in module %s]"), + pulongest (ull), + objfile_name (objfile)); + continue; + } + } + per_cu = per_bfd->get_cu (ull); + break; + case DW_IDX_type_unit: + /* Don't crash on bad data. */ + if (ull >= per_bfd->all_type_units.size ()) + { + complaint (_(".debug_names entry has bad TU index %s" + " [in module %s]"), + pulongest (ull), + objfile_name (objfile)); + continue; + } + { + int nr_cus = per_bfd->all_comp_units.size (); + per_cu = per_bfd->get_cu (nr_cus + ull); + } + break; + case DW_IDX_die_offset: + /* In a per-CU index (as opposed to a per-module index), index + entries without CU attribute implicitly refer to the single CU. */ + if (per_cu == NULL) + per_cu = per_bfd->get_cu (0); + break; + case DW_IDX_GNU_internal: + if (!m_map.augmentation_is_gdb) + break; + symbol_linkage_ = symbol_linkage::static_; + break; + case DW_IDX_GNU_external: + if (!m_map.augmentation_is_gdb) + break; + symbol_linkage_ = symbol_linkage::extern_; + break; + } + } + + /* Skip if we couldn't find a valid CU/TU index. */ + if (per_cu == nullptr) + goto again; + + /* Skip if already read in. */ + if (m_per_objfile->symtab_set_p (per_cu)) + goto again; + + /* Check static vs global. */ + if (symbol_linkage_ != symbol_linkage::unknown) + { + if (symbol_linkage_ == symbol_linkage::static_) + { + if ((m_block_index & SEARCH_STATIC_BLOCK) == 0) + goto again; + } + else + { + if ((m_block_index & SEARCH_GLOBAL_BLOCK) == 0) + goto again; + } + } + + /* Match dw2_symtab_iter_next, symbol_kind + and debug_names::psymbol_tag. */ + switch (m_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: + goto again; + } + break; + case STRUCT_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_typedef: + case DW_TAG_structure_type: + break; + default: + goto again; + } + break; + case LABEL_DOMAIN: + switch (indexval.dwarf_tag) + { + case 0: + case DW_TAG_variable: + break; + default: + goto again; + } + break; + case MODULE_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_module: + break; + default: + goto again; + } + break; + default: + break; + } + + /* Match dw2_expand_symtabs_matching, symbol_kind and + debug_names::psymbol_tag. */ + switch (m_search) + { + case VARIABLES_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_variable: + break; + default: + goto again; + } + break; + case FUNCTIONS_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_subprogram: + break; + default: + goto again; + } + break; + case TYPES_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_typedef: + case DW_TAG_structure_type: + break; + default: + goto again; + } + break; + case MODULES_DOMAIN: + switch (indexval.dwarf_tag) + { + case DW_TAG_module: + break; + default: + goto again; + } + default: + break; + } + + return per_cu; +} + +/* This dumps minimal information about .debug_names. It is called + via "mt print objfiles". The gdb.dwarf2/gdb-index.exp testcase + uses this to verify that .debug_names has been loaded. */ + +void +dwarf2_debug_names_index::dump (struct objfile *objfile) +{ + gdb_printf (".debug_names: exists\n"); +} + +void +dwarf2_debug_names_index::expand_matching_symbols + (struct objfile *objfile, + const lookup_name_info &name, domain_enum domain, + int global, + symbol_compare_ftype *ordered_compare) +{ + dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); + + mapped_debug_names &map + = *(gdb::checked_static_cast + (per_objfile->per_bfd->index_table.get ())); + const block_search_flags block_flags + = global ? SEARCH_GLOBAL_BLOCK : SEARCH_STATIC_BLOCK; + + const char *match_name = name.ada ().lookup_name ().c_str (); + auto matcher = [&] (const char *symname) + { + if (ordered_compare == nullptr) + return true; + return ordered_compare (symname, match_name) == 0; + }; + + dw2_expand_symtabs_matching_symbol (map, name, matcher, + [&] (offset_type namei) + { + /* The name was matched, now expand corresponding CUs that were + marked. */ + dw2_debug_names_iterator iter (map, block_flags, domain, namei, + per_objfile); + + struct dwarf2_per_cu_data *per_cu; + while ((per_cu = iter.next ()) != NULL) + dw2_expand_symtabs_matching_one (per_cu, per_objfile, nullptr, + nullptr); + return true; + }, per_objfile); +} + +bool +dwarf2_debug_names_index::expand_symtabs_matching + (struct objfile *objfile, + gdb::function_view file_matcher, + const lookup_name_info *lookup_name, + gdb::function_view symbol_matcher, + gdb::function_view expansion_notify, + block_search_flags search_flags, + domain_enum domain, + enum search_domain kind) +{ + dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); + + dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher); + + /* This invariant is documented in quick-functions.h. */ + gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr); + if (lookup_name == nullptr) + { + for (dwarf2_per_cu_data *per_cu + : all_units_range (per_objfile->per_bfd)) + { + QUIT; + + if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, + file_matcher, + expansion_notify)) + return false; + } + return true; + } + + mapped_debug_names &map + = *(gdb::checked_static_cast + (per_objfile->per_bfd->index_table.get ())); + + bool result + = dw2_expand_symtabs_matching_symbol (map, *lookup_name, + symbol_matcher, + [&] (offset_type namei) + { + /* The name was matched, now expand corresponding CUs that were + marked. */ + dw2_debug_names_iterator iter (map, kind, namei, per_objfile, domain); + + struct dwarf2_per_cu_data *per_cu; + while ((per_cu = iter.next ()) != NULL) + if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, + file_matcher, + expansion_notify)) + return false; + return true; + }, per_objfile); + + return result; +} diff --git a/gdb/dwarf2/read-debug-names.h b/gdb/dwarf2/read-debug-names.h new file mode 100644 index 000000000000..0c20e8cfb8db --- /dev/null +++ b/gdb/dwarf2/read-debug-names.h @@ -0,0 +1,30 @@ +/* Reading code for .debug_names + + Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef DWARF2_READ_DEBUG_NAMES_H +#define DWARF2_READ_DEBUG_NAMES_H + +struct dwarf2_per_objfile; + +/* Read .debug_names. If everything went ok, initialize the "quick" + elements of all the CUs and return true. Otherwise, return false. */ + +bool dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile); + +#endif /* DWARF2_READ_DEBUG_NAMES_H */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 77ebd9572bc1..eb37c776989b 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -41,6 +41,7 @@ #include "dwarf2/dwz.h" #include "dwarf2/macro.h" #include "dwarf2/die.h" +#include "dwarf2/read-debug-names.h" #include "dwarf2/read-gdb-index.h" #include "dwarf2/sect-names.h" #include "dwarf2/stringify.h" @@ -156,57 +157,6 @@ static int dwarf2_loclist_block_index; /* Size of .debug_rnglists section header for 64-bit DWARF format. */ #define RNGLIST_HEADER_SIZE64 20 -/* A description of the mapped .debug_names. - Uninitialized map has CU_COUNT 0. */ -struct mapped_debug_names final : public mapped_index_base -{ - bfd_endian dwarf5_byte_order; - bool dwarf5_is_dwarf64; - bool augmentation_is_gdb; - 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; - - struct index_val - { - ULONGEST dwarf_tag; - struct attr - { - /* 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, dwarf2_per_objfile *per_objfile) const; - - /* Implementation of the mapped_index_base virtual interface, for - the name_components cache. */ - - const char *symbol_name_at - (offset_type idx, dwarf2_per_objfile *per_objfile) const override - { return namei_to_name (idx, per_objfile); } - - size_t symbol_name_count () const override - { return this->name_count; } - - quick_symbol_functions_up make_quick_functions () const override; -}; - /* See dwarf2/read.h. */ dwarf2_per_objfile * @@ -1664,34 +1614,6 @@ struct readnow_functions : public dwarf2_base_index_functions } }; -struct dwarf2_debug_names_index : public dwarf2_base_index_functions -{ - void dump (struct objfile *objfile) override; - - void expand_matching_symbols - (struct objfile *, - const lookup_name_info &lookup_name, - domain_enum domain, - int global, - symbol_compare_ftype *ordered_compare) override; - - bool expand_symtabs_matching - (struct objfile *objfile, - gdb::function_view file_matcher, - const lookup_name_info *lookup_name, - gdb::function_view symbol_matcher, - gdb::function_view expansion_notify, - block_search_flags search_flags, - domain_enum domain, - enum search_domain kind) override; -}; - -quick_symbol_functions_up -mapped_debug_names::make_quick_functions () const -{ - return quick_symbol_functions_up (new dwarf2_debug_names_index); -} - /* Utility hash function for a stmt_list_hash. */ static hashval_t @@ -1874,61 +1796,11 @@ create_cu_from_index_list (dwarf2_per_bfd *per_bfd, return the_cu; } -/* Create the signatured type hash table from .debug_names. */ - -static void -create_signatured_type_table_from_debug_names - (dwarf2_per_objfile *per_objfile, - const mapped_debug_names &map, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section) -{ - struct objfile *objfile = per_objfile->objfile; - - section->read (objfile); - abbrev_section->read (objfile); - - htab_up sig_types_hash = allocate_signatured_type_table (); - - for (uint32_t i = 0; i < map.tu_count; ++i) - { - signatured_type_up sig_type; - void **slot; - - 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 (per_objfile, &cu_header, section, - abbrev_section, - section->buffer + to_underlying (sect_off), - rcuh_kind::TYPE); - - sig_type = per_objfile->per_bfd->allocate_signatured_type - (cu_header.signature); - sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu; - sig_type->section = section; - sig_type->sect_off = sect_off; - - slot = htab_find_slot (sig_types_hash.get (), sig_type.get (), INSERT); - *slot = sig_type.get (); - - per_objfile->per_bfd->all_units.emplace_back (sig_type.release ()); - } - - per_objfile->per_bfd->signatured_types = std::move (sig_types_hash); -} - -/* Read the address map data from DWARF-5 .debug_aranges, and use it - to populate given addrmap. Returns true on success, false on - failure. */ +/* See read.h. */ bool read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile, - struct dwarf2_section_info *section, + dwarf2_section_info *section, addrmap *mutable_map) { struct objfile *objfile = per_objfile->objfile; @@ -2105,23 +1977,6 @@ read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile, return true; } -/* Read the address map data from DWARF-5 .debug_aranges, and use it to - populate the index_addrmap. */ - -static void -create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile, - struct dwarf2_section_info *section) -{ - dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - - addrmap_mutable mutable_map; - - if (read_addrmap_from_aranges (per_objfile, section, &mutable_map)) - per_bfd->index_addrmap - = new (&per_bfd->obstack) addrmap_fixed (&per_bfd->obstack, - &mutable_map); -} - /* die_reader_func for dw2_get_file_names. */ static void @@ -3429,886 +3284,6 @@ dwarf2_base_index_functions::has_unexpanded_symtabs (struct objfile *objfile) return false; } -/* DWARF-5 debug_names reader. */ - -/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */ -static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 }; - -/* A helper function that reads the .debug_names section in SECTION - and fills in MAP. FILENAME is the name of the file containing the - section; it is used for error reporting. - - Returns true if all went well, false otherwise. */ - -static bool -read_debug_names_from_section (struct objfile *objfile, - const char *filename, - struct dwarf2_section_info *section, - mapped_debug_names &map) -{ - if (section->empty ()) - return false; - - /* Older elfutils strip versions could keep the section in the main - executable while splitting it for the separate debug info file. */ - if ((section->get_flags () & SEC_HAS_CONTENTS) == 0) - return false; - - section->read (objfile); - - map.dwarf5_byte_order = gdbarch_byte_order (objfile->arch ()); - - const gdb_byte *addr = section->buffer; - - bfd *const abfd = section->get_bfd_owner (); - - unsigned int bytes_read; - LONGEST 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. */ - uint16_t version = read_2_bytes (abfd, addr); - addr += 2; - if (version != 5) - { - warning (_("Section .debug_names in %s has unsupported version %d, " - "ignoring .debug_names."), - filename, version); - return false; - } - - /* Padding. */ - uint16_t 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; - } - - /* comp_unit_count - The number of CUs in the CU list. */ - map.cu_count = read_4_bytes (abfd, addr); - addr += 4; - - /* 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. */ - uint32_t foreign_tu_count = read_4_bytes (abfd, addr); - addr += 4; - if (foreign_tu_count != 0) - { - warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, " - "ignoring .debug_names."), - filename, static_cast (foreign_tu_count)); - return false; - } - - /* bucket_count - The number of hash buckets in the hash lookup - table. */ - map.bucket_count = read_4_bytes (abfd, addr); - addr += 4; - - /* 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. */ - uint32_t 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. */ - uint32_t augmentation_string_size = read_4_bytes (abfd, addr); - addr += 4; - map.augmentation_is_gdb = ((augmentation_string_size - == sizeof (dwarf5_augmentation)) - && memcmp (addr, dwarf5_augmentation, - sizeof (dwarf5_augmentation)) == 0); - 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; - - const gdb_byte *abbrev_table_start = addr; - for (;;) - { - 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) - { - 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; - - 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 (addr != abbrev_table_start + abbrev_table_size) - { - warning (_("Section .debug_names in %s has abbreviation_table " - "of size %s vs. written as %u, ignoring .debug_names."), - filename, plongest (addr - abbrev_table_start), - abbrev_table_size); - return false; - } - map.entry_pool = addr; - - return true; -} - -/* A helper for create_cus_from_debug_names that handles the MAP's CU - list. */ - -static bool -create_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, - const mapped_debug_names &map, - dwarf2_section_info §ion, - bool is_dwz) -{ - if (!map.augmentation_is_gdb) - { - for (uint32_t i = 0; i < map.cu_count; ++i) - { - sect_offset sect_off - = (sect_offset) (extract_unsigned_integer - (map.cu_table_reordered + i * map.offset_size, - map.offset_size, - map.dwarf5_byte_order)); - /* We don't know the length of the CU, because the CU list in a - .debug_names index can be incomplete, so we can't use the start - of the next CU as end of this CU. We create the CUs here with - length 0, and in cutu_reader::cutu_reader we'll fill in the - actual length. */ - dwarf2_per_cu_data_up per_cu - = create_cu_from_index_list (per_bfd, §ion, is_dwz, - sect_off, 0); - per_bfd->all_units.push_back (std::move (per_cu)); - } - return true; - } - - 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) - { - if (sect_off_next == sect_off_prev) - { - warning (_("Section .debug_names has duplicate entry in CU table," - " ignoring .debug_names.")); - return false; - } - if (sect_off_next < sect_off_prev) - { - warning (_("Section .debug_names has non-ascending CU table," - " ignoring .debug_names.")); - return false; - } - /* Note: we're not using length = sect_off_next - sect_off_prev, - to gracefully handle an incomplete CU list. */ - const ULONGEST length = 0; - dwarf2_per_cu_data_up per_cu - = create_cu_from_index_list (per_bfd, §ion, is_dwz, - sect_off_prev, length); - per_bfd->all_units.push_back (std::move (per_cu)); - } - sect_off_prev = sect_off_next; - } - - return true; -} - -/* Read the CU list from the mapped index, and use it to create all - the CU objects for this dwarf2_per_objfile. */ - -static bool -create_cus_from_debug_names (dwarf2_per_bfd *per_bfd, - const mapped_debug_names &map, - const mapped_debug_names &dwz_map) -{ - gdb_assert (per_bfd->all_units.empty ()); - per_bfd->all_units.reserve (map.cu_count + dwz_map.cu_count); - - if (!create_cus_from_debug_names_list (per_bfd, map, per_bfd->info, - false /* is_dwz */)) - return false; - - if (dwz_map.cu_count == 0) - return true; - - dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); - return create_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info, - true /* is_dwz */); -} - -/* 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 (dwarf2_per_objfile *per_objfile) -{ - std::unique_ptr map (new mapped_debug_names); - mapped_debug_names dwz_map; - struct objfile *objfile = per_objfile->objfile; - dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - - if (!read_debug_names_from_section (objfile, objfile_name (objfile), - &per_bfd->debug_names, *map)) - return false; - - /* Don't use the index if it's empty. */ - if (map->name_count == 0) - return false; - - /* If there is a .dwz file, read it so we can get its CU list as - well. */ - dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); - if (dwz != NULL) - { - if (!read_debug_names_from_section (objfile, - bfd_get_filename (dwz->dwz_bfd.get ()), - &dwz->debug_names, dwz_map)) - { - warning (_("could not read '.debug_names' section from %s; skipping"), - bfd_get_filename (dwz->dwz_bfd.get ())); - return false; - } - } - - if (!create_cus_from_debug_names (per_bfd, *map, dwz_map)) - { - per_bfd->all_units.clear (); - return false; - } - - if (map->tu_count != 0) - { - /* We can only handle a single .debug_types when we have an - index. */ - if (per_bfd->types.size () > 1) - { - per_bfd->all_units.clear (); - return false; - } - - dwarf2_section_info *section - = (per_bfd->types.size () == 1 - ? &per_bfd->types[0] - : &per_bfd->info); - - create_signatured_type_table_from_debug_names - (per_objfile, *map, section, &per_bfd->abbrev); - } - - finalize_all_units (per_bfd); - - create_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges); - - per_bfd->index_table = std::move (map); - per_bfd->quick_file_names_table = - create_quick_file_names_table (per_bfd->all_units.size ()); - - return true; -} - -/* Type used to manage iterating over all CUs looking for a symbol for - .debug_names. */ - -class dw2_debug_names_iterator -{ -public: - dw2_debug_names_iterator (const mapped_debug_names &map, - block_search_flags block_index, - domain_enum domain, - const char *name, dwarf2_per_objfile *per_objfile) - : m_map (map), m_block_index (block_index), m_domain (domain), - m_addr (find_vec_in_debug_names (map, name, per_objfile)), - m_per_objfile (per_objfile) - {} - - dw2_debug_names_iterator (const mapped_debug_names &map, - search_domain search, uint32_t namei, - dwarf2_per_objfile *per_objfile, - domain_enum domain = UNDEF_DOMAIN) - : m_map (map), - m_domain (domain), - m_search (search), - m_addr (find_vec_in_debug_names (map, namei, per_objfile)), - m_per_objfile (per_objfile) - {} - - dw2_debug_names_iterator (const mapped_debug_names &map, - block_search_flags block_index, domain_enum domain, - uint32_t namei, dwarf2_per_objfile *per_objfile) - : m_map (map), m_block_index (block_index), m_domain (domain), - m_addr (find_vec_in_debug_names (map, namei, per_objfile)), - m_per_objfile (per_objfile) - {} - - /* Return the next matching CU or NULL if there are no more. */ - dwarf2_per_cu_data *next (); - -private: - static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map, - const char *name, - dwarf2_per_objfile *per_objfile); - static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map, - uint32_t namei, - dwarf2_per_objfile *per_objfile); - - /* The internalized form of .debug_names. */ - const mapped_debug_names &m_map; - - /* Restrict the search to these blocks. */ - block_search_flags m_block_index = (SEARCH_GLOBAL_BLOCK - | SEARCH_STATIC_BLOCK); - - /* The kind of symbol we're looking for. */ - const domain_enum m_domain = UNDEF_DOMAIN; - const search_domain m_search = ALL_DOMAIN; - - /* The list of CUs from the index entry of the symbol, or NULL if - not found. */ - const gdb_byte *m_addr; - - dwarf2_per_objfile *m_per_objfile; -}; - -const char * -mapped_debug_names::namei_to_name - (uint32_t namei, dwarf2_per_objfile *per_objfile) 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 (per_objfile, 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, - dwarf2_per_objfile *per_objfile) -{ - int (*cmp) (const char *, const char *); - - gdb::unique_xmalloc_ptr without_params; - 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 - .debug_names does not contain any. */ - - if (strchr (name, '(') != NULL) - { - without_params = cp_remove_params (name); - if (without_params != NULL) - name = without_params.get (); - } - } - - cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp); - - const uint32_t full_hash = dwarf5_djb_hash (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) - return NULL; - --namei; - if (namei >= map.name_count) - { - complaint (_("Wrong .debug_names with name index %u but name_count=%u " - "[in module %s]"), - namei, map.name_count, - objfile_name (per_objfile->objfile)); - 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) - return NULL; - - if (full_hash == namei_full_hash) - { - const char *const namei_string = map.namei_to_name (namei, per_objfile); - -#if 0 /* An expensive sanity check. */ - if (namei_full_hash != dwarf5_djb_hash (namei_string)) - { - complaint (_("Wrong .debug_names hash for string at index %u " - "[in module %s]"), - namei, objfile_name (dwarf2_per_objfile->objfile)); - 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); - return map.entry_pool + namei_entry_offs; - } - } - - ++namei; - if (namei >= map.name_count) - return NULL; - } -} - -const gdb_byte * -dw2_debug_names_iterator::find_vec_in_debug_names - (const mapped_debug_names &map, uint32_t namei, dwarf2_per_objfile *per_objfile) -{ - if (namei >= map.name_count) - { - complaint (_("Wrong .debug_names with name index %u but name_count=%u " - "[in module %s]"), - namei, map.name_count, - objfile_name (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; -} - -/* See dw2_debug_names_iterator. */ - -dwarf2_per_cu_data * -dw2_debug_names_iterator::next () -{ - if (m_addr == NULL) - return NULL; - - dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; - struct objfile *objfile = m_per_objfile->objfile; - bfd *const abfd = objfile->obfd.get (); - - again: - - unsigned int bytes_read; - const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read); - m_addr += bytes_read; - if (abbrev == 0) - return NULL; - - const auto indexval_it = m_map.abbrev_map.find (abbrev); - if (indexval_it == m_map.abbrev_map.cend ()) - { - complaint (_("Wrong .debug_names undefined abbrev code %s " - "[in module %s]"), - pulongest (abbrev), objfile_name (objfile)); - return NULL; - } - const mapped_debug_names::index_val &indexval = indexval_it->second; - enum class symbol_linkage { - unknown, - static_, - extern_, - } symbol_linkage_ = symbol_linkage::unknown; - 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, m_addr, &bytes_read); - m_addr += bytes_read; - break; - case DW_FORM_ref4: - ull = read_4_bytes (abfd, m_addr); - m_addr += 4; - break; - case DW_FORM_ref8: - ull = read_8_bytes (abfd, m_addr); - m_addr += 8; - break; - case DW_FORM_ref_sig8: - ull = read_8_bytes (abfd, m_addr); - m_addr += 8; - break; - default: - complaint (_("Unsupported .debug_names form %s [in module %s]"), - dwarf_form_name (attr.form), - objfile_name (objfile)); - return NULL; - } - switch (attr.dw_idx) - { - case DW_IDX_compile_unit: - { - /* Don't crash on bad data. */ - if (ull >= per_bfd->all_comp_units.size ()) - { - complaint (_(".debug_names entry has bad CU index %s" - " [in module %s]"), - pulongest (ull), - objfile_name (objfile)); - continue; - } - } - per_cu = per_bfd->get_cu (ull); - break; - case DW_IDX_type_unit: - /* Don't crash on bad data. */ - if (ull >= per_bfd->all_type_units.size ()) - { - complaint (_(".debug_names entry has bad TU index %s" - " [in module %s]"), - pulongest (ull), - objfile_name (objfile)); - continue; - } - { - int nr_cus = per_bfd->all_comp_units.size (); - per_cu = per_bfd->get_cu (nr_cus + ull); - } - break; - case DW_IDX_die_offset: - /* In a per-CU index (as opposed to a per-module index), index - entries without CU attribute implicitly refer to the single CU. */ - if (per_cu == NULL) - per_cu = per_bfd->get_cu (0); - break; - case DW_IDX_GNU_internal: - if (!m_map.augmentation_is_gdb) - break; - symbol_linkage_ = symbol_linkage::static_; - break; - case DW_IDX_GNU_external: - if (!m_map.augmentation_is_gdb) - break; - symbol_linkage_ = symbol_linkage::extern_; - break; - } - } - - /* Skip if we couldn't find a valid CU/TU index. */ - if (per_cu == nullptr) - goto again; - - /* Skip if already read in. */ - if (m_per_objfile->symtab_set_p (per_cu)) - goto again; - - /* Check static vs global. */ - if (symbol_linkage_ != symbol_linkage::unknown) - { - if (symbol_linkage_ == symbol_linkage::static_) - { - if ((m_block_index & SEARCH_STATIC_BLOCK) == 0) - goto again; - } - else - { - if ((m_block_index & SEARCH_GLOBAL_BLOCK) == 0) - goto again; - } - } - - /* Match dw2_symtab_iter_next, symbol_kind - and debug_names::psymbol_tag. */ - switch (m_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: - goto again; - } - break; - case STRUCT_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_typedef: - case DW_TAG_structure_type: - break; - default: - goto again; - } - break; - case LABEL_DOMAIN: - switch (indexval.dwarf_tag) - { - case 0: - case DW_TAG_variable: - break; - default: - goto again; - } - break; - case MODULE_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_module: - break; - default: - goto again; - } - break; - default: - break; - } - - /* Match dw2_expand_symtabs_matching, symbol_kind and - debug_names::psymbol_tag. */ - switch (m_search) - { - case VARIABLES_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_variable: - break; - default: - goto again; - } - break; - case FUNCTIONS_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_subprogram: - break; - default: - goto again; - } - break; - case TYPES_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_typedef: - case DW_TAG_structure_type: - break; - default: - goto again; - } - break; - case MODULES_DOMAIN: - switch (indexval.dwarf_tag) - { - case DW_TAG_module: - break; - default: - goto again; - } - default: - break; - } - - return per_cu; -} - -/* This dumps minimal information about .debug_names. It is called - via "mt print objfiles". The gdb.dwarf2/gdb-index.exp testcase - uses this to verify that .debug_names has been loaded. */ - -void -dwarf2_debug_names_index::dump (struct objfile *objfile) -{ - gdb_printf (".debug_names: exists\n"); -} - -void -dwarf2_debug_names_index::expand_matching_symbols - (struct objfile *objfile, - const lookup_name_info &name, domain_enum domain, - int global, - symbol_compare_ftype *ordered_compare) -{ - dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); - - mapped_debug_names &map - = *(gdb::checked_static_cast - (per_objfile->per_bfd->index_table.get ())); - const block_search_flags block_flags - = global ? SEARCH_GLOBAL_BLOCK : SEARCH_STATIC_BLOCK; - - const char *match_name = name.ada ().lookup_name ().c_str (); - auto matcher = [&] (const char *symname) - { - if (ordered_compare == nullptr) - return true; - return ordered_compare (symname, match_name) == 0; - }; - - dw2_expand_symtabs_matching_symbol (map, name, matcher, - [&] (offset_type namei) - { - /* The name was matched, now expand corresponding CUs that were - marked. */ - dw2_debug_names_iterator iter (map, block_flags, domain, namei, - per_objfile); - - struct dwarf2_per_cu_data *per_cu; - while ((per_cu = iter.next ()) != NULL) - dw2_expand_symtabs_matching_one (per_cu, per_objfile, nullptr, - nullptr); - return true; - }, per_objfile); -} - -bool -dwarf2_debug_names_index::expand_symtabs_matching - (struct objfile *objfile, - gdb::function_view file_matcher, - const lookup_name_info *lookup_name, - gdb::function_view symbol_matcher, - gdb::function_view expansion_notify, - block_search_flags search_flags, - domain_enum domain, - enum search_domain kind) -{ - dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); - - dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher); - - /* This invariant is documented in quick-functions.h. */ - gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr); - if (lookup_name == nullptr) - { - for (dwarf2_per_cu_data *per_cu - : all_units_range (per_objfile->per_bfd)) - { - QUIT; - - if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, - file_matcher, - expansion_notify)) - return false; - } - return true; - } - - mapped_debug_names &map - = *(gdb::checked_static_cast - (per_objfile->per_bfd->index_table.get ())); - - bool result - = dw2_expand_symtabs_matching_symbol (map, *lookup_name, - symbol_matcher, - [&] (offset_type namei) - { - /* The name was matched, now expand corresponding CUs that were - marked. */ - dw2_debug_names_iterator iter (map, kind, namei, per_objfile, domain); - - struct dwarf2_per_cu_data *per_cu; - while ((per_cu = iter.next ()) != NULL) - if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, - file_matcher, - expansion_notify)) - return false; - return true; - }, per_objfile); - - return result; -} - /* Get the content of the .gdb_index section of OBJ. SECTION_OWNER should point to either a dwarf2_per_bfd or dwz_file object. */ -- 2.39.1