public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] DWARF-5: .debug_names index
@ 2017-06-18 19:32 Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

Hi,

https://sourceware.org/git/gitweb.cgi?p=archer.git;a=shortlog;h=refs/heads/users/jkratoch/index
git://sourceware.org/git/archer.git
  git diff gdb/master...archer/users/jkratoch/index

the patches mailed in this series depend on these already posted ones:
	[gcc patch] DWARF-5: Define DW_IDX_GNU_static and DW_IDX_GNU_external
	https://gcc.gnu.org/ml/gcc-patches/2017-05/msg02074.html
	Message-ID: <20170526181408.GA15337@host1.jankratochvil.net>
	+
	[binutils patch] DWARF-5: readelf: .debug_names
	https://sourceware.org/ml/binutils/2017-05/msg00291.html
	Message-ID: <20170526181552.GA15442@host1.jankratochvil.net>

Default "save gdb-index" will switch to DWARF-5 but that requires also the
updated: contrib/gdb-add-index.sh

DWO is not yet handled.  Discussed here whether it should be:
	https://sourceware.org/ml/gdb-patches/2017-06/msg00479.html


Jan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
@ 2017-06-18 19:32 ` Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

Hi,

just for the next patch.


Jan


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

	* dwarf2read.c (create_cu_from_index_list): New from ...
	(create_cus_from_index_list): ... this function, use it.
	(dw_expand_symtabs_matching_file_matcher)
	(dw2_expand_symtabs_matching_one): New from ...
	(dw2_expand_symtabs_matching): ... this function, use them.
---
 gdb/dwarf2read.c |  220 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 130 insertions(+), 90 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 763f539..3137d2f 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2941,6 +2941,28 @@ dw2_get_cu (int index)
   return dwarf2_per_objfile->all_comp_units[index];
 }
 
+/* Return newly allocated dwarf2_per_cu_data from objfile_obstack
+   with the specified field values.  */
+
+static dwarf2_per_cu_data *
+create_cu_from_index_list (struct objfile *objfile,
+			   struct dwarf2_section_info *section,
+			   int is_dwz,
+			   sect_offset sect_off, ULONGEST length)
+{
+  dwarf2_per_cu_data *the_cu
+    = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+		      struct dwarf2_per_cu_data);
+  the_cu->sect_off = sect_off;
+  the_cu->length = length;
+  the_cu->objfile = objfile;
+  the_cu->section = section;
+  the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+				    struct dwarf2_per_cu_quick_data);
+  the_cu->is_dwz = is_dwz;
+  return the_cu;
+}
+
 /* A helper for create_cus_from_index that handles a given list of
    CUs.  */
 
@@ -2962,17 +2984,8 @@ create_cus_from_index_list (struct objfile *objfile,
       ULONGEST length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE);
       cu_list += 2 * 8;
 
-      dwarf2_per_cu_data *the_cu
-	= OBSTACK_ZALLOC (&objfile->objfile_obstack,
-			  struct dwarf2_per_cu_data);
-      the_cu->sect_off = sect_off;
-      the_cu->length = length;
-      the_cu->objfile = objfile;
-      the_cu->section = section;
-      the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-					struct dwarf2_per_cu_quick_data);
-      the_cu->is_dwz = is_dwz;
-      dwarf2_per_objfile->all_comp_units[base_offset + i / 2] = the_cu;
+      dwarf2_per_objfile->all_comp_units[base_offset + i / 2] =
+	 create_cu_from_index_list (objfile, section, is_dwz, sect_off, length);
     }
 }
 
@@ -4015,96 +4028,135 @@ dw2_map_matching_symbols (struct objfile *objfile,
      does not look for non-Ada symbols this function should just return.  */
 }
 
+/* If FILE_MATCHER is non-zero set for current DWARF2_PER_OBJFILE all
+   dwarf2_per_cu_quick_data::MARK matching FILE_MATCHER.  */
+
 static void
-dw2_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)
+dw_expand_symtabs_matching_file_matcher
+  (gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
 {
-  int i;
-  offset_type iter;
-  struct mapped_index *index;
+  objfile *const objfile (dwarf2_per_objfile->objfile);
 
-  dw2_setup (objfile);
-
-  /* index_table is NULL if OBJF_READNOW.  */
-  if (!dwarf2_per_objfile->index_table)
+  if (file_matcher == NULL)
     return;
-  index = dwarf2_per_objfile->index_table;
 
-  if (file_matcher != NULL)
-    {
-      htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
+  htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
+					    htab_eq_pointer,
+					    NULL, xcalloc, xfree));
+  htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer,
 						htab_eq_pointer,
 						NULL, xcalloc, xfree));
-      htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer,
-						    htab_eq_pointer,
-						    NULL, xcalloc, xfree));
 
-      /* The rule is CUs specify all the files, including those used by
-	 any TU, so there's no need to scan TUs here.  */
+  /* The rule is CUs specify all the files, including those used by
+     any TU, so there's no need to scan TUs here.  */
 
-      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;
+  for (int 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;
 
-	  QUIT;
+      QUIT;
 
-	  per_cu->v.quick->mark = 0;
+      per_cu->v.quick->mark = 0;
 
-	  /* We only need to look at symtabs not already expanded.  */
-	  if (per_cu->v.quick->compunit_symtab)
-	    continue;
+      /* 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;
+      file_data = dw2_get_file_names (per_cu);
+      if (file_data == NULL)
+	continue;
 
-	  if (htab_find (visited_not_found.get (), file_data) != NULL)
-	    continue;
-	  else if (htab_find (visited_found.get (), file_data) != NULL)
+      if (htab_find (visited_not_found.get (), file_data) != NULL)
+	continue;
+      else if (htab_find (visited_found.get (), file_data) != NULL)
+	{
+	  per_cu->v.quick->mark = 1;
+	  continue;
+	}
+
+      for (j = 0; j < file_data->num_file_names; ++j)
+	{
+	  const char *this_real_name;
+
+	  if (file_matcher (file_data->file_names[j], false))
 	    {
 	      per_cu->v.quick->mark = 1;
-	      continue;
+	      break;
 	    }
 
-	  for (j = 0; j < file_data->num_file_names; ++j)
+	  /* Before we invoke realpath, which can get expensive when many
+	     files are involved, do a quick comparison of the basenames.  */
+	  if (!basenames_may_differ
+	      && !file_matcher (lbasename (file_data->file_names[j]),
+				true))
+	    continue;
+
+	  this_real_name = dw2_get_real_path (objfile, file_data, j);
+	  if (file_matcher (this_real_name, false))
 	    {
-	      const char *this_real_name;
+	      per_cu->v.quick->mark = 1;
+	      break;
+	    }
+	}
 
-	      if (file_matcher (file_data->file_names[j], false))
-		{
-		  per_cu->v.quick->mark = 1;
-		  break;
-		}
+      slot = htab_find_slot (per_cu->v.quick->mark
+			     ? visited_found.get ()
+			     : visited_not_found.get (),
+			     file_data, INSERT);
+      *slot = file_data;
+    }
+}
 
-	      /* Before we invoke realpath, which can get expensive when many
-		 files are involved, do a quick comparison of the basenames.  */
-	      if (!basenames_may_differ
-		  && !file_matcher (lbasename (file_data->file_names[j]),
-				    true))
-		continue;
+/* If FILE_MATCHER is zero
+   or if PER_CU has dwarf2_per_cu_quick_data::MARK set
+   (see dw_expand_symtabs_matching_file_matcher) expand the CU
+   and call its EXPANSION_NOTIFY.  */
 
-	      this_real_name = dw2_get_real_path (objfile, file_data, j);
-	      if (file_matcher (this_real_name, false))
-		{
-		  per_cu->v.quick->mark = 1;
-		  break;
-		}
-	    }
+static void
+dw2_expand_symtabs_matching_one
+  (struct dwarf2_per_cu_data *per_cu,
+   gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+   gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify)
+{
+  if (file_matcher == NULL || per_cu->v.quick->mark)
+    {
+      int symtab_was_null =
+	(per_cu->v.quick->compunit_symtab == NULL);
+
+      dw2_instantiate_symtab (per_cu);
 
-	  slot = htab_find_slot (per_cu->v.quick->mark
-				 ? visited_found.get ()
-				 : visited_not_found.get (),
-				 file_data, INSERT);
-	  *slot = file_data;
+      if (expansion_notify != NULL
+	  && symtab_was_null
+	  && per_cu->v.quick->compunit_symtab != NULL)
+	{
+	  expansion_notify (per_cu->v.quick->compunit_symtab);
 	}
     }
+}
+
+static void
+dw2_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)
+{
+  int i;
+  offset_type iter;
+  struct mapped_index *index;
+
+  dw2_setup (objfile);
+
+  /* index_table is NULL if OBJF_READNOW.  */
+  if (!dwarf2_per_objfile->index_table)
+    return;
+  index = dwarf2_per_objfile->index_table;
+
+  dw_expand_symtabs_matching_file_matcher (file_matcher);
 
   for (iter = 0; iter < index->symbol_table_slots; ++iter)
     {
@@ -4187,20 +4239,8 @@ dw2_expand_symtabs_matching
 	    }
 
 	  per_cu = dw2_get_cutu (cu_index);
-	  if (file_matcher == NULL || per_cu->v.quick->mark)
-	    {
-	      int symtab_was_null =
-		(per_cu->v.quick->compunit_symtab == NULL);
-
-	      dw2_instantiate_symtab (per_cu);
-
-	      if (expansion_notify != NULL
-		  && symtab_was_null
-		  && per_cu->v.quick->compunit_symtab != NULL)
-		{
-		  expansion_notify (per_cu->v.quick->compunit_symtab);
-		}
-	    }
+	  dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+					   expansion_notify);
 	}
     }
 }

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 2/5] DWARF-5: .debug_names index producer
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
                   ` (2 preceding siblings ...)
  2017-06-18 19:32 ` [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
@ 2017-06-18 19:32 ` Jan Kratochvil
  2017-06-18 19:33 ` [PATCH v2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
  2017-06-19 20:56 ` obsolete: [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

Hi,

there are two FIXME lines I do not have a real answer for.

Also I am not sure if the -dwarf-4 option for former .gdb_index should be named
that way.  And contrib/gdb-add-index.sh (incl. cc-with-tweaks.sh) has no
commandline option for that -dwarf-4 GDB option.


Jan


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

	* contrib/gdb-add-index.sh (index): Rename to ...
	(index4): ... here.
	(index5, debugstr, debugstrmerge, debugstrerr): New variables.
	Support also .debug_names and .debug_str.
	* dwarf2read.c: Include cmath, locale, set, list.
	(INDEX_SUFFIX): Rename to ...
	(INDEX4_SUFFIX): ... here.
	(INDEX5_SUFFIX, DEBUG_STR_SUFFIX): New.
	(data_buf::append_unsigned_leb128, data_buf::empty)
	(data_buf::operator const char *, debug_names, check_dwarf64_offsets): New.
	(write_gdbindex): New from write_psymtabs_to_index code.
	(write_debug_names): New.
	(write_psymtabs_to_index): New parameter is_dwarf5.  Support
	filename_str and out_file_str.  Move code to write_gdbindex, possibly
	call write_debug_names.
	(save_gdb_index_command): New parameter -dwarf-4.
	(_initialize_dwarf2_read): Document the new parameter -dwarf-4.

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

	* gdb.texinfo (Index Files): Document .debug_names and -dwarf-4.
	(Index Section Format): Mention .debug_names.
---
 gdb/contrib/gdb-add-index.sh |   53 ++-
 gdb/doc/gdb.texinfo          |   22 +
 gdb/dwarf2read.c             |  803 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 841 insertions(+), 37 deletions(-)

diff --git a/gdb/contrib/gdb-add-index.sh b/gdb/contrib/gdb-add-index.sh
index 0cd4ce3..02b17f0 100755
--- a/gdb/contrib/gdb-add-index.sh
+++ b/gdb/contrib/gdb-add-index.sh
@@ -37,11 +37,15 @@ fi
 
 dir="${file%/*}"
 test "$dir" = "$file" && dir="."
-index="${file}.gdb-index"
+index4="${file}.gdb-index"
+index5="${file}.debug_names"
+debugstr="${file}.debug_str"
+debugstrmerge="${file}.debug_str.merge"
+debugstrerr="${file}.debug_str.err"
 
-rm -f $index
+rm -f $index4 $index5 $debugstr $debugstrmerge $debugstrerr
 # Ensure intermediate index file is removed when we exit.
-trap "rm -f $index" 0
+trap "rm -f $index4 $index5 $debugstr $debugstrmerge $debugstrerr" 0
 
 $GDB --batch -nx -iex 'set auto-load no' \
     -ex "file $file" -ex "save gdb-index $dir" || {
@@ -57,9 +61,46 @@ $GDB --batch -nx -iex 'set auto-load no' \
 # already stripped binary, it's a no-op.
 status=0
 
-if test -f "$index"; then
-    $OBJCOPY --add-section .gdb_index="$index" \
-	--set-section-flags .gdb_index=readonly "$file" "$file"
+if test -f "$index4" -a -f "$index5"; then
+    echo "$myname: Both index types were created for $file" 1>&2
+    status=1
+elif test -f "$index4" -o -f "$index5"; then
+    if test -f "$index4"; then
+	index="$index4"
+	section=".gdb_index"
+    else
+	index="$index5"
+	section=".debug_names"
+    fi
+    debugstradd=false
+    debugstrupdate=false
+    if test -s "$debugstr"; then
+	if ! $OBJCOPY --dump-section .debug_str="$debugstrmerge" "$file" /dev/null \
+		 2>$debugstrerr; then
+	    cat >&2 $debugstrerr
+	    exit 1
+	fi
+	if grep -q "can't dump section '.debug_str' - it does not exist" \
+		  $debugstrerr; then
+	    debugstradd=true
+	else
+	    debugstrupdate=true
+	    cat >&2 $debugstrerr
+	fi
+	cat "$debugstr" >>"$debugstrmerge"
+    fi
+
+    $OBJCOPY --add-section $section="$index" \
+	--set-section-flags $section=readonly \
+	$(if $debugstradd; then \
+	      echo --add-section .debug_str="$debugstrmerge"; \
+	      echo --set-section-flags .debug_str=readonly; \
+	  fi; \
+	  if $debugstrupdate; then \
+	      echo --update-section .debug_str="$debugstrmerge"; \
+	  fi) \
+	"$file" "$file"
+
     status=$?
 else
     echo "$myname: No index was created for $file" 1>&2
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c167a86..573c51b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19244,18 +19244,29 @@ using @command{objcopy}.
 To create an index file, use the @code{save gdb-index} command:
 
 @table @code
-@item save gdb-index @var{directory}
+@item save gdb-index [-dwarf-4] @var{directory}
 @kindex save gdb-index
 Create an index file for each symbol file currently known by
 @value{GDBN}.  Each file is named after its corresponding symbol file,
-with @samp{.gdb-index} appended, and is written into the given
-@var{directory}.
+with @samp{.debug_names} and @samp{.str} (or @samp{.gdb-index}
+from @code{-dwarf-4} option for older index consumers) appended, and is written
+into the given @var{directory}.
 @end table
 
 Once you have created an index file you can merge it into your symbol
 file, here named @file{symfile}, using @command{objcopy}:
 
 @smallexample
+$ objcopy --dump-section .debug_str=symfile.str.new symfile
+$ cat symfile.str >>symfile.str.new
+$ objcopy --add-section .debug_names=symfile.gdb-index \
+    --set-section-flags .debug_names=readonly \
+    --update-section .debug_str=symfile.str.new symfile symfile
+@end smallexample
+
+Or for @code{-dwarf-4}:
+
+@smallexample
 $ objcopy --add-section .gdb_index=symfile.gdb-index \
     --set-section-flags .gdb_index=readonly symfile symfile
 @end smallexample
@@ -41702,7 +41713,10 @@ of blocks.
 @cindex index section format
 
 This section documents the index section that is created by @code{save
-gdb-index} (@pxref{Index Files}).  The index section is
+gdb-index -dwarf-4} (@pxref{Index Files}).  Currently preferred section is
+@code{.debug_names} as produced by the default @code{save gdb-index} command.
+@code{.debug_names} section is documented in official @code{DWARF-5}
+specification outside of this @value{GDBN} manual.  The index section is
 DWARF-specific; some knowledge of DWARF is assumed in this
 description.
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index abe14b2..2b7990f 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -80,6 +80,10 @@
 #include <algorithm>
 #include <unordered_set>
 #include <unordered_map>
+#include <cmath>
+#include <locale>
+#include <set>
+#include <forward_list>
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -2183,7 +2187,9 @@ attr_value_as_address (struct attribute *attr)
 }
 
 /* The suffix for an index file.  */
