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 \
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 \
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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> attr_vec;
+ };
+
+ std::unordered_map<ULONGEST, index_val> 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<expand_symtabs_file_matcher_ftype> file_matcher,
+ const lookup_name_info *lookup_name,
+ gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> 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<unsigned long> (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<const uint32_t *> (addr);
+ addr += map.bucket_count * 4;
+ map.hash_table_reordered = reinterpret_cast<const uint32_t *> (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<mapped_debug_names> 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<char> 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<const gdb_byte *>
+ (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<const gdb_byte *>
+ (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<mapped_debug_names *>
+ (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<expand_symtabs_file_matcher_ftype> file_matcher,
+ const lookup_name_info *lookup_name,
+ gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> 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<mapped_debug_names *>
+ (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;
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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 */
#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"
/* 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> attr_vec;
- };
-
- std::unordered_map<ULONGEST, index_val> 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 *
}
};
-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<expand_symtabs_file_matcher_ftype> file_matcher,
- const lookup_name_info *lookup_name,
- gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
- gdb::function_view<expand_symtabs_exp_notify_ftype> 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
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;
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
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<unsigned long> (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<const uint32_t *> (addr);
- addr += map.bucket_count * 4;
- map.hash_table_reordered = reinterpret_cast<const uint32_t *> (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<mapped_debug_names> 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<char> 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<const gdb_byte *>
- (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<const gdb_byte *>
- (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<mapped_debug_names *>
- (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<expand_symtabs_file_matcher_ftype> file_matcher,
- const lookup_name_info *lookup_name,
- gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
- gdb::function_view<expand_symtabs_exp_notify_ftype> 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<mapped_debug_names *>
- (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. */