/* 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 &section,
				  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, &section, 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, &section, 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)
{
  auto map = gdb::make_unique<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;
}