-#define INDEX_SUFFIX ".gdb-index"
+#define INDEX4_SUFFIX ".gdb-index"
+#define INDEX5_SUFFIX ".debug_names"
+#define DEBUG_STR_SUFFIX ".debug_str"
 
 /* Try to locate the sections we need for DWARF 2 debugging
    information and return true if we have enough to do something.
@@ -23217,6 +23223,21 @@ public:
     std::copy (cstr, cstr + size, grow (size));
   }
 
+  /* Store INPUT as ULEB128 to the end of buffer.  */
+  void append_unsigned_leb128 (ULONGEST input)
+  {
+    for (;;)
+      {
+	gdb_byte output (input & 0x7f);
+	input >>= 7;
+	if (input)
+	  output |= 0x80;
+	append_data (output);
+	if (!input)
+	  break;
+      }
+  }
+
   /* Accept a host-format integer in VAL and append it to the buffer
      as a target-format integer which is LEN bytes long.  */
   void append_uint (size_t len, bfd_endian byte_order, ULONGEST val)
@@ -23230,6 +23251,12 @@ public:
     return m_vec.size ();
   }
 
+  /* Return true iff the buffer has size zero.  */
+  bool empty () const
+  {
+    return m_vec.empty ();
+  }
+
   /* Write the buffer to FILE.  */
   void file_write (FILE *file) const
   {
@@ -23383,6 +23410,12 @@ public:
     return strcmp (m_cstr, other.m_cstr) == 0;
   }
 
