Patchwork [v2,5/5] DWARF-5: .debug_names index consumer

login
register
mail settings
Submitter Jan Kratochvil
Date June 18, 2017, 7:33 p.m.
Message ID <149781438249.10382.13230549403227962191.stgit@host1.jankratochvil.net>
Download mbox | patch
Permalink /patch/21069/
State New
Headers show

Comments

Jan Kratochvil - June 18, 2017, 7:33 p.m.
Hi,

it is not regression-free against no-index but it is regression-free against
.gdb_index.  That is because .gdb_index is not regression-free against
no-index.

Some testcases needed to be updated as they were missing .debug_aranges.
While that does not matter for no-index (as GDB builds the mapping internally
during dwarf2_build_psymtabs_hard) and neither for .gdb_index (as GDB uses that
internally built mapping which it stores into .gdb_index) it does matter for
.debug_names as that simply assumes existing .debug_aranges from GCC.

I tried some performance checking but the index handling speed is negligible
compared to the CU expansion associated with it.  .debug_names looked even as
a bit faster to me than .gdb_index which rather surprised me but I did not
investigate it more.


Jan


gdb/ChangeLog
2017-05-26  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* defs.h (elf_sym_fns_debug_names): New declaration.
	* dwarf2read.c (mapped_debug_names): New.
	(struct dwarf2_per_objfile): Add debug_names, debug_aranges and
	debug_names_table.
	(dwarf2_elf_names): Add debug_names and debug_aranges.
	(struct dwz_file): Add debug_names.
	(dwarf2_locate_sections): Add debug_names and debug_aranges.
	(locate_dwz_sections): Add debug_names.
	(create_signatured_type_table_from_debug_names)
	(create_addrmap_from_aranges): New.
	(dwarf2_read_index): Update function comment.
	(read_debug_names_from_section, create_cus_from_debug_names_list)
	(create_cus_from_debug_names, dwarf2_read_debug_names): New.
	(dwarf5_djb_hash): Function renamed from DebugNamesNameTable::djb_hash.
	(dw2_debug_names_iterator): New.
	(read_indirect_string_at_offset): New declaration.
	(mapped_debug_names::namei_to_name)
	(dw2_debug_names_iterator::find_vec_in_debug_names)
	(dw2_debug_names_iterator::find_vec_in_debug_names)
	(dw2_debug_names_iterator::next, dw2_debug_names_lookup_symbol)
	(dw2_debug_names_dump, dw2_debug_names_expand_symtabs_for_function)
	(dw2_debug_names_expand_symtabs_matching, dwarf2_debug_names_functions):
	New.
	(dwarf2_initialize_objfile): Return also elf_sym_fns_debug_names.
	(dwarf2_free_objfile): Delete also debug_names_table;
	(debug_names::djb_hash): Rename it to dwarf5_djb_hash.
	(debug_names::build): Update djb_hash caller.
	* elfread.c (elf_sym_fns_debug_names): New.
	* psymtab.h (dwarf2_debug_names_functions): New declaration.
	* symfile.h (struct dwarf2_debug_sections): Add debug_names and
	debug_aranges.
	* xcoffread.c (dwarf2_xcoff_names): Add debug_names and debug_aranges.

gdb/testsuite/ChangeLog
2017-05-26  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.base/maint.exp (check for .gdb_index): Check also for
	.debug_names.
	* gdb.dlang/watch-loc.c (.debug_aranges): New.
	* gdb.dwarf2/dw2-case-insensitive-debug.S: Likewise.
	* gdb.dwarf2/gdb-index.exp (check if index present, .gdb_index used)
	(.gdb_index used after symbol reloading): Support also .debug_names.
	* gdb.mi/dw2-ref-missing-frame-func.c (.debug_aranges): New.
---
 gdb/defs.h                                         |    1 
 gdb/dwarf2read.c                                   | 1474 +++++++++++++++++---
 gdb/elfread.c                                      |   17 
 gdb/psymtab.h                                      |    1 
 gdb/symfile.h                                      |    2 
 gdb/testsuite/gdb.base/maint.exp                   |    7 
 gdb/testsuite/gdb.dlang/watch-loc.c                |   19 
 .../gdb.dwarf2/dw2-case-insensitive-debug.S        |   17 
 gdb/testsuite/gdb.dwarf2/gdb-index.exp             |    7 
 gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c  |   20 
 gdb/xcoffread.c                                    |    2 
 11 files changed, 1378 insertions(+), 189 deletions(-)

Patch

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