+  /* Returned string is only a reference with lifetime of this object.  */
+  operator const char * () const
+  {
+    return m_cstr;
+  }
+
 private:
   friend class c_str_view_hasher;
   const char *const m_cstr;
@@ -23751,34 +23784,572 @@ private:
   FILE *m_file;
 };
 
-/* Create an index file for OBJFILE in the directory DIR.  */
-
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+/* DWARF-5 .debug_names builder.  */
+class debug_names
 {
-  if (dwarf2_per_objfile->using_index)
-    error (_("Cannot use an index to create the index"));
+public:
+  debug_names (bool is_dwarf64, bfd_endian dwarf5_byte_order_)
+  : m_dwarf5_byte_order (dwarf5_byte_order_), m_dwarf32 (dwarf5_byte_order_),
+  m_dwarf64 (dwarf5_byte_order_),
+  m_dwarf (is_dwarf64 ? static_cast<dwarf &> (m_dwarf64)
+		      : static_cast<dwarf &> (m_dwarf32)),
+  m_name_table_string_offs (m_dwarf.name_table_string_offs),
+  m_name_table_entry_offs (m_dwarf.name_table_entry_offs)
+  {
+  }
 
-  if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
-    error (_("Cannot make an index when the file has multiple .debug_types sections"));
+  /* Insert one symbol.  */
+  void insert (const partial_symbol *psym, int cu_index, bool is_static)
+  {
+    const int dwarf_tag (psymbol_tag (psym));
+    if (!dwarf_tag)
+      return;
+    const char *const name (SYMBOL_SEARCH_NAME (psym));
+    const auto insertpair (m_name_to_value_set.emplace (c_str_view (name),
+						    std::set<symbol_value> ()));
+    std::set<symbol_value> &value_set (insertpair.first->second);
+    value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static));
+  }
 
-  if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
-    return;
+  /* Build all the tables.  All symbols must be already inserted.
+     This function does not call file_write, caller has to do it
+     afterwards.  */
+  void build ()
+  {
+    /* Verify the build method has not be called twice.  */
+    gdb_assert (m_abbrev_table.empty ());
+    const size_t name_count (m_name_to_value_set.size ());
+    m_bucket_table.resize
+		     (std::pow (2, std::ceil (std::log2 (name_count * 4 / 3))));
+    m_hash_table.reserve (name_count);
+    m_name_table_string_offs.reserve (name_count);
+    m_name_table_entry_offs.reserve (name_count);
+
+    /* Map each hash of symbol to its name and value.  */
+    class hash_it_pair
+    {
+    public:
+      uint32_t hash;
+      decltype (m_name_to_value_set)::const_iterator it;
+    };
+    std::vector<std::forward_list<hash_it_pair>> bucket_hash;
+    bucket_hash.resize (m_bucket_table.size ());
+    for (decltype (m_name_to_value_set)::const_iterator it =
+						  m_name_to_value_set.cbegin ();
+	 it != m_name_to_value_set.cend (); ++it)
+      {
+	const char *const name (it->first);
+	const unsigned char *const nameuc
+			       (reinterpret_cast<const unsigned char *> (name));
+	const uint32_t hash (djb_hash (nameuc));
+	hash_it_pair hashitpair;
+	hashitpair.hash = hash;
+	hashitpair.it = it;
+	bucket_hash[hash % bucket_hash.size()].push_front
+						       (std::move (hashitpair));
+      }
+    for (size_t bucket_ix = 0; bucket_ix < bucket_hash.size (); ++bucket_ix)
+      {
+	const std::forward_list<hash_it_pair> &hashitlist
+						       (bucket_hash[bucket_ix]);
+	if (hashitlist.empty ())
+	  continue;
+	uint32_t &bucket_slot (m_bucket_table[bucket_ix]);
+	/* The hashes array is indexed starting at 1.  */
+	store_unsigned_integer (reinterpret_cast<gdb_byte *> (&bucket_slot),
+				sizeof (bucket_slot), m_dwarf5_byte_order,
+				m_hash_table.size () + 1);
+	for (const hash_it_pair &hashitpair : hashitlist)
+	  {
+	    m_hash_table.push_back (0);
+	    store_unsigned_integer (reinterpret_cast<gdb_byte *>
+							(&m_hash_table.back ()),
+				    sizeof (m_hash_table.back ()),
+				    m_dwarf5_byte_order, hashitpair.hash);
+	    const c_str_view &name (hashitpair.it->first);
+	    const std::set<symbol_value> &value_set (hashitpair.it->second);
+	    m_name_table_string_offs.push_back_reorder
+					       (m_debugstrlookup.lookup (name));
+	    m_name_table_entry_offs.push_back_reorder (m_entry_pool.size ());
+	    gdb_assert (!value_set.empty ());
+	    for (const symbol_value &value : value_set)
+	      {
+		int &idx (m_indexkey_to_idx[index_key (value.dwarf_tag,
+						       value.is_static)]);
+		if (!idx) {
+		  idx = m_idx_next++;
+		  m_abbrev_table.append_unsigned_leb128 (idx);
+		  m_abbrev_table.append_unsigned_leb128 (value.dwarf_tag);
+		  m_abbrev_table.append_unsigned_leb128 (DW_IDX_compile_unit);
+		  m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+		  m_abbrev_table.append_unsigned_leb128 (value.is_static
+							 ? DW_IDX_GNU_static
+							 : DW_IDX_GNU_external);
+		  m_abbrev_table.append_unsigned_leb128 (DW_FORM_flag_present);
+
+		  /* Terminate attributes list.  */
+		  m_abbrev_table.append_unsigned_leb128 (0);
+		  m_abbrev_table.append_unsigned_leb128 (0);
+		}
 
-  struct stat st;
-  if (stat (objfile_name (objfile), &st) < 0)
-    perror_with_name (objfile_name (objfile));
+		m_entry_pool.append_unsigned_leb128 (idx);
+		m_entry_pool.append_unsigned_leb128 (value.cu_index);
+	      }
 
-  std::string filename (std::string (dir) + SLASH_STRING
-			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+	    /* Terminate the list of CUs.  */
+	    m_entry_pool.append_unsigned_leb128 (0);
+	  }
+      }
+    gdb_assert (m_hash_table.size () == name_count);
 
-  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
-  if (!out_file)
-    error (_("Can't open `%s' for writing"), filename.c_str ());
+    /* Terminate tags list.  */
+    m_abbrev_table.append_unsigned_leb128 (0);
+  }
 
-  file_closer close_out_file (out_file);
-  gdb::unlinker unlink_file (filename.c_str ());
+  /* Return .debug_names bucket count.
+     It must be called only after calling build method.  */
+  uint32_t bucket_count () const
+  {
+    /* Verify the build method has been already called.  */
+    gdb_assert (!m_abbrev_table.empty ());
+    const uint32_t retval (m_bucket_table.size ());
+
+    /* Check for overflow; to use boost::numeric_cast.  */
+    gdb_assert (retval == m_bucket_table.size ());
+    return retval;
+  }
+
+  /* Return .debug_names names count.
+     It must be called only after calling build method.  */
+  uint32_t name_count () const
+  {
+    /* Verify the build method has been already called.  */
+    gdb_assert (!m_abbrev_table.empty ());
+    const uint32_t retval (m_hash_table.size ());
+
+    /* Check for overflow; to use boost::numeric_cast.  */
+    gdb_assert (retval == m_hash_table.size ());
+    return retval;
+  }
+
+  /* Return number of bytes of .debug_names abbreviation table.
+     It must be called only after calling build method.  */
+  uint32_t abbrev_table_bytes () const
+  {
+    gdb_assert (!m_abbrev_table.empty ());
+    return m_abbrev_table.size ();
+  }
+
+  /* Recurse into all "included" dependencies and store their symbols as
+     if they appeared in this psymtab.  */
+  void recursively_write_psymbols (struct objfile *objfile,
+				   struct partial_symtab *psymtab,
+				   std::unordered_set<partial_symbol *> &psyms_seen,
+				   int cu_index)
+  {
+    int i;
+
+    for (i = 0; i < psymtab->number_of_dependencies; ++i)
+      if (psymtab->dependencies[i]->user != NULL)
+	recursively_write_psymbols (objfile, psymtab->dependencies[i],
+				    psyms_seen, cu_index);
+
+    write_psymbols (psyms_seen,
+		    objfile->global_psymbols.list + psymtab->globals_offset,
+		    psymtab->n_global_syms, cu_index, false);
+    write_psymbols (psyms_seen,
+		    objfile->static_psymbols.list + psymtab->statics_offset,
+		    psymtab->n_static_syms, cu_index, true);
+  }
+
+  /* Return number of bytes the .debug_names section will have.
+     It must be called only after calling build method.  */
+  size_t bytes () const
+  {
+    /* Verify the build method has been already called.  */
+    gdb_assert (!m_abbrev_table.empty ());
+    size_t expected_bytes (0);
+    expected_bytes += m_bucket_table.size () * sizeof (m_bucket_table[0]);
+    expected_bytes += m_hash_table.size () * sizeof (m_hash_table[0]);
+    expected_bytes += m_name_table_string_offs.bytes ();
+    expected_bytes += m_name_table_entry_offs.bytes ();
+    expected_bytes += m_abbrev_table.size ();
+    expected_bytes += m_entry_pool.size ();
+    return expected_bytes;
+  }
+
+  /* Write .debug_names to FILE and .debug_str addition to FILE_STR.
+     It must be called only after calling build method.  */
+  void file_write (FILE *file, FILE *file_str) const
+  {
+    /* Verify the build method has been already called.  */
+    gdb_assert (!m_abbrev_table.empty ());
+    if (::fwrite (m_bucket_table.data (), sizeof (m_bucket_table[0]),
+		  m_bucket_table.size (), file)
+	!= m_bucket_table.size ())
+      error (_("couldn't write data to file"));
+    if (::fwrite (m_hash_table.data (), sizeof (m_hash_table[0]),
+		  m_hash_table.size (), file)
+	!= m_hash_table.size ())
+      error (_("couldn't write data to file"));
+    m_name_table_string_offs.file_write (file);
+    m_name_table_entry_offs.file_write (file);
+    m_abbrev_table.file_write (file);
+    m_entry_pool.file_write (file);
+    m_debugstrlookup.file_write (file_str);
+  }
+
+private:
+
+  /* Storage for symbol names mapping them to their .debug_str section
+     offsets.  */
+  class debug_str_lookup
+  {
+  public:
+
+    /* Object costructor to be called for current DWARF2_PER_OBJFILE.
+       All .debug_str section strings are automatically stored.  */
+    debug_str_lookup () : m_abfd (dwarf2_per_objfile->objfile->obfd)
+    {
+      dwarf2_read_section (dwarf2_per_objfile->objfile,
+			   &dwarf2_per_objfile->str);
+      if (dwarf2_per_objfile->str.buffer == NULL)
+	return;
+      for (const gdb_byte *data = dwarf2_per_objfile->str.buffer;
+	   data < (dwarf2_per_objfile->str.buffer
+		   + dwarf2_per_objfile->str.size);)
+	{
+	  const char *const s (reinterpret_cast<const char *> (data));
+	  const auto insertpair
+		  (m_str_table.emplace (c_str_view (s),
+					data - dwarf2_per_objfile->str.buffer));
+	  if (!insertpair.second)
+	    complaint (&symfile_complaints,
+		       _("Duplicate string \"%s\" in "
+			 ".debug_str section [in module %s]"),
+		       s, bfd_get_filename (m_abfd));
+	  data += strlen (s) + 1;
+	}
+    }
+
+    /* Return offset of symbol name S in .debug_str section.  Add such
+       symbol to the section end if it does not exist there yet.  */
+    size_t lookup (const char *s)
+    {
+      const auto it (m_str_table.find (c_str_view (s)));
+      if (it != m_str_table.end ())
+	return it->second;
+      const size_t offset (dwarf2_per_objfile->str.size
+			   + m_str_add_buf.size ());
+      m_str_table.emplace (c_str_view (s), offset);
+      m_str_add_buf.append_cstr0 (s);
+      return offset;
+    }
+
+    /* Write appended end of .debug_str section to FILE.  */
+    void file_write (FILE *file) const
+    {
+      m_str_add_buf.file_write (file);
+    }
+
+  private:
+    std::unordered_map<c_str_view, size_t, c_str_view_hasher> m_str_table;
+    bfd *const m_abfd;
+
+    /* Data to add at the end of .debug_str for new needed symbol names.  */
+    data_buf m_str_add_buf;
+  };
+
+  /* Container to map used DWARF tags to their .debug_names abbreviation
+     tags.  */
+  class index_key
+  {
+  public:
+    index_key (int dwarf_tag_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), is_static (is_static_)
+    {
+    }
+    bool
+    operator == (const index_key &other) const
+    {
+      return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+    }
+    const int dwarf_tag;
+    const bool is_static;
+  };
+
+  /* Provide std::unordered_map::hasher for index_key.  */
+  class index_key_hasher
+  {
+  public:
+    size_t
+    operator () (const index_key &key) const
+    {
+      return (std::hash<int>() (key.dwarf_tag) << 1) | key.is_static;
+    }
+  };
+
+  /* Parameters of one symbol entry.  */
+  class symbol_value
+  {
+  public:
+    const int dwarf_tag, cu_index;
+    const bool is_static;
+    symbol_value (int dwarf_tag_, int cu_index_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+    {
+    }
+    bool
+    operator < (const symbol_value &other) const
+    {
+#define X(n) \
+  do \
+    { \
+      if (n < other.n) \
+	return true; \
+      if (n > other.n) \
+	return false; \
+    } \
+  while (0)
+      X (dwarf_tag);
+      X (is_static);
+      X (cu_index);
+#undef X
+      return false;
+    }
+  };
+
+  /* Abstract base class to unify DWARF-32 and DWARF-64 name table output.  */
+  class offset_vec
+  {
+  protected:
+    const bfd_endian dwarf5_byte_order;
+  public:
+    offset_vec (bfd_endian dwarf5_byte_order_)
+    : dwarf5_byte_order (dwarf5_byte_order_)
+    {
+    }
+
+    /* Call std::vector::reserve for NELEM elements.  */
+    virtual void reserve (size_t nelem) = 0;
+
+    /* Call std::vector::push_back with store_unsigned_integer byte
+       reordering for ELEM.  */
+    virtual void push_back_reorder (size_t elem) = 0;
+
+    /* Return expected output size in bytes.  */
+    virtual size_t bytes () const = 0;
+
+    /* Write name table to FILE.  */
+    virtual void file_write (FILE *file) const = 0;
+  };
+  
+  /* Template to unify DWARF-32 and DWARF-64 output.  */
+  template<class OffsetSize> class offset_vec_tmpl : public offset_vec
+  {
+  public:
+    offset_vec_tmpl (bfd_endian dwarf5_byte_order_)
+    : offset_vec (dwarf5_byte_order_)
+    {
+    }
+
+    /* Implement offset_vec::reserve.  */
+    virtual void
+    reserve (size_t nelem) override
+    {
+      m_vec.reserve (nelem);
+    }
+
+    /* Implement offset_vec::push_back_reorder.  */
+    virtual void
+    push_back_reorder (size_t elem) override
+    {
+      m_vec.push_back (elem);
+      /* Check for overflow.  */
+      gdb_assert (m_vec.back () == elem);
+      store_unsigned_integer (reinterpret_cast<gdb_byte *> (&m_vec.back ()),
+			      sizeof (m_vec.back ()), dwarf5_byte_order, elem);
+    }
+
+    /* Implement offset_vec::bytes.  */
+    virtual size_t
+    bytes () const override
+    {
+      return m_vec.size () * sizeof (m_vec[0]);
+    }
+
+    /* Implement offset_vec::file_write.  */
+    virtual void
+    file_write (FILE *file) const override
+    {
+      if (::fwrite (m_vec.data (), sizeof (m_vec[0]), m_vec.size (), file)
+	  != m_vec.size ())
+	error (_("couldn't write data to file"));
+    }
+
+  private:
+    std::vector<OffsetSize> m_vec;
+  };
+
+  /* Base class to unify DWARF-32 and DWARF-64 .debug_names output
+     respecting name table width.  */
+  class dwarf
+  {
+  public:
+    offset_vec &name_table_string_offs, &name_table_entry_offs;
+    dwarf (offset_vec &name_table_string_offs_,
+	   offset_vec &name_table_entry_offs_)
+    : name_table_string_offs (name_table_string_offs_),
+    name_table_entry_offs (name_table_entry_offs_)
+    {
+    }
+  };
+
+  /* Template to unify DWARF-32 and DWARF-64 .debug_names output
+     respecting name table width.  */
+  template<class OffsetSize> class dwarf_tmpl : public dwarf
+  {
+  public:
+    dwarf_tmpl (bfd_endian dwarf5_byte_order_)
+    : dwarf (m_name_table_string_offs, m_name_table_entry_offs),
+    m_name_table_string_offs (dwarf5_byte_order_),
+    m_name_table_entry_offs (dwarf5_byte_order_)
+    {
+    }
+  private:
+    offset_vec_tmpl<OffsetSize> m_name_table_string_offs,
+				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.  */
+  static int psymbol_tag (const struct partial_symbol *psym)
+  {
+    domain_enum domain = PSYMBOL_DOMAIN (psym);
+    enum address_class aclass = PSYMBOL_CLASS (psym);
+
+    switch (domain)
+      {
+      case VAR_DOMAIN:
+	switch (aclass)
+	  {
+	  case LOC_BLOCK:
+	    return DW_TAG_subprogram;
+	  case LOC_TYPEDEF:
+	    return DW_TAG_typedef;
+	  case LOC_COMPUTED:
+	  case LOC_CONST_BYTES:
+	  case LOC_OPTIMIZED_OUT:
+	  case LOC_STATIC:
+	    return DW_TAG_variable;
+	  case LOC_CONST:
+	    /* Note: It's currently impossible to recognize psyms as enum values
+	       short of reading the type info.  For now punt.  */
+	    return DW_TAG_variable;
+	  default:
+	    /* There are other LOC_FOO values that one might want to classify
+	       as variables, but dwarf2read.c doesn't currently use them.  */
+	    return DW_TAG_variable;
+	  }
+      case STRUCT_DOMAIN:
+	return DW_TAG_structure_type;
+      default:
+	return 0;
+      }
+  }
+
+  /* Call insert for all partial symbols and mark them in PSYMS_SEEN.  */
+  void write_psymbols (std::unordered_set<partial_symbol *> &psyms_seen,
+		       struct partial_symbol **psymp, int count, int cu_index,
+		       bool is_static)
+  {
+    for (; count-- > 0; ++psymp)
+      {
+	struct partial_symbol *psym = *psymp;
+
+	if (SYMBOL_LANGUAGE (psym) == language_ada)
+	  error (_("Ada is not currently supported by the index"));
+
+	/* Only add a given psymbol once.  */
+	if (psyms_seen.insert (psym).second)
+	  insert (psym, cu_index, is_static);
+      }
+  }
+
+  /* Store value of each symbol.  */
+  std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
+							    m_name_to_value_set;
+
+  /* Tables of DWARF-5 .debug_names.  They are in object file byte order.  */
+  std::vector<uint32_t> m_bucket_table;
+  std::vector<uint32_t> m_hash_table;
 
+  const bfd_endian m_dwarf5_byte_order;
+  dwarf_tmpl<uint32_t> m_dwarf32;
+  dwarf_tmpl<uint64_t> m_dwarf64;
+  dwarf &m_dwarf;
+  offset_vec &m_name_table_string_offs, &m_name_table_entry_offs;
+  debug_str_lookup m_debugstrlookup;
+
+  /* Map each used .debug_names abbreviation tag parameters to its index
+     value.  */
+  std::unordered_map<index_key, int, index_key_hasher> m_indexkey_to_idx;
+
+  /* Next unused .debug_names abbreviation tag for m_indexkey_to_idx.  */
+  int m_idx_next = 1;
+
+  /* .debug_names abbreviation table.  */
+  data_buf m_abbrev_table;
+
+  /* .debug_names entry pool.  */
+  data_buf m_entry_pool;
+};
+
+/* Return iff any of the needed offsets does not fit into 32-bit
+   .debug_names section.  */
+
+static bool
+check_dwarf64_offsets ()
+{
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      const dwarf2_per_cu_data &per_cu (*dwarf2_per_objfile->all_comp_units[i]);
+
+      if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+	return true;
+    }
+  for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+    {
+      const signatured_type &sigtype (*dwarf2_per_objfile->all_type_units[i]);
+      const dwarf2_per_cu_data &per_cu (sigtype.per_cu);
+
+      if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+	return true;
+    }
+  return false;
+}
+
+/* Write new .gdb_index section for OBJFILE into OUT_FILE.
+   OUT_FILE_STR is unused.
+   Return how many bytes were expected to be written into OUT_FILE.  */
+
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
   mapped_symtab symtab;
   data_buf cu_list;
 
@@ -23896,8 +24467,172 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   symtab_vec.file_write (out_file);
   constant_pool.file_write (out_file);
 
-  /* We want to keep the file.  */
+  return total_len;
+}
+
+/* Write new .debug_names section for OBJFILE into OUT_FILE,
+   write needed addition to .debug_str section to OUT_FILE_STR.
+   Return how many bytes were expected to be written into OUT_FILE.  */
+
+static size_t
+write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
+  const bool dwarf5_is_dwarf64 (check_dwarf64_offsets ());
+  const int dwarf5_offset_size (dwarf5_is_dwarf64 ? 8 : 4);
+  const enum bfd_endian dwarf5_byte_order
+			      (gdbarch_byte_order (get_objfile_arch (objfile)));
+
+  /* The CU list is already sorted, so we don't need to do additional
+     work here.  Also, the debug_types entries do not appear in
+     all_comp_units, but only in their own hash table.  */
+  data_buf cu_list;
+  debug_names nametable (dwarf5_is_dwarf64, dwarf5_byte_order);
+  std::unordered_set<partial_symbol *> psyms_seen;
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      const dwarf2_per_cu_data *per_cu (dwarf2_per_objfile->all_comp_units[i]);
+      partial_symtab *psymtab = per_cu->v.psymtab;
+
+      /* CU of a shared file from 'dwz -m' may be unused by this main file.
+	 It may be referenced from a local scope but in such case it does
+	 not need to be present in .gdb_index.  */
+      if (psymtab == NULL)
+	continue;
+
+      if (psymtab->user == NULL)
+	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
+
+      cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+			   to_underlying (per_cu->sect_off));
+    }
+  nametable.build ();
+
+  /* No addr_vec - DWARF-5 uses .debug_aranges genereated by GCC.  */
+
+  data_buf types_cu_list;
+  for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+    {
+      const signatured_type &sigtype
+				 (*dwarf2_per_objfile->all_type_units[i]);
+      const dwarf2_per_cu_data &per_cu (sigtype.per_cu);
+
+      types_cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+				 to_underlying (per_cu.sect_off));
+    }
+
+  const gdb_byte augmentation[] = { 'G', 'D', 'B', 0 };
+  const offset_type bytes_of_header ((dwarf5_is_dwarf64 ? 12 : 4)
+				     + 2 + 2 + 7 * 4 + sizeof (augmentation));
+  size_t expected_bytes (0);
+  expected_bytes += bytes_of_header;
+  expected_bytes += cu_list.size ();
+  expected_bytes += types_cu_list.size ();
+  expected_bytes += nametable.bytes ();
+  data_buf header;
+
+  if (!dwarf5_is_dwarf64)
+    {
+      const uint64_t size64 (expected_bytes - 4);
+      gdb_assert (size64 < 0xfffffff0);
+      header.append_uint (4, dwarf5_byte_order, size64);
+    }
+  else
+    {
+      header.append_uint (4, dwarf5_byte_order, 0xffffffff);
+      header.append_uint (8, dwarf5_byte_order, expected_bytes - 12);
+    }
+
+  /* The version number.  */
+  header.append_uint (2, dwarf5_byte_order, 5);
+
+  /* Padding.  */
+  header.append_uint (2, dwarf5_byte_order, 0);
+
+  /* comp_unit_count - The number of CUs in the CU list.  */
+  header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_comp_units);
+
+  /* local_type_unit_count - The number of TUs
+     in the local TU list.  */
+  header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_type_units);
+
+  /* foreign_type_unit_count - The number of TUs
+     in the foreign TU list.  */
+  header.append_uint (4, dwarf5_byte_order, 0);
+
+  /* bucket_count - The number of hash buckets
+     in the hash lookup table.  */
+  header.append_uint (4, dwarf5_byte_order, nametable.bucket_count ());
+
+  /* name_count - The number of unique names in the index.  */
+  header.append_uint (4, dwarf5_byte_order, nametable.name_count ());
+
+  /* abbrev_table_size - The size in bytes
+     of the abbreviations table.  */
+  header.append_uint (4, dwarf5_byte_order, nametable.abbrev_table_bytes ());
+
+  /* augmentation_string_size - The size in bytes of the augmentation
+     string.  This value is rounded up to a multiple of 4.  */
+  static_assert (sizeof (augmentation) % 4 == 0);
+  header.append_uint (4, dwarf5_byte_order, sizeof (augmentation));
+  header.append_data (augmentation);
+
+  gdb_assert (header.size () == bytes_of_header);
+
+  header.file_write (out_file);
+  cu_list.file_write (out_file);
+  types_cu_list.file_write (out_file);
+  nametable.file_write (out_file, out_file_str);
+
+  return expected_bytes;
+}
+
+/* Create an index file for OBJFILE in the directory DIR.  */
+
+static void
+write_psymtabs_to_index (struct objfile *objfile, const char *dir, bool is_dwarf5)
+{
+  if (dwarf2_per_objfile->using_index)
+    error (_("Cannot use an index to create the index"));
+
+  if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
+    error (_("Cannot make an index when the file has multiple .debug_types sections"));
+
+  if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
+    return;
+
+  struct stat st;
+  if (stat (objfile_name (objfile), &st) < 0)
+    perror_with_name (objfile_name (objfile));
+
+  std::string filename (std::string (dir) + SLASH_STRING
+			+ lbasename (objfile_name (objfile))
+			+ (is_dwarf5 ? INDEX5_SUFFIX : INDEX4_SUFFIX));
+  std::string filename_str (std::string (dir) + SLASH_STRING
+			    + lbasename (objfile_name (objfile))
+			    + DEBUG_STR_SUFFIX);
+
+  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
+  if (!out_file)
+    error (_("Can't open `%s' for writing"), filename.c_str ());
+  file_closer close_out_file (out_file);
+  gdb::unlinker unlink_file (filename.c_str ());
+
+  FILE *out_file_str = gdb_fopen_cloexec (filename_str.c_str (), "wb");
+  if (!out_file_str)
+    error (_("Can't open `%s' for writing"), filename_str.c_str ());
+  file_closer close_out_file_str (out_file_str);
+  gdb::unlinker unlink_file_str (filename_str.c_str ());
+
+  const size_t total_len ((is_dwarf5 ? write_debug_names : write_gdbindex)
+					 (objfile, out_file, out_file_str));
+  const auto out_file_size (ftell (out_file));
+  if (out_file_size == -1)
+    error (_("Can't get `%s' size"), filename.c_str ());
+  gdb_assert (out_file_size == total_len);
+
+  /* We want to keep the files.  */
   unlink_file.keep ();
+  unlink_file_str.keep ();
 }
 
 /* Implementation of the `save gdb-index' command.
@@ -23906,12 +24641,26 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
    GDB manual.  Any changes here must be documented there.  */
 
 static void
-save_gdb_index_command (char *arg, int from_tty)
+save_gdb_index_command (char *arg_entry, int from_tty)
 {
   struct objfile *objfile;
+  const char dwarf4space[] = "-dwarf-4 ";
+  bool is_dwarf5 (true);
+  const char *arg = arg_entry;
+
+  if (!arg)
+    arg = "";
+
+  arg = skip_spaces_const (arg);
+  if (strncmp (arg, dwarf4space, strlen (dwarf4space)) == 0)
+    {
+      is_dwarf5 = false;
+      arg += strlen (dwarf4space);
+      arg = skip_spaces_const (arg);
+    }
 
-  if (!arg || !*arg)
-    error (_("usage: save gdb-index DIRECTORY"));
+  if (!*arg)
+    error (_("usage: save gdb-index [-dwarf-4] DIRECTORY"));
 
   ALL_OBJFILES (objfile)
   {
@@ -23929,7 +24678,7 @@ save_gdb_index_command (char *arg, int from_tty)
 
 	TRY
 	  {
-	    write_psymtabs_to_index (objfile, arg);
+	    write_psymtabs_to_index (objfile, arg, is_dwarf5);
 	  }
 	CATCH (except, RETURN_MASK_ERROR)
 	  {
@@ -24063,7 +24812,7 @@ Warning: This option must be enabled before gdb reads the file."),
   c = add_cmd ("gdb-index", class_files, save_gdb_index_command,
 	       _("\
 Save a gdb-index file.\n\
-Usage: save gdb-index DIRECTORY"),
+Usage: save gdb-index [-dwarf-4] DIRECTORY"),
 	       &save_cmdlist);
   set_cmd_completer (c, filename_completer);
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
@ 2017-06-18 19:32 ` Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

Hi,

dwarf2_initialize_objfile was returning boolean whether it is psymtabs or
.gdb_index while now it needs to return also whether it is .debug_names.


Jan


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

	* defs.h (elf_sym_fns_lazy_psyms, elf_sym_fns_gdb_index): Move here
	declarations from elfread.c.
	(dwarf2_initialize_objfile): Change return value.
	* elfread.c (elf_sym_fns_lazy_psyms, elf_sym_fns_gdb_index): Move these
	declarations to defs.h.
	(elf_symfile_read): Adjust dwarf2_initialize_objfile caller.
	* symfile.h (dwarf2_initialize_objfile): Change return type.
---
 gdb/defs.h       |    5 +++++
 gdb/dwarf2read.c |    8 ++++----
 gdb/elfread.c    |   11 +++--------
 gdb/symfile.h    |    2 +-
 4 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/gdb/defs.h b/gdb/defs.h
index 55d16d1..516c234 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -758,6 +758,11 @@ extern int (*deprecated_ui_load_progress_hook) (const char *section,
 extern void initialize_progspace (void);
 extern void initialize_inferiors (void);
 
+/* From elfread.c */
+
+extern const struct sym_fns elf_sym_fns_lazy_psyms;
+extern const struct sym_fns elf_sym_fns_gdb_index;
+
 /* * Special block numbers */
 
 enum block_enum
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 2b7990f..763f539 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4356,7 +4356,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
 /* Initialize for reading DWARF for this objfile.  Return 0 if this
    file will use psymtabs, or 1 if using the GNU index.  */
 
-int
+const sym_fns &
 dwarf2_initialize_objfile (struct objfile *objfile)
 {
   /* If we're about to read full symbols, don't bother with the
@@ -4385,13 +4385,13 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       /* Return 1 so that gdb sees the "quick" functions.  However,
 	 these functions will be no-ops because we will have expanded
 	 all symtabs.  */
-      return 1;
+      return elf_sym_fns_gdb_index;
     }
 
   if (dwarf2_read_index (objfile))
-    return 1;
+    return elf_sym_fns_gdb_index;
 
-  return 0;
+  return elf_sym_fns_lazy_psyms;
 }
 
 \f
diff --git a/gdb/elfread.c b/gdb/elfread.c
index fba2026..9ae0432 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -50,10 +50,6 @@
 
 extern void _initialize_elfread (void);
 
-/* Forward declarations.  */
-extern const struct sym_fns elf_sym_fns_gdb_index;
-extern const struct sym_fns elf_sym_fns_lazy_psyms;
-
 /* The struct elfinfo is available only during ELF symbol table and
    psymtab reading.  It is destroyed at the completion of psymtab-reading.
    It's local to elf_symfile_read.  */
@@ -1237,10 +1233,7 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 	 information present in OBJFILE.  If there is such debug info present
 	 never use .gdb_index.  */
 
-      if (!objfile_has_partial_symbols (objfile)
-	  && dwarf2_initialize_objfile (objfile))
-	objfile_set_sym_fns (objfile, &elf_sym_fns_gdb_index);
-      else
+      if (objfile_has_partial_symbols (objfile))
 	{
 	  /* It is ok to do this even if the stabs reader made some
 	     partial symbols, because OBJF_PSYMTABS_READ has not been
@@ -1248,6 +1241,8 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 	     when needed.  */
 	  objfile_set_sym_fns (objfile, &elf_sym_fns_lazy_psyms);
 	}
+      else
+	objfile_set_sym_fns (objfile, &dwarf2_initialize_objfile (objfile));
     }
   /* If the file has its own symbol tables it has no separate debug
      info.  `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to
diff --git a/gdb/symfile.h b/gdb/symfile.h
index bb47fdf..8e51d41 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -625,7 +625,7 @@ extern void dwarf2_get_section_info (struct objfile *,
 				     asection **, const gdb_byte **,
 				     bfd_size_type *);
 
-extern int dwarf2_initialize_objfile (struct objfile *);
+extern const sym_fns &dwarf2_initialize_objfile (struct objfile *);
 extern void dwarf2_build_psymtabs (struct objfile *);
 extern void dwarf2_build_frame_info (struct objfile *);
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
@ 2017-06-18 19:32 ` Jan Kratochvil
  2017-06-18 19:32 ` [PATCH v2 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

Hi,

currently contrib/cc-with-tweaks.sh is calling for its -i option objcopy itself
instead of using contrib/gdb-add-index.sh which does the same.

With DWARF-5 .debug_names the commands are more complicated (as now also
.debug_str needs to be modified) and so I have decided to rather reuse
contrib/gdb-add-index.sh instead of duplicating its code
in contrib/cc-with-tweaks.sh.

The problem is when no index is produced whether contrib/cc-with-tweaks.sh
should fail or not.  As originally contrib/cc-with-tweaks.sh was more quiet
(=successful) than contrib/gdb-add-index.sh and so after this patch the
testsuite runs with an index would "regress".  I have tried to keep the
behavior unchanged.  Some cases still error with:
	Ada is not currently supported by the index
But some cases (such as some trivial gdb.dwarf2/ testcases with no DWARF data
to index) produce no index while the testcases still PASS now instead of:
	-PASS: gdb.arch/i386-bp_permanent.exp: stack pointer value matches
	+gdb compile failed, gdb-add-index.sh: No index was created for /quadgdb/testsuite.unix.-m64/outputs/gdb.arch/i386-bp_permanent/i386-bp_permanent
	+gdb-add-index.sh: [Was there no debuginfo? Was there already an index?]
	+UNTESTED: gdb.arch/i386-bp_permanent.exp: failed to compile


Jan


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

	* contrib/cc-with-tweaks.sh (t, GDB_ADD_INDEX): New variables.
	<$want_index>: Call $GDB_ADD_INDEX.
---
 gdb/contrib/cc-with-tweaks.sh |   40 ++++++++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/gdb/contrib/cc-with-tweaks.sh b/gdb/contrib/cc-with-tweaks.sh
index 7d39c00..c5a8088 100755
--- a/gdb/contrib/cc-with-tweaks.sh
+++ b/gdb/contrib/cc-with-tweaks.sh
@@ -74,6 +74,8 @@ DWP=${DWP:-dwp}
 have_link=unknown
 next_is_output_file=no
 output_file=a.out
+t=/tmp/cc-with-tweaks.$$
+rm -f $t
 
 want_index=false
 want_dwz=false
@@ -93,6 +95,25 @@ while [ $# -gt 0 ]; do
     shift
 done
 
+if [ "$want_index" = true ]; then
+  if [ -z "$GDB_ADD_INDEX" ]
+  then
+      if [ -f ./contrib/gdb-add-index.sh ]
+      then
+	  GDB_ADD_INDEX="./contrib/gdb-add-index.sh"
+      elif [ -f ../contrib/gdb-add-index.sh ]
+      then
+	  GDB_ADD_INDEX="../contrib/gdb-add-index.sh"
+      elif [ -f ../../contrib/gdb-add-index.sh ]
+      then
+	  GDB_ADD_INDEX="../../contrib/gdb-add-index.sh"
+      else
+	  echo "$myname: unable to find usable contrib/gdb-add-index.sh" >&2
+	  exit 1
+      fi
+  fi
+fi
+
 for arg in "$@"
 do
     if [ "$next_is_output_file" = "yes" ]
@@ -152,20 +173,11 @@ if [ "$want_objcopy_compress" = true ]; then
 fi
 
 if [ "$want_index" = true ]; then
-    $GDB --batch-silent -nx -ex "set auto-load no" -ex "file $output_file" -ex "save gdb-index $output_dir"
-    rc=$?
-    [ $rc != 0 ] && exit $rc
-
-    # GDB might not always create an index.  Cope.
-    if [ -f "$index_file" ]
-    then
-	$OBJCOPY --add-section .gdb_index="$index_file" \
-	    --set-section-flags .gdb_index=readonly \
-	    "$output_file" "$output_file"
-	rc=$?
-    else
-	rc=0
-    fi
+    # Filter out these messages which would stop dejagnu testcase run:
+    # echo "$myname: No index was created for $file" 1>&2
+    # echo "$myname: [Was there no debuginfo? Was there already an index?]" 1>&2
+    GDB=$GDB $GDB_ADD_INDEX "$output_file" 2>&1|grep -v "^${GDB_ADD_INDEX##*/}: " >&2
+    rc=${PIPESTATUS[0]}
     [ $rc != 0 ] && exit $rc
 fi
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 5/5] DWARF-5: .debug_names index consumer
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
                   ` (3 preceding siblings ...)
  2017-06-18 19:32 ` [PATCH v2 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
@ 2017-06-18 19:33 ` Jan Kratochvil
  2017-06-19 20:56 ` obsolete: [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:33 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

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(-)

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
 };
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* obsolete: [PATCH v2 0/5] DWARF-5: .debug_names index
  2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
                   ` (4 preceding siblings ...)
  2017-06-18 19:33 ` [PATCH v2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
@ 2017-06-19 20:56 ` Jan Kratochvil
  5 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

[PATCH v3 0/5] DWARF-5: .debug_names index
https://sourceware.org/ml/gdb-patches/2017-06/msg00541.html
Message-ID: <149790572259.20186.14601775821404892582.stgit@host1.jankratochvil.net>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-06-19 20:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-18 19:32 [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
2017-06-18 19:32 ` [PATCH v2 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
2017-06-18 19:33 ` [PATCH v2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
2017-06-19 20:56 ` obsolete: [PATCH v2 0/5] DWARF-5: .debug_names index Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).