public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
@ 2017-06-19 20:55 ` Jan Kratochvil
  2017-06-29 19:40   ` Simon Marchi
  2017-06-19 20:55 ` [PATCH v3 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:55 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] 31+ messages in thread

* [PATCH v3 2/5] DWARF-5: .debug_names index producer
  2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
  2017-06-19 20:55 ` [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
@ 2017-06-19 20:55 ` Jan Kratochvil
  2017-06-20 15:19   ` Eli Zaretskii
  2017-06-19 20:56 ` [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:55 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.
	(file_write, file_write, file_write): New.
	(data_buf::append_unsigned_leb128, data_buf::empty): New.
	(data_buf::file_write): Use ::file_write.
	(data_buf::operator const char *, debug_names, check_dwarf64_offsets):
	New.
	(psyms_seen_size, 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             |  875 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 890 insertions(+), 60 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 2369d4b..fd3dc64 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.
@@ -23196,6 +23202,33 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+   error checking.  */
+
+static void
+file_write (FILE *file, const void *data, size_t size)
+{
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
+}
+
+/* Write the contents of VEC to FILE, with error checking.  */
+
+template<class Elem>
+static void
+file_write (FILE *file, const std::vector<Elem> &vec)
+{
+  file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
+}
+
+/* Write the contents of BUF to FILE, with error checking.  */
+
+static void
+file_write (FILE *file, const gdb::byte_vector &buf)
+{
+  file_write (file, buf.data (), buf.size ());
+}
+
 /* In-memory buffer to prepare data to be written later to a file.  */
 class data_buf
 {
@@ -23217,6 +23250,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,11 +23278,16 @@ 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
   {
-    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
-      error (_("couldn't write data to file"));
+    ::file_write (file, m_vec);
   }
 
 private:
@@ -23383,6 +23436,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,57 +23810,566 @@ 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);
+  }
 
-  /* Order matters here; we want FILE to be closed before FILENAME is
-     unlinked, because on MS-Windows one cannot delete a file that is
-     still open.  (Don't call anything here that might throw until
-     file_closer is created.)  */
-  gdb::unlinker unlink_file (filename.c_str ());
-  file_closer close_out_file (out_file);
+  /* 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 ());
 
-  mapped_symtab symtab;
-  data_buf cu_list;
+    /* Check for overflow; to use boost::numeric_cast.  */
+    gdb_assert (retval == m_bucket_table.size ());
+    return retval;
+  }
 
-  /* While we're scanning CU's create a table that maps a psymtab pointer
-     (which is what addrmap records) to its index (which is what is recorded
-     in the index file).  This will later be needed to write the address
-     table.  */
-  psym_index_map cu_index_htab;
-  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+  /* 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 ());
 
-  /* 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.  */
+    /* 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 ());
+    ::file_write (file, m_bucket_table);
+    ::file_write (file, m_hash_table);
+    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
+    {
+      ::file_write (file, m_vec);
+    }
+
+  private:
+    std::vector<OffsetSize> m_vec;
+  };
 
-  /* The psyms_seen set is potentially going to be largish (~40k
-     elements when indexing a -g3 build of GDB itself).  Estimate the
-     number of elements in order to avoid too many rehashes, which
-     require rebuilding buckets and thus many trips to
-     malloc/free.  */
+  /* 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;
+}
+
+/* The psyms_seen set is potentially going to be largish (~40k
+   elements when indexing a -g3 build of GDB itself).  Estimate the
+   number of elements in order to avoid too many rehashes, which
+   require rebuilding buckets and thus many trips to
+   malloc/free.  */
+
+static size_t
+psyms_seen_size ()
+{
   size_t psyms_count = 0;
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
@@ -23814,7 +24382,31 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
     }
   /* Generating an index for gdb itself shows a ratio of
      TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5.  4 seems like a good bet.  */
-  std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+  return psyms_count / 4;
+}
+
+/* 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;
+
+  /* While we're scanning CU's create a table that maps a psymtab pointer
+     (which is what addrmap records) to its index (which is what is recorded
+     in the index file).  This will later be needed to write the address
+     table.  */
+  psym_index_map cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+
+  /* 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.  */
+
+  std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
@@ -23900,8 +24492,177 @@ 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 (psyms_seen_size ());
+  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 ());
+
+  /* Order matters here; we want FILE to be closed before FILENAME is
+     unlinked, because on MS-Windows one cannot delete a file that is
+     still open.  (Don't call anything here that might throw until
+     file_closer is created.)  */
+  gdb::unlinker unlink_file (filename.c_str ());
+  file_closer close_out_file (out_file);
+
+  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 ());
+  gdb::unlinker unlink_file_str (filename_str.c_str ());
+  file_closer close_out_file_str (out_file_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.
@@ -23910,12 +24671,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)
   {
@@ -23933,7 +24708,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)
 	  {
@@ -24067,7 +24842,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] 31+ messages in thread

* [PATCH v3 0/5] DWARF-5: .debug_names index
@ 2017-06-19 20:55 Jan Kratochvil
  2017-06-19 20:55 ` [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
                   ` (4 more replies)
  0 siblings, 5 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:55 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] 31+ messages in thread

* [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
                   ` (3 preceding siblings ...)
  2017-06-19 20:56 ` [PATCH v3 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
@ 2017-06-19 20:56 ` Jan Kratochvil
  2017-12-08 23:52   ` Pedro Alves
  4 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:56 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 fd3dc64..08f193b 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] 31+ messages in thread

* [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code
  2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
  2017-06-19 20:55 ` [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
  2017-06-19 20:55 ` [PATCH v3 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
@ 2017-06-19 20:56 ` Jan Kratochvil
  2017-12-08 23:53   ` Pedro Alves
  2017-06-19 20:56 ` [PATCH v3 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
  2017-06-19 20:56 ` [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
  4 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:56 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 08f193b..fd518f3 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] 31+ messages in thread

* [PATCH v3 5/5] DWARF-5: .debug_names index consumer
  2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
                   ` (2 preceding siblings ...)
  2017-06-19 20:56 ` [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
@ 2017-06-19 20:56 ` Jan Kratochvil
  2017-06-28 21:21   ` [PATCH v3.1 " Jan Kratochvil
  2017-06-19 20:56 ` [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
  4 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 20:56 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 fd518f3..8c2e3f4 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.
@@ -23907,7 +25024,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;
@@ -24279,19 +25396,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] 31+ messages in thread

* Re: [PATCH v3 2/5] DWARF-5: .debug_names index producer
  2017-06-19 20:55 ` [PATCH v3 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
@ 2017-06-20 15:19   ` Eli Zaretskii
  2017-06-22 18:35     ` [PATCH v3.1 " Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Eli Zaretskii @ 2017-06-20 15:19 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, vleschuk

> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: Victor Leschuk <vleschuk@accesssoftek.com>
> Date: Mon, 19 Jun 2017 22:55:44 +0200
> 
>  @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}.

The file-name extensions are better put in @file.

More importantly, this text is now confusing: what do you mean by
"with @samp{.debug_names} and @samp{.str}"?  Do we produce one file or
two?  If only one, then what determines whether its extension will be
.debug_names or .str?

Once I understand this, I could suggest an alternative wording to
clarify the issue.

>  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

The command should be in @kbd, not @code, as it's something the user
types on the keyboard.

> +@code{.debug_names} as produced by the default @code{save gdb-index} command.
> +@code{.debug_names} section is documented in official @code{DWARF-5}

DWARF-5 should not be in @code.  Maybe in @acronym, or even no markup
at all.

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

I think we should have a short explanation how the -dwarf-4 option
changes the behavior.

Thanks.

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

* [PATCH v3.1 2/5] DWARF-5: .debug_names index producer
  2017-06-20 15:19   ` Eli Zaretskii
@ 2017-06-22 18:35     ` Jan Kratochvil
  2017-06-22 19:18       ` Eli Zaretskii
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-22 18:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, vleschuk

[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]

On Tue, 20 Jun 2017 17:18:31 +0200, Eli Zaretskii wrote:
> The file-name extensions are better put in @file.

Done.


> More importantly, this text is now confusing: what do you mean by
> "with @samp{.debug_names} and @samp{.str}"?  Do we produce one file or
> two?

Two.


> Once I understand this, I could suggest an alternative wording to
> clarify the issue.

Primarily this whole manual section is pointless.  IMO it was already
inappropriate during its initial check-in as the "save gdb-index" is never
going to be executed by GDB user.  GDB users use /usr/bin/gdb-add-index .
But that is now shipped only as gdb/contrib/gdb-add-index.sh .
	FYI: revert gdb-add-index
	https://sourceware.org/ml/gdb-patches/2010-08/msg00127.html
	Message-ID: <m3pqxqco3v.fsf@fleche.redhat.com>

Fedora ships it on its own, also with a man page:
	https://src.fedoraproject.org/cgit/rpms/gdb.git/tree/gdb-gdb-add-index-script.patch


> The command should be in @kbd, not @code, as it's something the user
> types on the keyboard.

Done.


> DWARF-5 should not be in @code.  Maybe in @acronym, or even no markup
> at all.

Done.


> >    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);
> 
> I think we should have a short explanation how the -dwarf-4 option
> changes the behavior.

[-- Attachment #2: Type: message/rfc822, Size: 39145 bytes --]

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] DWARF-5: .debug_names index producer
Date: Thu, 22 Jun 2017 20:18:20 +0200

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.
	(file_write, file_write, file_write): New.
	(data_buf::append_unsigned_leb128, data_buf::empty): New.
	(data_buf::file_write): Use ::file_write.
	(data_buf::operator const char *, debug_names, check_dwarf64_offsets):
	New.
	(psyms_seen_size, 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          |  24 +-
 gdb/dwarf2read.c             | 879 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 895 insertions(+), 61 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..7411ce8 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 @file{.debug_names} and @file{.debug_str} (or @file{.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.debug_str.new symfile
+$ cat symfile.debug_str >>symfile.debug_str.new
+$ objcopy --add-section .debug_names=symfile.gdb-index \
+    --set-section-flags .debug_names=readonly \
+    --update-section .debug_str=symfile.debug_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
@@ -41701,8 +41712,11 @@ of blocks.
 @cindex .gdb_index section format
 @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
+This section documents the index section that is created by @kbd{save
+gdb-index -dwarf-4} (@pxref{Index Files}).  Currently preferred section is
+@code{.debug_names} as produced by the default @kbd{save gdb-index} command.
+@code{.debug_names} section is documented in official 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 2369d4b..79f5c92 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.
@@ -23196,6 +23202,33 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+   error checking.  */
+
+static void
+file_write (FILE *file, const void *data, size_t size)
+{
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
+}
+
+/* Write the contents of VEC to FILE, with error checking.  */
+
+template<class Elem>
+static void
+file_write (FILE *file, const std::vector<Elem> &vec)
+{
+  file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
+}
+
+/* Write the contents of BUF to FILE, with error checking.  */
+
+static void
+file_write (FILE *file, const gdb::byte_vector &buf)
+{
+  file_write (file, buf.data (), buf.size ());
+}
+
 /* In-memory buffer to prepare data to be written later to a file.  */
 class data_buf
 {
@@ -23217,6 +23250,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,11 +23278,16 @@ 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
   {
-    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
-      error (_("couldn't write data to file"));
+    ::file_write (file, m_vec);
   }
 
 private:
@@ -23383,6 +23436,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,57 +23810,566 @@ 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);
+  }
 
-  /* Order matters here; we want FILE to be closed before FILENAME is
-     unlinked, because on MS-Windows one cannot delete a file that is
-     still open.  (Don't call anything here that might throw until
-     file_closer is created.)  */
-  gdb::unlinker unlink_file (filename.c_str ());
-  file_closer close_out_file (out_file);
+  /* 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 ());
 
-  mapped_symtab symtab;
-  data_buf cu_list;
+    /* Check for overflow; to use boost::numeric_cast.  */
+    gdb_assert (retval == m_bucket_table.size ());
+    return retval;
+  }
 
-  /* While we're scanning CU's create a table that maps a psymtab pointer
-     (which is what addrmap records) to its index (which is what is recorded
-     in the index file).  This will later be needed to write the address
-     table.  */
-  psym_index_map cu_index_htab;
-  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+  /* 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 ());
 
-  /* 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.  */
+    /* 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 ());
+    ::file_write (file, m_bucket_table);
+    ::file_write (file, m_hash_table);
+    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
+    {
+      ::file_write (file, m_vec);
+    }
+
+  private:
+    std::vector<OffsetSize> m_vec;
+  };
 
-  /* The psyms_seen set is potentially going to be largish (~40k
-     elements when indexing a -g3 build of GDB itself).  Estimate the
-     number of elements in order to avoid too many rehashes, which
-     require rebuilding buckets and thus many trips to
-     malloc/free.  */
+  /* 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;
+}
+
+/* The psyms_seen set is potentially going to be largish (~40k
+   elements when indexing a -g3 build of GDB itself).  Estimate the
+   number of elements in order to avoid too many rehashes, which
+   require rebuilding buckets and thus many trips to
+   malloc/free.  */
+
+static size_t
+psyms_seen_size ()
+{
   size_t psyms_count = 0;
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
@@ -23814,7 +24382,31 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
     }
   /* Generating an index for gdb itself shows a ratio of
      TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5.  4 seems like a good bet.  */
-  std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+  return psyms_count / 4;
+}
+
+/* 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;
+
+  /* While we're scanning CU's create a table that maps a psymtab pointer
+     (which is what addrmap records) to its index (which is what is recorded
+     in the index file).  This will later be needed to write the address
+     table.  */
+  psym_index_map cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+
+  /* 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.  */
+
+  std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
@@ -23900,8 +24492,177 @@ 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 (psyms_seen_size ());
+  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 ());
+
+  /* Order matters here; we want FILE to be closed before FILENAME is
+     unlinked, because on MS-Windows one cannot delete a file that is
+     still open.  (Don't call anything here that might throw until
+     file_closer is created.)  */
+  gdb::unlinker unlink_file (filename.c_str ());
+  file_closer close_out_file (out_file);
+
+  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 ());
+  gdb::unlinker unlink_file_str (filename_str.c_str ());
+  file_closer close_out_file_str (out_file_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.
@@ -23910,12 +24671,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)
   {
@@ -23933,7 +24708,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)
 	  {
@@ -24067,7 +24842,11 @@ 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\n\
+\n\
+No options create two files with extension .debug_names and .debug_str\n\
+for DWARF-5 .debug_names section.  The -dwarf-4 creates one file with\n\
+.gdb-index extension for pre-DWARF-5 compatible .gdb_index section."),
 	       &save_cmdlist);
   set_cmd_completer (c, filename_completer);
 
-- 
2.9.4

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

* Re: [PATCH v3.1 2/5] DWARF-5: .debug_names index producer
  2017-06-22 18:35     ` [PATCH v3.1 " Jan Kratochvil
@ 2017-06-22 19:18       ` Eli Zaretskii
  2017-06-22 20:03         ` [PATCH v3.2 " Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Eli Zaretskii @ 2017-06-22 19:18 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, vleschuk

> Date: Thu, 22 Jun 2017 20:35:42 +0200
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: gdb-patches@sourceware.org, vleschuk@accesssoftek.com
> 
> -@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 @file{.debug_names} and @file{.debug_str} (or @file{.gdb-index}
> +from @code{-dwarf-4} option for older index consumers) appended, and is written
> +into the given @var{directory}.
>  @end table

Given your explanations, I suggest to reword this:

  Create index files for all symbol files currently known by
  @value{GDBN}.  For each known @var{symbol-file}, this command
  by default creates 2 files: @file{@var{symbol-file}.debug_names}
  and @file{@var{symbol-file}.debug_str}.  If you invoke this
  command with the @option{-dwarf-4} option, it produces a single
  file @file{@var{symbol-file}.gdb-index}.  The files are created
  in the given @var{directory}.

Otherwise, the documentation parts are fine, thanks.

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

* [PATCH v3.2 2/5] DWARF-5: .debug_names index producer
  2017-06-22 19:18       ` Eli Zaretskii
@ 2017-06-22 20:03         ` Jan Kratochvil
  2017-12-08 23:51           ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-22 20:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, vleschuk

[-- Attachment #1: Type: text/plain, Size: 131 bytes --]

On Thu, 22 Jun 2017 21:17:41 +0200, Eli Zaretskii wrote:
> Given your explanations, I suggest to reword this:

Done.


Thanks,
Jan

[-- Attachment #2: Type: message/rfc822, Size: 39372 bytes --]

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] DWARF-5: .debug_names index producer
Date: Thu, 22 Jun 2017 20:18:20 +0200

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.
	(file_write, file_write, file_write): New.
	(data_buf::append_unsigned_leb128, data_buf::empty): New.
	(data_buf::file_write): Use ::file_write.
	(data_buf::operator const char *, debug_names, check_dwarf64_offsets):
	New.
	(psyms_seen_size, 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          |  30 +-
 gdb/dwarf2read.c             | 879 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 899 insertions(+), 63 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..d2057ca 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19244,18 +19244,31 @@ 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}.
+Create index files for all symbol files currently known by
+@value{GDBN}.  For each known @var{symbol-file}, this command
+by default creates 2 files: @file{@var{symbol-file}.debug_names}
+and @file{@var{symbol-file}.debug_str}.  If you invoke this
+command with the @option{-dwarf-4} option, it produces a single
+file @file{@var{symbol-file}.gdb-index}.  The files are created
+in 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.debug_str.new symfile
+$ cat symfile.debug_str >>symfile.debug_str.new
+$ objcopy --add-section .debug_names=symfile.gdb-index \
+    --set-section-flags .debug_names=readonly \
+    --update-section .debug_str=symfile.debug_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
@@ -41701,8 +41714,11 @@ of blocks.
 @cindex .gdb_index section format
 @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
+This section documents the index section that is created by @kbd{save
+gdb-index -dwarf-4} (@pxref{Index Files}).  Currently preferred section is
+@code{.debug_names} as produced by the default @kbd{save gdb-index} command.
+@code{.debug_names} section is documented in official 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 2369d4b..79f5c92 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.
@@ -23196,6 +23202,33 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+   error checking.  */
+
+static void
+file_write (FILE *file, const void *data, size_t size)
+{
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
+}
+
+/* Write the contents of VEC to FILE, with error checking.  */
+
+template<class Elem>
+static void
+file_write (FILE *file, const std::vector<Elem> &vec)
+{
+  file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
+}
+
+/* Write the contents of BUF to FILE, with error checking.  */
+
+static void
+file_write (FILE *file, const gdb::byte_vector &buf)
+{
+  file_write (file, buf.data (), buf.size ());
+}
+
 /* In-memory buffer to prepare data to be written later to a file.  */
 class data_buf
 {
@@ -23217,6 +23250,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,11 +23278,16 @@ 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
   {
-    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
-      error (_("couldn't write data to file"));
+    ::file_write (file, m_vec);
   }
 
 private:
@@ -23383,6 +23436,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,57 +23810,566 @@ 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);
+  }
 
-  /* Order matters here; we want FILE to be closed before FILENAME is
-     unlinked, because on MS-Windows one cannot delete a file that is
-     still open.  (Don't call anything here that might throw until
-     file_closer is created.)  */
-  gdb::unlinker unlink_file (filename.c_str ());
-  file_closer close_out_file (out_file);
+  /* 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 ());
 
-  mapped_symtab symtab;
-  data_buf cu_list;
+    /* Check for overflow; to use boost::numeric_cast.  */
+    gdb_assert (retval == m_bucket_table.size ());
+    return retval;
+  }
 
-  /* While we're scanning CU's create a table that maps a psymtab pointer
-     (which is what addrmap records) to its index (which is what is recorded
-     in the index file).  This will later be needed to write the address
-     table.  */
-  psym_index_map cu_index_htab;
-  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+  /* 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 ());
 
-  /* 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.  */
+    /* 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 ());
+    ::file_write (file, m_bucket_table);
+    ::file_write (file, m_hash_table);
+    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
+    {
+      ::file_write (file, m_vec);
+    }
+
+  private:
+    std::vector<OffsetSize> m_vec;
+  };
 
-  /* The psyms_seen set is potentially going to be largish (~40k
-     elements when indexing a -g3 build of GDB itself).  Estimate the
-     number of elements in order to avoid too many rehashes, which
-     require rebuilding buckets and thus many trips to
-     malloc/free.  */
+  /* 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;
+}
+
+/* The psyms_seen set is potentially going to be largish (~40k
+   elements when indexing a -g3 build of GDB itself).  Estimate the
+   number of elements in order to avoid too many rehashes, which
+   require rebuilding buckets and thus many trips to
+   malloc/free.  */
+
+static size_t
+psyms_seen_size ()
+{
   size_t psyms_count = 0;
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
@@ -23814,7 +24382,31 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
     }
   /* Generating an index for gdb itself shows a ratio of
      TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5.  4 seems like a good bet.  */
-  std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+  return psyms_count / 4;
+}
+
+/* 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;
+
+  /* While we're scanning CU's create a table that maps a psymtab pointer
+     (which is what addrmap records) to its index (which is what is recorded
+     in the index file).  This will later be needed to write the address
+     table.  */
+  psym_index_map cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+
+  /* 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.  */
+
+  std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
@@ -23900,8 +24492,177 @@ 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 (psyms_seen_size ());
+  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 ());
+
+  /* Order matters here; we want FILE to be closed before FILENAME is
+     unlinked, because on MS-Windows one cannot delete a file that is
+     still open.  (Don't call anything here that might throw until
+     file_closer is created.)  */
+  gdb::unlinker unlink_file (filename.c_str ());
+  file_closer close_out_file (out_file);
+
+  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 ());
+  gdb::unlinker unlink_file_str (filename_str.c_str ());
+  file_closer close_out_file_str (out_file_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.
@@ -23910,12 +24671,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)
   {
@@ -23933,7 +24708,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)
 	  {
@@ -24067,7 +24842,11 @@ 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\n\
+\n\
+No options create two files with extension .debug_names and .debug_str\n\
+for DWARF-5 .debug_names section.  The -dwarf-4 creates one file with\n\
+.gdb-index extension for pre-DWARF-5 compatible .gdb_index section."),
 	       &save_cmdlist);
   set_cmd_completer (c, filename_completer);
 
-- 
2.9.4

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

* [PATCH v3.1 5/5] DWARF-5: .debug_names index consumer
  2017-06-19 20:56 ` [PATCH v3 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
@ 2017-06-28 21:21   ` Jan Kratochvil
  2017-07-02 14:30     ` [PATCH v3.2 " Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-28 21:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

[-- Attachment #1: Type: text/plain, Size: 36 bytes --]

Compilability update for GDB trunk.

[-- Attachment #2: Type: message/rfc822, Size: 63279 bytes --]

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] DWARF-5: .debug_names index consumer
Date: Wed, 28 Jun 2017 23:07:28 +0200

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                                   | 1465 +++++++++++++++++---
 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, 1368 insertions(+), 190 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 9fbdb55..3bfbc2b 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.  */
 
@@ -3126,6 +3244,165 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
 						    &objfile->objfile_obstack);
 }
 
+/* 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 addrmap *mutable_map;
+  const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets,
+				      SECT_OFF_TEXT (objfile)));
+
+  auto_obstack 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));
+	  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));
+	  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);
+	  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));
+	  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);
+	  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);
+	  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);
+	    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);
+	      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);
+}
+
 /* 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
@@ -3342,8 +3619,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
@@ -3419,98 +3695,409 @@ 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
-   table for THIS_CU.  */
+/* 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 *
 dw2_get_file_names (struct dwarf2_per_cu_data *this_cu)
@@ -4229,163 +4816,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
 };
@@ -4425,6 +5526,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;
 
@@ -22903,6 +24007,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.
@@ -23897,7 +25003,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;
@@ -24269,19 +25375,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
 };
 
-- 
2.9.4

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

* Re: [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-06-19 20:55 ` [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
@ 2017-06-29 19:40   ` Simon Marchi
  2017-07-01 15:23     ` [PATCH v3.1 " Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Simon Marchi @ 2017-06-29 19:40 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, Victor Leschuk

Hi Jan,

On 2017-06-19 22:55, Jan Kratochvil wrote:
> 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

Nit: use the same style ("then" on same line or next line) for all ifs.

> +      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

This strategy doesn't work for out of tree builds.  Perhaps cooking up 
something based on $0 would be better?  I see that the GDB variable is 
auto-detected the same way, but the gdb binary is found in the build 
directory, so it works for the tests, whereas gdb-add-index.sh is in the 
source directory.

I think it would still be nice to improve how GDB is auto-detected (in 
another patch), because one currently can't call the cc-with-tweaks.sh 
script from anywhere:

$ cd / && /home/emaisin/src/binutils-gdb/gdb/contrib/cc-with-tweaks.sh
cc-with-tweaks.sh: unable to find usable gdb

> +
>  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]}

Is PIPESTATUS bash specific?  If so, we should probably change the 
interpreter to

#!/usr/bin/env bash

The CC/CXX_FOR_TARGET variables in cc-with-tweaks.exp also use /bin/sh 
explicitly, I think it those can just be removed.

Thanks,

Simon

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

* [PATCH v3.1 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-06-29 19:40   ` Simon Marchi
@ 2017-07-01 15:23     ` Jan Kratochvil
  2017-12-08 23:43       ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-07-01 15:23 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Victor Leschuk

[-- Attachment #1: Type: text/plain, Size: 1750 bytes --]

On Thu, 29 Jun 2017 21:40:32 +0200, Simon Marchi wrote:
> On 2017-06-19 22:55, Jan Kratochvil wrote:
> > +if [ "$want_index" = true ]; then
> > +  if [ -z "$GDB_ADD_INDEX" ]
> > +  then
> 
> Nit: use the same style ("then" on same line or next line) for all ifs.

Done.


> > +      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
> 
> This strategy doesn't work for out of tree builds.

I use it always with explicit $GDB_ADD_INDEX so this auto-detection does not
really matter to me:
	https://git.jankratochvil.net/?p=nethome.git;a=commitdiff;h=44099fb634eca7837d30ab9b6afde0ec2838f705


> Perhaps cooking up
> something based on $0 would be better?  I see that the GDB variable is
> auto-detected the same way, but the gdb binary is found in the build
> directory, so it works for the tests, whereas gdb-add-index.sh is in the
> source directory.
> 
> I think it would still be nice to improve how GDB is auto-detected (in
> another patch),

OK, I believe that is unrelated to this patchset.  I am fine to always specify
all the tools explicitly.


> Is PIPESTATUS bash specific?  If so, we should probably change the
> interpreter to
> 
> #!/usr/bin/env bash
> 
> The CC/CXX_FOR_TARGET variables in cc-with-tweaks.exp also use /bin/sh
> explicitly, I think it those can just be removed.

Done.


Thanks,
Jan

[-- Attachment #2: Type: message/rfc822, Size: 4281 bytes --]

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] cc-with-tweaks.sh: Use gdb-add-index.sh
Date: Wed, 28 Jun 2017 23:07:25 +0200

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: Change interpreter to bash, incl. initial
	comment.
	(t, GDB_ADD_INDEX): New variables.
	<$want_index>: Call $GDB_ADD_INDEX.
---
 gdb/contrib/cc-with-tweaks.sh | 47 +++++++++++++++++++++++++++----------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/gdb/contrib/cc-with-tweaks.sh b/gdb/contrib/cc-with-tweaks.sh
index 7d39c00..ae52e1d 100755
--- a/gdb/contrib/cc-with-tweaks.sh
+++ b/gdb/contrib/cc-with-tweaks.sh
@@ -1,4 +1,4 @@
-#! /bin/sh
+#!/usr/bin/env bash
 # Wrapper around gcc to tweak the output in various ways when running
 # the testsuite.
 
@@ -27,8 +27,8 @@
 #
 # bash$ cd $objdir/gdb/testsuite
 # bash$ runtest \
-#   CC_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS gcc" \
-#   CXX_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS g++"
+#   CC_FOR_TARGET="/bin/bash $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS gcc" \
+#   CXX_FOR_TARGET="/bin/bash $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS g++"
 #
 # For documentation on Fission and dwp files:
 #     http://gcc.gnu.org/wiki/DebugFission
@@ -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,26 @@ 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 +174,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
 
-- 
2.9.4

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

* [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer
  2017-06-28 21:21   ` [PATCH v3.1 " Jan Kratochvil
@ 2017-07-02 14:30     ` Jan Kratochvil
  2017-12-08 23:59       ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-07-02 14:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

[-- Attachment #1: Type: text/plain, Size: 47 bytes --]

Forgotten augmentation checking in the reader.

[-- Attachment #2: Type: message/rfc822, Size: 64611 bytes --]

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] DWARF-5: .debug_names index consumer
Date: Sat, 1 Jul 2017 17:24:41 +0200

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.
	(dwarf5_augmentation): New from write_debug_names.
	(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.
	(write_debug_names): Move out and rename augmentation to
	dwarf5_augmentation.
	* 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                                   | 1481 +++++++++++++++++---
 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, 1382 insertions(+), 192 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 9fbdb55..fb671f8 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -211,6 +211,42 @@ 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;
+  bool augmentation_is_gdb;
+  uint8_t offset_size;
+  uint32_t cu_count = 0;
+  uint32_t tu_count, bucket_count, name_count;
+  const gdb_byte *cu_table_reordered, *tu_table_reordered;
+  const uint32_t *bucket_table_reordered, *hash_table_reordered;
+  const gdb_byte *name_table_string_offs_reordered;
+  const gdb_byte *name_table_entry_offs_reordered;
+  const gdb_byte *entry_pool;
+  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 +279,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 +346,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 +399,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 +1062,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 +2468,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 +2674,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 +3130,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.  */
 
@@ -3126,6 +3245,165 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
 						    &objfile->objfile_obstack);
 }
 
+/* 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 addrmap *mutable_map;
+  const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets,
+				      SECT_OFF_TEXT (objfile)));
+
+  auto_obstack 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));
+	  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));
+	  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);
+	  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));
+	  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);
+	  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);
+	  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);
+	    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);
+	      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);
+}
+
 /* 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
@@ -3342,8 +3620,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
@@ -3419,99 +3696,417 @@ dwarf2_read_index (struct objfile *objfile)
   return 1;
 }
 
-/* A helper for the "quick" functions which sets the global
-   dwarf2_per_objfile according to OBJFILE.  */
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
+static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
 
-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);
-}
+/* 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.
 
-/* die_reader_func for dw2_get_file_names.  */
+   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.
 
-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)
+   Returns true if all went well, false otherwise.  */
+
+static bool
+read_debug_names_from_section (struct objfile *objfile,
+			       const char *filename,
+			       struct dwarf2_section_info *section,
+			       mapped_debug_names &map)
 {
-  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;
+  map.augmentation_is_gdb = ((augmentation_string_size
+			      == sizeof (dwarf5_augmentation))
+			     && memcmp (addr, dwarf5_augmentation,
+					sizeof (dwarf5_augmentation)) == 0);
+  augmentation_string_size += (-augmentation_string_size) & 3;
+  addr += augmentation_string_size;
+
+  /* List of CUs */
+  map.cu_table_reordered = addr;
+  addr += map.cu_count * map.offset_size;
+
+  /* List of Local TUs */
+  map.tu_table_reordered = addr;
+  addr += map.tu_count * map.offset_size;
+  
+  /* Hash Lookup Table */
+  map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+  addr += map.bucket_count * 4;
+  map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+  addr += map.name_count * 4;
+
+  /* Name Table */
+  map.name_table_string_offs_reordered = addr;
+  addr += map.name_count * map.offset_size;
+  map.name_table_entry_offs_reordered = addr;
+  addr += map.name_count * map.offset_size;
+
+  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
-   table for THIS_CU.  */
-
+/* 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 *
 dw2_get_file_names (struct dwarf2_per_cu_data *this_cu)
 {
@@ -4235,157 +4830,675 @@ dw2_expand_symtabs_matching
 	      continue;
 	    }
 
-	  per_cu = dw2_get_cutu (cu_index);
-	  dw2_expand_symtabs_matching_one (per_cu, file_matcher,
-					   expansion_notify);
+	  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;
+	    }
+	}
+
+      ++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:
+	  if (!map.augmentation_is_gdb)
+	    break;
+	  have_is_static = true;
+	  is_static = true;
+	  break;
+	case DW_IDX_GNU_external:
+	  if (!map.augmentation_is_gdb)
+	    break;
+	  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
 };
@@ -4425,6 +5538,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;
 
@@ -22903,6 +24019,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.
@@ -23897,7 +25015,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;
@@ -24269,19 +25387,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.  */
@@ -24575,9 +25680,9 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
 				 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));
+				     + 2 + 2 + 7 * 4
+				     + sizeof (dwarf5_augmentation));
   size_t expected_bytes (0);
   expected_bytes += bytes_of_header;
   expected_bytes += cu_list.size ();
@@ -24627,9 +25732,9 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
 
   /* 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);
+  static_assert (sizeof (dwarf5_augmentation) % 4 == 0);
+  header.append_uint (4, dwarf5_byte_order, sizeof (dwarf5_augmentation));
+  header.append_data (dwarf5_augmentation);
 
   gdb_assert (header.size () == bytes_of_header);
 
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
 };
 
-- 
2.9.4

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

* Re: [PATCH v3.1 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-07-01 15:23     ` [PATCH v3.1 " Jan Kratochvil
@ 2017-12-08 23:43       ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-08 23:43 UTC (permalink / raw)
  To: Jan Kratochvil, Simon Marchi; +Cc: gdb-patches, Victor Leschuk

On 07/01/2017 04:23 PM, Jan Kratochvil wrote:
> On Thu, 29 Jun 2017 21:40:32 +0200, Simon Marchi wrote:
> 
>>> +      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
>>
>> This strategy doesn't work for out of tree builds.
> 
> I use it always with explicit $GDB_ADD_INDEX so this auto-detection does not
> really matter to me:
> 	https://git.jankratochvil.net/?p=nethome.git;a=commitdiff;h=44099fb634eca7837d30ab9b6afde0ec2838f705
> 
> 

Still, it's not OK to break testing with out of tree builds,
which is what most GDB developers use.

>> Perhaps cooking up
>> something based on $0 would be better?  I see that the GDB variable is
>> auto-detected the same way, but the gdb binary is found in the build
>> directory, so it works for the tests, whereas gdb-add-index.sh is in the
>> source directory.
>>
>> I think it would still be nice to improve how GDB is auto-detected (in
>> another patch),
> 
> OK, I believe that is unrelated to this patchset.  I am fine to always specify
> all the tools explicitly.

We must not break out of tree builds testing (with e.g
--target_board=dwarf4-gdb-index) at least.

I couldn't figure out what this hunk in the patch was for:

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

so I removed it.


> 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

I think we may want to revisit this -- may be better to skip the
tests when testing with an index, using some skip_foo_marker (like
the existing skip_python_tests, etc.), so that testing doesn't spend
time needlessly on those.

But I sympathize with not wanting to change the current behavior.

Thus, here's what I pushed.

From 6432ec65a8822246db5bcede0c6bd3ed0e464a0b Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Fri, 8 Dec 2017 22:44:10 +0000
Subject: [PATCH 1/9] cc-with-tweaks.sh: Use gdb-add-index.sh

With DWARF-5 .debug_names, the commands to add the index to the symbol
file are more complicated, as now also .debug_str needs to be
modified.

Currently, contrib/cc-with-tweaks.sh calls objcopy to handle the '-i'
option instead of using contrib/gdb-add-index.sh which basically does
the same.  To help with .debug_names, this commit makes
contrib/cc-with-tweaks.sh reuse contrib/gdb-add-index.sh instead.

A problem this ran into is whether contrib/cc-with-tweaks.sh should
fail or not when no index is produced.

Currently, contrib/cc-with-tweaks.sh is more quiet (=successful) than
contrib/gdb-add-index.sh and so with no further changes testsuite runs
with an index would "regress".  This commit tries 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 gdb/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

gdb/ChangeLog
2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Pedro Alves  <palves@redhat.com>

	* contrib/cc-with-tweaks.sh: Change interpreter to bash, incl. initial
	comment.
	(GDB_ADD_INDEX): New variable.
	<$want_index>: Call $GDB_ADD_INDEX.
---
 gdb/ChangeLog                 |  8 ++++++++
 gdb/contrib/cc-with-tweaks.sh | 40 +++++++++++++++++++++++-----------------
 2 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 26cf18e..e90a3f0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+	    Pedro Alves  <palves@redhat.com>
+
+	* contrib/cc-with-tweaks.sh: Change interpreter to bash, incl. initial
+	comment.
+	(GDB_ADD_INDEX): New variable.
+	<$want_index>: Call $GDB_ADD_INDEX.
+
 2017-12-08  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* dtrace-probe.c (dtrace_process_dof_probe): Do not declare a new
diff --git a/gdb/contrib/cc-with-tweaks.sh b/gdb/contrib/cc-with-tweaks.sh
index 7d39c00..a65fef8 100755
--- a/gdb/contrib/cc-with-tweaks.sh
+++ b/gdb/contrib/cc-with-tweaks.sh
@@ -1,4 +1,4 @@
-#! /bin/sh
+#!/usr/bin/env bash
 # Wrapper around gcc to tweak the output in various ways when running
 # the testsuite.
 
@@ -27,8 +27,8 @@
 #
 # bash$ cd $objdir/gdb/testsuite
 # bash$ runtest \
-#   CC_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS gcc" \
-#   CXX_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS g++"
+#   CC_FOR_TARGET="/bin/bash $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS gcc" \
+#   CXX_FOR_TARGET="/bin/bash $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS g++"
 #
 # For documentation on Fission and dwp files:
 #     http://gcc.gnu.org/wiki/DebugFission
@@ -47,6 +47,7 @@
 # If nothing is given, no changes are made
 
 myname=cc-with-tweaks.sh
+mydir=`dirname "$0"`
 
 if [ -z "$GDB" ]
 then
@@ -93,6 +94,20 @@ while [ $# -gt 0 ]; do
     shift
 done
 
+if [ "$want_index" = true ]
+then
+    if [ -z "$GDB_ADD_INDEX" ]
+    then
+	if [ -f $mydir/gdb-add-index.sh ]
+	then
+	    GDB_ADD_INDEX="$mydir/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 +167,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
 
-- 
2.5.5


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

* Re: [PATCH v3.2 2/5] DWARF-5: .debug_names index producer
  2017-06-22 20:03         ` [PATCH v3.2 " Jan Kratochvil
@ 2017-12-08 23:51           ` Pedro Alves
  2017-12-12 15:38             ` Jan Kratochvil
  2017-12-31  3:52             ` Simon Marchi
  0 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-08 23:51 UTC (permalink / raw)
  To: Jan Kratochvil, Eli Zaretskii; +Cc: gdb-patches, vleschuk

On 06/22/2017 09:03 PM, Jan Kratochvil wrote:
> 
> 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.

I much prefer to add the support for debug_names first without
changing the default.  Seems a bit too risky to me to flip
the default without some more experience.  I do see some
regressions compared to .gdb_index, for example.  (See more
in the consumer patch.)

When I started looking at this in detail this week, I was
a bit surprised to learn that the names table is essentially the
same as .gdb_index's, meaning full-qualified names with no
overload/parameter info, and especially -- no indication
of which language the name is for, which was a nuisance
for making C++ wildmatching support work with .gdb_index.
Somehow I had the impression that it was different from
earlier chats.  OTOH, the upside is that that we'll manage
to reuse the mapped_index::name_components code for .debug_names.

Some comments / nits below.  Resulting merged patch at the bottom.

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index c167a86..d2057ca 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -19244,18 +19244,31 @@ 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}.
> +Create index files for all symbol files currently known by
> +@value{GDBN}.  For each known @var{symbol-file}, this command
> +by default creates 2 files: @file{@var{symbol-file}.debug_names}
> +and @file{@var{symbol-file}.debug_str}.  If you invoke this
> +command with the @option{-dwarf-4} option, it produces a single
> +file @file{@var{symbol-file}.gdb-index}.  The files are created
> +in the given @var{directory}.
>  @end table

I changed the patch to add a new -dwarf-5 option instead to
request .debug_names, and kept the default producing .gdb_index.
I did the trivial update to the documentation, keeping all the
text that Eli had already approved as is.

I think we may want to revisit the command arguments.
"-dwarf-5" may be confusing since there's really nothing preventing
use of .debug_names with -gdwarf-4, etc.  The reference to "5"
may also look outdated in a few years, after a couple
of DWARF releases more.

Maybe something like this would be better:

 (gdb) save gdb-index -format gdb_index
 (gdb) save gdb-index -format debug_names

> +/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
> +   error checking.  */
> +
> +static void
> +file_write (FILE *file, const void *data, size_t size)
> +{
> +  if (fwrite (data, 1, size, file) != size)
> +    error (_("couldn't data write to file"));
> +}
> +
> +/* Write the contents of VEC to FILE, with error checking.  */
> +
> +template<class Elem>
> +static void
> +file_write (FILE *file, const std::vector<Elem> &vec)
> +{
> +  file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
> +}
> +
> +/* Write the contents of BUF to FILE, with error checking.  */
> +
> +static void
> +file_write (FILE *file, const gdb::byte_vector &buf)
> +{
> +  file_write (file, buf.data (), buf.size ());
> +}

We don't really need this last overload, we can use 
the one above, we just need to add an extra template
parameter for the allocator.

> +
>  /* In-memory buffer to prepare data to be written later to a file.  */
>  class data_buf
>  {
> @@ -23217,6 +23250,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;
> +      }
> +  }
> +

>  private:
> @@ -23383,6 +23436,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;
> +  }
> +

I was surprised by this implicit conversion operator, so I
renamed it to explicit c_str() instead.

>  private:
>    friend class c_str_view_hasher;
>    const char *const m_cstr;
> @@ -23751,57 +23810,566 @@ private:
>    FILE *m_file;
>  };
>  

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

These look like always return false, since per_cu.sect_off is 32-bit?
I've left it as is, but it doesn't look right to me.  Seems like
that makes all the 64-bit support dead as is.


> -/* 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_),

Tail '_' not necessary since the fields are prefixed with m_ (i.e., there's
no ambiguity without the '_').

> +  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));

The patch series has lots of uses of direct-initialization when
copy-initialization would do just fine.  I've changed all I found.

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

> +
> +  /* 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);

Yeah, we don't support that very well currently.  I've looked
at it a bit recently, 
  https://sourceware.org/ml/gdb/2017-11/msg00021.html

and I'd like to see gdb's unicode identifiers support improve,
but as you have it should be fine for now.

It's not been a high priority because with GCC, the only way
to use unicode identifiers is to use UCNs, which of course
nobody does.

I saw that you were moving this method out of the class
in the consumer patch, so I went ahead and moved it out here
already.  I also changed the parameter to "const char *" while
at it, which avoids the casts at the callers side.

Likewise, I made the dwarf5_gdb_augmentation global already
in this patch.

> +
> +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 ());
> +
> +  /* Order matters here; we want FILE to be closed before FILENAME is
> +     unlinked, because on MS-Windows one cannot delete a file that is
> +     still open.  (Don't call anything here that might throw until
> +     file_closer is created.)  */
> +  gdb::unlinker unlink_file (filename.c_str ());
> +  file_closer close_out_file (out_file);
> +
> +  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 ());
> +  gdb::unlinker unlink_file_str (filename_str.c_str ());
> +  file_closer close_out_file_str (out_file_str);

This is opening/creating/deleting the out_file_str file unnecessarily
when generating .gdb_index indexes.  I've fixed it to only create
the .debug_str file when is_dwarf5 is true.  And then that meant that
we no longer need to add the unused out_file_str parameter
to write_gdbindex.

Also, I've replaced the is_dwarf5 boolean with an enum.

> +
> +  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.
> @@ -23910,12 +24671,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"));
>  

As mentioned, I switched this to -dwarf-5 instead, and changed the
default back.

>    ALL_OBJFILES (objfile)
>    {
> @@ -23933,7 +24708,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)
>  	  {
> @@ -24067,7 +24842,11 @@ 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\n\
> +\n\
> +No options create two files with extension .debug_names and .debug_str\n\
> +for DWARF-5 .debug_names section.  The -dwarf-4 creates one file with\n\
> +.gdb-index extension for pre-DWARF-5 compatible .gdb_index section."),
>  	       &save_cmdlist);

Ditto.

I also adjusted DW_IDX_GNU_static -> DW_IDX_GNU_internal, since that had
gone in meanwhile.

I also fixed uses of single-argument static_assert, which
requires C++17, and doesn't compile with e.g. gcc 5.3.1.

Here's what I pushed.  Thanks for the patch.

From 437afbb81e3a04cbd933fc534a50c686eaa63b19 Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Fri, 8 Dec 2017 22:44:10 +0000
Subject: [PATCH 2/9] DWARF-5: .debug_names index producer

This adds a new "-dwarf-5" switch to "save gdb-index" that makes it
generate index files with DWARF-5 .debug_names/.debug_str sections
instead of GDB's own .gdb_index.

We should probably add a command line option to
contrib/gdb-add-index.sh (incl. cc-with-tweaks.sh) for the new
-dwarf-5 GDB option, and a new target board to make it more convenient
to exercise this.  To be done later.

gdb/ChangeLog
2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Pedro Alves  <palves@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, set, list.
	(INDEX_SUFFIX): Rename to ...
	(INDEX4_SUFFIX): ... here.
	(INDEX5_SUFFIX, DEBUG_STR_SUFFIX): New.
	(file_write(FILE *, const void *, size_t)): New.
	(file_write(FILE *, const std::vector<Elem, Alloc> &)): New.
	(data_buf::append_unsigned_leb128, data_buf::empty): New.
	(data_buf::file_write): Use ::file_write.
	(data_buf::c_str, dwarf5_djb_hash, debug_names)
	(check_dwarf64_offsets): New.
	(psyms_seen_size, write_gdbindex): New from
	write_psymtabs_to_index code.
	(dwarf5_gdb_augmentation, write_debug_names, assert_file_size)
	(enum dw_index_kind): New.
	(write_psymtabs_to_index): New parameter index_kind.  Support
	filename_str and out_file_str.  Move code to write_gdbindex,
	possibly call write_debug_names.
	(save_gdb_index_command): New parameter -dwarf-5.
	(_initialize_dwarf2_read): Document the new parameter -dwarf-5.

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

	* gdb.texinfo (Index Files): Document .debug_names and -dwarf-5.
--

 gdb/contrib/gdb-add-index.sh |   53 ++
 gdb/doc/gdb.texinfo          |   24 +
 gdb/dwarf2read.c             |  919 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 935 insertions(+), 61 deletions(-)
---
 gdb/ChangeLog                |  27 ++
 gdb/doc/ChangeLog            |   4 +
 gdb/doc/gdb.texinfo          |  24 +-
 gdb/contrib/gdb-add-index.sh |  53 ++-
 gdb/dwarf2read.c             | 916 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 964 insertions(+), 60 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e90a3f0..0f26785 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,6 +1,33 @@
 2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
 	    Pedro Alves  <palves@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, set, list.
+	(INDEX_SUFFIX): Rename to ...
+	(INDEX4_SUFFIX): ... here.
+	(INDEX5_SUFFIX, DEBUG_STR_SUFFIX): New.
+	(file_write(FILE *, const void *, size_t)): New.
+	(file_write(FILE *, const std::vector<Elem, Alloc> &)): New.
+	(data_buf::append_unsigned_leb128, data_buf::empty): New.
+	(data_buf::file_write): Use ::file_write.
+	(data_buf::c_str, dwarf5_djb_hash, debug_names)
+	(check_dwarf64_offsets): New.
+	(psyms_seen_size, write_gdbindex): New from
+	write_psymtabs_to_index code.
+	(dwarf5_gdb_augmentation, write_debug_names, assert_file_size)
+	(enum dw_index_kind): New.
+	(write_psymtabs_to_index): New parameter index_kind.  Support
+	filename_str and out_file_str.  Move code to write_gdbindex,
+	possibly call write_debug_names.
+	(save_gdb_index_command): New parameter -dwarf-5.
+	(_initialize_dwarf2_read): Document the new parameter -dwarf-5.
+
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+	    Pedro Alves  <palves@redhat.com>
+
 	* contrib/cc-with-tweaks.sh: Change interpreter to bash, incl. initial
 	comment.
 	(GDB_ADD_INDEX): New variable.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index df294d6..7710640 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* gdb.texinfo (Index Files): Document .debug_names and -dwarf-5.
+
 2017-12-07  Keith Seitz  <keiths@redhat.com>
 
 	* gdb.texinfo (Symbols): Document "set print type nested-type-limit"
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1e4ef98..062f01d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19565,12 +19565,16 @@ 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-5] @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}.
+Create index files for all symbol files currently known by
+@value{GDBN}.  For each known @var{symbol-file}, this command by
+default creates it produces a single file
+@file{@var{symbol-file}.gdb-index}.  If you invoke this command with
+the @option{-dwarf-5} option, it produces 2 files:
+@file{@var{symbol-file}.debug_names} and
+@file{@var{symbol-file}.debug_str}.  The files are created in the
+given @var{directory}.
 @end table
 
 Once you have created an index file you can merge it into your symbol
@@ -19581,6 +19585,16 @@ $ objcopy --add-section .gdb_index=symfile.gdb-index \
     --set-section-flags .gdb_index=readonly symfile symfile
 @end smallexample
 
+Or for @code{-dwarf-5}:
+
+@smallexample
+$ objcopy --dump-section .debug_str=symfile.debug_str.new symfile
+$ cat symfile.debug_str >>symfile.debug_str.new
+$ objcopy --add-section .debug_names=symfile.gdb-index \
+    --set-section-flags .debug_names=readonly \
+    --update-section .debug_str=symfile.debug_str.new symfile symfile
+@end smallexample
+
 @value{GDBN} will normally ignore older versions of @file{.gdb_index}
 sections that have been deprecated.  Usually they are deprecated because
 they are missing a new feature or have performance issues.
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/dwarf2read.c b/gdb/dwarf2read.c
index 68ddbb1..a9daf1f 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -82,6 +82,12 @@
 #include <unordered_set>
 #include <unordered_map>
 #include "selftest.h"
+#include <cmath>
+#include <set>
+#include <forward_list>
+
+typedef struct symbol *symbolp;
+DEF_VEC_P (symbolp);
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -2267,7 +2273,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"
 
 /* See declaration.  */
 
@@ -24232,6 +24240,25 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+   error checking.  */
+
+static void
+file_write (FILE *file, const void *data, size_t size)
+{
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
+}
+
+/* Write the contents of VEC to FILE, with error checking.  */
+
+template<typename Elem, typename Alloc>
+static void
+file_write (FILE *file, const std::vector<Elem, Alloc> &vec)
+{
+  file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
+}
+
 /* In-memory buffer to prepare data to be written later to a file.  */
 class data_buf
 {
@@ -24253,6 +24280,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 == 0)
+	  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)
@@ -24266,11 +24308,16 @@ public:
     return m_vec.size ();
   }
 
+  /* Return true iff the buffer is empty.  */
+  bool empty () const
+  {
+    return m_vec.empty ();
+  }
+
   /* Write the buffer to FILE.  */
   void file_write (FILE *file) const
   {
-    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
-      error (_("couldn't write data to file"));
+    ::file_write (file, m_vec);
   }
 
 private:
@@ -24419,6 +24466,13 @@ public:
     return strcmp (m_cstr, other.m_cstr) == 0;
   }
 
+  /* Return the underlying C string.  Note, the returned string is
+     only a reference with lifetime of this object.  */
+  const char *c_str () const
+  {
+    return m_cstr;
+  }
+
 private:
   friend class c_str_view_hasher;
   const char *const m_cstr;
@@ -24771,57 +24825,575 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
-/* Create an index file for OBJFILE in the directory DIR.  */
+/* Symbol name hashing function as specified by DWARF-5.  */
 
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+static uint32_t
+dwarf5_djb_hash (const char *str_)
 {
-  if (dwarf2_per_objfile->using_index)
-    error (_("Cannot use an index to create the index"));
+  const unsigned char *str = (const unsigned char *) str_;
 
-  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"));
+  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+     See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
 
-  if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
-    return;
+  uint32_t hash = 5381;
+  while (int c = *str++)
+    hash = hash * 33 + tolower (c);
+  return hash;
+}
 
-  struct stat st;
-  if (stat (objfile_name (objfile), &st) < 0)
-    perror_with_name (objfile_name (objfile));
+/* DWARF-5 .debug_names builder.  */
+class debug_names
+{
+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)
+  {}
 
-  std::string filename (std::string (dir) + SLASH_STRING
-			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+  /* 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 == 0)
+      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));
+  }
 
-  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
-  if (!out_file)
-    error (_("Can't open `%s' for writing"), filename.c_str ());
+  /* 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.  */
+    struct hash_it_pair
+    {
+      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.c_str ();
+	const uint32_t hash = dwarf5_djb_hash (name);
+	hash_it_pair hashitpair;
+	hashitpair.hash = hash;
+	hashitpair.it = it;
+	auto &slot = bucket_hash[hash % bucket_hash.size()];
+	slot.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.c_str ()));
+	    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 == 0)
+		  {
+		    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_internal
+							   : 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);
+		  }
 
-  /* Order matters here; we want FILE to be closed before FILENAME is
-     unlinked, because on MS-Windows one cannot delete a file that is
-     still open.  (Don't call anything here that might throw until
-     file_closer is created.)  */
-  gdb::unlinker unlink_file (filename.c_str ());
-  gdb_file_up close_out_file (out_file);
+		m_entry_pool.append_unsigned_leb128 (idx);
+		m_entry_pool.append_unsigned_leb128 (value.cu_index);
+	      }
 
-  mapped_symtab symtab;
-  data_buf cu_list;
+	    /* Terminate the list of CUs.  */
+	    m_entry_pool.append_unsigned_leb128 (0);
+	  }
+      }
+    gdb_assert (m_hash_table.size () == name_count);
 
-  /* While we're scanning CU's create a table that maps a psymtab pointer
-     (which is what addrmap records) to its index (which is what is recorded
-     in the index file).  This will later be needed to write the address
-     table.  */
-  psym_index_map cu_index_htab;
-  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+    /* Terminate tags list.  */
+    m_abbrev_table.append_unsigned_leb128 (0);
+  }
 
-  /* 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.  */
+  /* Return .debug_names bucket count.  This must be called only after
+     calling the 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.  */
+    gdb_assert (retval == m_bucket_table.size ());
+    return retval;
+  }
+
+  /* Return .debug_names names count.  This must be called only after
+     calling the 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.  */
+    gdb_assert (retval == m_hash_table.size ());
+    return retval;
+  }
+
+  /* Return number of bytes of .debug_names abbreviation table.  This
+     must be called only after calling the 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)
+  {
+    for (int 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[psymtab->globals_offset],
+		    psymtab->n_global_syms, cu_index, false);
+    write_psymbols (psyms_seen,
+		    &objfile->static_psymbols[psymtab->statics_offset],
+		    psymtab->n_static_syms, cu_index, true);
+  }
+
+  /* Return number of bytes the .debug_names section will have.  This
+     must be called only after calling the 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_NAMES and .debug_str addition to
+     FILE_STR.  This must be called only after calling the build
+     method.  */
+  void file_write (FILE *file_names, FILE *file_str) const
+  {
+    /* Verify the build method has been already called.  */
+    gdb_assert (!m_abbrev_table.empty ());
+    ::file_write (file_names, m_bucket_table);
+    ::file_write (file_names, m_hash_table);
+    m_name_table_string_offs.file_write (file_names);
+    m_name_table_entry_offs.file_write (file_names);
+    m_abbrev_table.file_write (file_names);
+    m_entry_pool.file_write (file_names);
+    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 the .debug_str section.  Add
+       such symbol to the section's 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;
+    }
+
+    /* Append the end of the .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:
+    explicit 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<typename OffsetSize>
+  class offset_vec_tmpl : public offset_vec
+  {
+  public:
+    explicit offset_vec_tmpl (bfd_endian dwarf5_byte_order_)
+      : offset_vec (dwarf5_byte_order_)
+    {}
+
+    /* Implement offset_vec::reserve.  */
+    void reserve (size_t nelem) override
+    {
+      m_vec.reserve (nelem);
+    }
+
+    /* Implement offset_vec::push_back_reorder.  */
+    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.  */
+    size_t bytes () const override
+    {
+      return m_vec.size () * sizeof (m_vec[0]);
+    }
+
+    /* Implement offset_vec::file_write.  */
+    void file_write (FILE *file) const override
+    {
+      ::file_write (file, m_vec);
+    }
+
+  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_)
+    {
+    }
+  };
 
-  /* The psyms_seen set is potentially going to be largish (~40k
-     elements when indexing a -g3 build of GDB itself).  Estimate the
-     number of elements in order to avoid too many rehashes, which
-     require rebuilding buckets and thus many trips to
-     malloc/free.  */
+  /* Template to unify DWARF-32 and DWARF-64 .debug_names output
+     respecting name table width.  */
+  template<typename OffsetSize>
+  class dwarf_tmpl : public dwarf
+  {
+  public:
+    explicit 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;
+    offset_vec_tmpl<OffsetSize> m_name_table_entry_offs;
+  };
+
+  /* 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 parameter 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;
+}
+
+/* The psyms_seen set is potentially going to be largish (~40k
+   elements when indexing a -g3 build of GDB itself).  Estimate the
+   number of elements in order to avoid too many rehashes, which
+   require rebuilding buckets and thus many trips to
+   malloc/free.  */
+
+static size_t
+psyms_seen_size ()
+{
   size_t psyms_count = 0;
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
@@ -24834,7 +25406,30 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
     }
   /* Generating an index for gdb itself shows a ratio of
      TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5.  4 seems like a good bet.  */
-  std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+  return psyms_count / 4;
+}
+
+/* Write new .gdb_index section for OBJFILE into OUT_FILE.
+   Return how many bytes were expected to be written into OUT_FILE.  */
+
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file)
+{
+  mapped_symtab symtab;
+  data_buf cu_list;
+
+  /* While we're scanning CU's create a table that maps a psymtab pointer
+     (which is what addrmap records) to its index (which is what is recorded
+     in the index file).  This will later be needed to write the address
+     table.  */
+  psym_index_map cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
+
+  /* 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.  */
+
+  std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
@@ -24920,22 +25515,241 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   symtab_vec.file_write (out_file);
   constant_pool.file_write (out_file);
 
+  return total_len;
+}
+
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
+static const gdb_byte dwarf5_gdb_augmentation[] = { 'G', 'D', 'B', 0 };
+
+/* Write a 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 (psyms_seen_size ());
+  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 .debug_names.  */
+      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 generated 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 offset_type bytes_of_header
+    = ((dwarf5_is_dwarf64 ? 12 : 4)
+       + 2 + 2 + 7 * 4
+       + sizeof (dwarf5_gdb_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 (dwarf5_gdb_augmentation) % 4 == 0, "");
+  header.append_uint (4, dwarf5_byte_order, sizeof (dwarf5_gdb_augmentation));
+  header.append_data (dwarf5_gdb_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;
+}
+
+/* Assert that FILE's size is EXPECTED_SIZE.  Assumes file's seek
+   position is at the end of the file.  */
+
+static void
+assert_file_size (FILE *file, const char *filename, size_t expected_size)
+{
+  const auto file_size = ftell (file);
+  if (file_size == -1)
+    error (_("Can't get `%s' size"), filename);
+  gdb_assert (file_size == expected_size);
+}
+
+/* An index variant.  */
+enum dw_index_kind
+{
+  /* GDB's own .gdb_index format.   */
+  GDB_INDEX,
+
+  /* DWARF5 .debug_names.  */
+  DEBUG_NAMES,
+};
+
+/* Create an index file for OBJFILE in the directory DIR.  */
+
+static void
+write_psymtabs_to_index (struct objfile *objfile, const char *dir,
+			 dw_index_kind index_kind)
+{
+  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))
+			+ (index_kind == dw_index_kind::DEBUG_NAMES
+			   ? INDEX5_SUFFIX : INDEX4_SUFFIX));
+
+  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
+  if (!out_file)
+    error (_("Can't open `%s' for writing"), filename.c_str ());
+
+  /* Order matters here; we want FILE to be closed before FILENAME is
+     unlinked, because on MS-Windows one cannot delete a file that is
+     still open.  (Don't call anything here that might throw until
+     file_closer is created.)  */
+  gdb::unlinker unlink_file (filename.c_str ());
+  gdb_file_up close_out_file (out_file);
+
+  if (index_kind == dw_index_kind::DEBUG_NAMES)
+    {
+      std::string filename_str (std::string (dir) + SLASH_STRING
+				+ lbasename (objfile_name (objfile))
+				+ DEBUG_STR_SUFFIX);
+      FILE *out_file_str
+	= gdb_fopen_cloexec (filename_str.c_str (), "wb").release ();
+      if (!out_file_str)
+	error (_("Can't open `%s' for writing"), filename_str.c_str ());
+      gdb::unlinker unlink_file_str (filename_str.c_str ());
+      gdb_file_up close_out_file_str (out_file_str);
+
+      const size_t total_len
+	= write_debug_names (objfile, out_file, out_file_str);
+      assert_file_size (out_file, filename.c_str (), total_len);
+
+      /* We want to keep the file .debug_str file too.  */
+      unlink_file_str.keep ();
+    }
+  else
+    {
+      const size_t total_len
+	= write_gdbindex (objfile, out_file);
+      assert_file_size (out_file, filename.c_str (), total_len);
+    }
+
   /* We want to keep the file.  */
   unlink_file.keep ();
 }
 
 /* Implementation of the `save gdb-index' command.
    
-   Note that the file format used by this command is documented in the
-   GDB manual.  Any changes here must be documented there.  */
+   Note that the .gdb_index file format used by this command is
+   documented in the GDB manual.  Any changes here must be documented
+   there.  */
 
 static void
 save_gdb_index_command (const char *arg, int from_tty)
 {
   struct objfile *objfile;
+  const char dwarf5space[] = "-dwarf-5 ";
+  dw_index_kind index_kind = dw_index_kind::GDB_INDEX;
+
+  if (!arg)
+    arg = "";
+
+  arg = skip_spaces (arg);
+  if (strncmp (arg, dwarf5space, strlen (dwarf5space)) == 0)
+    {
+      index_kind = dw_index_kind::DEBUG_NAMES;
+      arg += strlen (dwarf5space);
+      arg = skip_spaces (arg);
+    }
 
-  if (!arg || !*arg)
-    error (_("usage: save gdb-index DIRECTORY"));
+  if (!*arg)
+    error (_("usage: save gdb-index [-dwarf-5] DIRECTORY"));
 
   ALL_OBJFILES (objfile)
   {
@@ -24953,7 +25767,7 @@ save_gdb_index_command (const char *arg, int from_tty)
 
 	TRY
 	  {
-	    write_psymtabs_to_index (objfile, arg);
+	    write_psymtabs_to_index (objfile, arg, index_kind);
 	  }
 	CATCH (except, RETURN_MASK_ERROR)
 	  {
@@ -25085,7 +25899,11 @@ 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-5] DIRECTORY\n\
+\n\
+No options create one file with .gdb-index extension for pre-DWARF-5\n\
+compatible .gdb_index section.  With -dwarf-5 creates two files with\n\
+extension .debug_names and .debug_str for DWARF-5 .debug_names section."),
 	       &save_cmdlist);
   set_cmd_completer (c, filename_completer);
 
-- 
2.5.5


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

* Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-06-19 20:56 ` [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
@ 2017-12-08 23:52   ` Pedro Alves
  2017-12-11 13:04     ` Yao Qi
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-12-08 23:52 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 06/19/2017 09:55 PM, Jan Kratochvil wrote:
> 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.

I could argue it's a step backward for exposing ELF details to the
DWARF code.  There's no reason AFAIK that .gdb_index and/or .debug_names
couldn't be made to work with COFF/PE for example.

But we can cross that bridge when we come to it.  I've pushed
this in as is, except I removed the "code cleanup" from the
subject.  :-)

From abccd1e7b7a37385159610ca4e0bc2632a547e9a Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Fri, 8 Dec 2017 22:44:11 +0000
Subject: [PATCH 3/9] Change dwarf2_initialize_objfile's return value

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.

gdb/ChangeLog
2017-12-08  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/ChangeLog    | 10 ++++++++++
 gdb/defs.h       |  5 +++++
 gdb/dwarf2read.c |  8 ++++----
 gdb/elfread.c    | 11 +++--------
 gdb/symfile.h    |  2 +-
 5 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0f26785..b6f3714 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,4 +1,14 @@
 2017-12-08  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.
+
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
 	    Pedro Alves  <palves@redhat.com>
 
 	* contrib/gdb-add-index.sh (index): Rename to ...
diff --git a/gdb/defs.h b/gdb/defs.h
index f76293f..a873a55 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -679,6 +679,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 a9daf1f..798af72 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -5291,7 +5291,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
@@ -5320,13 +5320,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 b8881d9..904696f 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -48,10 +48,6 @@
 #include "location.h"
 #include "auxv.h"
 
-/* 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.  */
@@ -1219,10 +1215,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
@@ -1230,6 +1223,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 fa38abf..194dccf 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -601,7 +601,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 *);
 
-- 
2.5.5


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

* Re: [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code
  2017-06-19 20:56 ` [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
@ 2017-12-08 23:53   ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-08 23:53 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 06/19/2017 09:55 PM, Jan Kratochvil wrote:
> 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.

This code had unfortunately changed too much for the patch to
apply, but I managed to reconstruct it manually.

Here's what I pushed.

From 4b514bc80885fa91e57b9d80f74ea267df343c46 Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Fri, 8 Dec 2017 22:44:11 +0000
Subject: [PATCH 4/9] Refactor: Move some generic code out of .gdb_index code

Preparation for the next patch.

gdb/ChangeLog
2017-12-08  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/ChangeLog    |   8 ++
 gdb/dwarf2read.c | 220 +++++++++++++++++++++++++++++++++----------------------
 2 files changed, 139 insertions(+), 89 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b6f3714..5d596f0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
 2017-12-08  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.
+
+2017-12-08  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.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 798af72..80d4857 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -3061,6 +3061,29 @@ dw2_get_cu (int index)
   return dwarf2_per_objfile->all_comp_units[index];
 }
 
+/* Return a new dwarf2_per_cu_data allocated on OBJFILE's
+   objfile_obstack, and constructed 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.  */
 
@@ -3082,17 +3105,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);
     }
 }
 
@@ -4939,6 +4953,31 @@ run_test ()
 
 #endif /* GDB_SELF_TEST */
 
+/* If FILE_MATCHER is NULL or if PER_CU has
+   dwarf2_per_cu_quick_data::MARK set (see
+   dw_expand_symtabs_matching_file_matcher), expand the CU and call
+   EXPANSION_NOTIFY on it.  */
+
+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)
+    {
+      bool 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);
+    }
+}
+
 /* Helper for dw2_expand_matching symtabs.  Called on each symbol
    matched, to expand corresponding CUs that were marked.  IDX is the
    index of the symbol name that matched.  */
@@ -5016,109 +5055,112 @@ dw2_expand_marked_cus
 	}
 
       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);
     }
 }
 
+/* If FILE_MATCHER is non-NULL, set all the
+   dwarf2_per_cu_quick_data::MARK of the current DWARF2_PER_OBJFILE
+   that match FILE_MATCHER.  */
+
 static void
-dw2_expand_symtabs_matching
-  (struct objfile *objfile,
-   gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
-   const lookup_name_info &lookup_name,
-   gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
-   gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
-   enum search_domain kind)
+dw_expand_symtabs_matching_file_matcher
+  (gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
 {
-  int i;
-
-  dw2_setup (objfile);
-
-  /* index_table is NULL if OBJF_READNOW.  */
-  if (!dwarf2_per_objfile->index_table)
+  if (file_matcher == NULL)
     return;
 
-  if (file_matcher != NULL)
-    {
-      htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
+  objfile *const objfile = dwarf2_per_objfile->objfile;
+
+  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;
+static void
+dw2_expand_symtabs_matching
+  (struct objfile *objfile,
+   gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+   const lookup_name_info &lookup_name,
+   gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+   gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
+   enum search_domain kind)
+{
+  int i;
 
-	      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;
-		}
-	    }
+  dw2_setup (objfile);
 
-	  slot = htab_find_slot (per_cu->v.quick->mark
-				 ? visited_found.get ()
-				 : visited_not_found.get (),
-				 file_data, INSERT);
-	  *slot = file_data;
-	}
-    }
+  /* index_table is NULL if OBJF_READNOW.  */
+  if (!dwarf2_per_objfile->index_table)
+    return;
+
+  dw_expand_symtabs_matching_file_matcher (file_matcher);
 
   mapped_index &index = *dwarf2_per_objfile->index_table;
 
-- 
2.5.5

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

* Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer
  2017-07-02 14:30     ` [PATCH v3.2 " Jan Kratochvil
@ 2017-12-08 23:59       ` Pedro Alves
  2017-12-09  0:07         ` [pushed] Add gdb::hash_enum (Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer) Pedro Alves
  2017-12-12 16:52         ` [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
  0 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-08 23:59 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 07/02/2017 03:29 PM, Jan Kratochvil wrote:
> 
> 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.

I'm seeing a few regressions compared to .gdb_index, using
--target_board=dwarf4-gdb-index :

-PASS: gdb.base/enumval.exp: p ZERO 
+FAIL: gdb.base/enumval.exp: p ZERO 
-PASS: gdb.base/opaque.exp: ptype on opaque struct pointer (statically) 
+FAIL: gdb.base/opaque.exp: ptype on opaque struct pointer (statically) 
-PASS: gdb.base/type-opaque.exp: opaque struct type resolving 
+FAIL: gdb.base/type-opaque.exp: opaque struct type resolving 
-PASS: gdb.base/vla-stub.exp: p *local_struct.ptr 
+FAIL: gdb.base/vla-stub.exp: p *local_struct.ptr 
-PASS: gdb.cp/derivation.exp: before run: ptype A2::value_type 
-PASS: gdb.cp/derivation.exp: before run: whatis A2::value_type 
-PASS: gdb.cp/derivation.exp: before run: p (A2::value_type) 0 
-PASS: gdb.cp/derivation.exp: before run: ptype D2::value_type 
-PASS: gdb.cp/derivation.exp: before run: whatis D2::value_type 
-PASS: gdb.cp/derivation.exp: before run: p (D2::value_type) 0 
+FAIL: gdb.cp/derivation.exp: before run: ptype A2::value_type 
+FAIL: gdb.cp/derivation.exp: before run: whatis A2::value_type 
+FAIL: gdb.cp/derivation.exp: before run: p (A2::value_type) 0 
+FAIL: gdb.cp/derivation.exp: before run: ptype D2::value_type 
+FAIL: gdb.cp/derivation.exp: before run: whatis D2::value_type 
+FAIL: gdb.cp/derivation.exp: before run: p (D2::value_type) 0 

etc.  There are a few more.  That board has:

 set_board_info debug_flags "-gdwarf-4 -fdebug-types-section"

and if I remove "-fdebug-types-section", then the series
is regression-free compared to .gdb_index.  Have you seen this?

> 
> 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.
> 

Thanks!  FWIW, I found this patch quite hard to read, until
I discovered "git diff --patience" (!).  The default algorithm
makes it looks like this is changing much more code than
it is.  With "git diff --patience", I was finally able to
see that this is mostly new code.  I wish I'd known about
that switch before...

> +/* 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 addrmap *mutable_map;
> +  const CORE_ADDR baseaddr (ANOFFSET (objfile->section_offsets,
> +				      SECT_OFF_TEXT (objfile)));
> +
> +  auto_obstack temp_obstack;
> +
> +  mutable_map = addrmap_create_mutable (&temp_obstack);
> +
> +  std::unordered_map<sect_offset,
> +		     dwarf2_per_cu_data *> debug_info_offset_to_per_cu;

This doesn't compile with 5.3.1 and earlier (at least):

      In file included from /usr/include/c++/5.3.1/bits/hashtable.h:35:0,
                   from /usr/include/c++/5.3.1/unordered_set:47,
                   from src/gdb/dwarf2read.c:79:
      /usr/include/c++/5.3.1/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> >’:
      /usr/include/c++/5.3.1/type_traits:137:12:   required from ‘struct std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > >’
      /usr/include/c++/5.3.1/type_traits:148:38:   required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > > >’
      /usr/include/c++/5.3.1/bits/unordered_map.h:100:66:   required from ‘class std::unordered_map<sect_offset, dwarf2_per_cu_data*>’
      src/gdb/dwarf2read.c:3260:30:   required from here
      /usr/include/c++/5.3.1/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<sect_offset>) (const sect_offset&)’
        noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
                                    ^
      In file included from /usr/include/c++/5.3.1/bits/move.h:57:0,
                   from /usr/include/c++/5.3.1/bits/stl_pair.h:59,
                   from /usr/include/c++/5.3.1/bits/stl_algobase.h:64,
                   from /usr/include/c++/5.3.1/bits/char_traits.h:39,
                   from /usr/include/c++/5.3.1/string:40,
                   from /home/pedro/gdb/mygit/src/gdb/common/common-utils.h:23,
                   from /home/pedro/gdb/mygit/src/gdb/common/common-defs.h:78,
                   from /home/pedro/gdb/mygit/src/gdb/defs.h:28,
                   from /home/pedro/gdb/mygit/src/gdb/dwarf2read.c:31:

This is due to a C++11 language defect:
     http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148

I've fixed this by adding a gdb::hash_enum type (in a separate
preparatory patch).

> +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

.gdb_index -> .debug_names.

> -  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"

.gdb_index -> .debug_names.  I've fixed all the cases that I noticed.

> +			   " [in module %s]"),
> +			 pulongest (ull),
> +			 objfile_name (dwarf2_per_objfile->objfile));
> +	      continue;
> +	    }
> +	  per_cu = dw2_get_cutu (ull);
> +	  break;
> +	case DW_IDX_GNU_static:
> +	  if (!map.augmentation_is_gdb)
> +	    break;
> +	  have_is_static = true;
> +	  is_static = true;
> +	  break;
> +	case DW_IDX_GNU_external:
> +	  if (!map.augmentation_is_gdb)
> +	    break;
> +	  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 ();

These next() calls are recursing, which carries an implicit
assumption that this will tail call.  That doesn't seem like a
good idea to me, because we wouldn't want to risk blowing the
stack if we're testing at -O0 and end up skipping a lot
of symtabs.  I applied a minimal tweak using "goto again;" to
jump to the top again.

>  
> @@ -22903,6 +24019,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;

This should have been above the "everything else" comment.
But I've actually make dwarf2_per_objfile->debug_names_table
be a std::unique_ptr instead, so the delete is no longer
necessary.

> 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.

I've tweaked several places in the tests that I noticed
were still referencing .gdb_index only, both in comments
and in test messages.

I applied the same many editorial fixups that I
applied to the producer patch throughout, and the necessary
tweaks to adjust to current master, but otherwise the
algorithms etc. are unmodified from your original patch.

Thanks much, and below's what I pushed, generated with
"git format-patch --patience".

Let me know if I messed something up too badly.

I'll follow up with a few patches that adjust this
to handle the new symbol_name_match_type::WILD, since
currently as is, this only supports fully-qualified matching.

From 927aa2e778dce440f4de5de8fc37ead1683a804e Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Fri, 8 Dec 2017 22:44:12 +0000
Subject: [PATCH 6/9] DWARF-5: .debug_names index consumer

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.

gdb/ChangeLog:
2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Pedro Alves  <palves@redhat.com>

	* defs.h (elf_sym_fns_debug_names): New declaration.
	* dwarf2read.c: Include "hash_enum.h".
	(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_per_objfile::locate_sections): Handle debug_names and
	debug_aranges.
	(locate_dwz_sections): Handle debug_names.
	(create_signatured_type_table_from_debug_names)
	(create_addrmap_from_aranges): New.
	(dwarf2_read_index): Update function comment.
	(dwarf5_augmentation): Moved up.
	(read_debug_names_from_section, create_cus_from_debug_names_list)
	(create_cus_from_debug_names, dwarf2_read_debug_names): New.
	(dwarf5_djb_hash): Moved up.
	(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::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.
	(debug_names::djb_hash): Rename it to dwarf5_djb_hash.
	(debug_names::build): Update djb_hash caller.
	(write_debug_names): Move out and rename augmentation to
	dwarf5_augmentation.
	* 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-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Pedro Alves  <palves@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/ChangeLog                                      |   39 +
 gdb/testsuite/ChangeLog                            |   11 +
 gdb/defs.h                                         |    1 +
 gdb/dwarf2read.c                                   | 1126 +++++++++++++++++++-
 gdb/elfread.c                                      |   17 +
 gdb/psymtab.h                                      |    1 +
 gdb/symfile.h                                      |    2 +
 gdb/testsuite/gdb.base/maint.exp                   |    9 +-
 gdb/testsuite/gdb.dlang/watch-loc.c                |   20 +
 .../gdb.dwarf2/dw2-case-insensitive-debug.S        |   18 +
 gdb/testsuite/gdb.dwarf2/gdb-index.exp             |   19 +-
 gdb/testsuite/gdb.mi/dw2-ref-missing-frame-func.c  |   21 +
 gdb/xcoffread.c                                    |    2 +
 13 files changed, 1257 insertions(+), 29 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 09cafd0..ee2f1c4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,42 @@
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+	    Pedro Alves  <palves@redhat.com>
+
+	* defs.h (elf_sym_fns_debug_names): New declaration.
+	* dwarf2read.c: Include "hash_enum.h".
+	(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_per_objfile::locate_sections): Handle debug_names and
+	debug_aranges.
+	(locate_dwz_sections): Handle debug_names.
+	(create_signatured_type_table_from_debug_names)
+	(create_addrmap_from_aranges): New.
+	(dwarf2_read_index): Update function comment.
+	(dwarf5_augmentation): Moved up.
+	(read_debug_names_from_section, create_cus_from_debug_names_list)
+	(create_cus_from_debug_names, dwarf2_read_debug_names): New.
+	(dwarf5_djb_hash): Moved up.
+	(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::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.
+	(debug_names::djb_hash): Rename it to dwarf5_djb_hash.
+	(debug_names::build): Update djb_hash caller.
+	(write_debug_names): Move out and rename augmentation to
+	dwarf5_augmentation.
+	* 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.
+
 2017-12-08  Pedro Alves  <palves@redhat.com>
 
 	* common/hash_enum.h: New file.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 53a2ca4..48bad29 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
+	    Pedro Alves  <palves@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.
+
 2017-12-08  Yao Qi  <yao.qi@linaro.org>
 
 	* gdb.arch/aarch64-tagged-pointer.c (main): Update.
diff --git a/gdb/defs.h b/gdb/defs.h
index a873a55..c2e145e 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -683,6 +683,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 80d4857..ca2b04d 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -74,6 +74,7 @@
 #include "common/gdb_optional.h"
 #include "common/underlying.h"
 #include "common/byte-vector.h"
+#include "common/hash_enum.h"
 #include "filename-seen-cache.h"
 #include "producer.h"
 #include <fcntl.h>
@@ -282,6 +283,44 @@ struct mapped_index
     find_name_components_bounds (const lookup_name_info &ln_no_params) const;
 };
 
+/* A description of the mapped .debug_names.
+   Uninitialized map has CU_COUNT 0.  */
+struct mapped_debug_names
+{
+  bfd_endian dwarf5_byte_order;
+  bool dwarf5_is_dwarf64;
+  bool augmentation_is_gdb;
+  uint8_t offset_size;
+  uint32_t cu_count = 0;
+  uint32_t tu_count, bucket_count, name_count;
+  const gdb_byte *cu_table_reordered, *tu_table_reordered;
+  const uint32_t *bucket_table_reordered, *hash_table_reordered;
+  const gdb_byte *name_table_string_offs_reordered;
+  const gdb_byte *name_table_entry_offs_reordered;
+  const gdb_byte *entry_pool;
+
+  struct index_val
+  {
+    ULONGEST dwarf_tag;
+    struct attr
+    {
+      /* Attribute name DW_IDX_*.  */
+      ULONGEST dw_idx;
+
+      /* Attribute form DW_FORM_*.  */
+      ULONGEST form;
+
+      /* Value if FORM is DW_FORM_implicit_const.  */
+      LONGEST implicit_const;
+    };
+    std::vector<attr> attr_vec;
+  };
+
+  std::unordered_map<ULONGEST, index_val> abbrev_map;
+
+  const char *namei_to_name (uint32_t namei) const;
+};
+
 typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr;
 DEF_VEC_P (dwarf2_per_cu_ptr);
 
@@ -334,6 +373,8 @@ public:
   dwarf2_section_info frame {};
   dwarf2_section_info eh_frame {};
   dwarf2_section_info gdb_index {};
+  dwarf2_section_info debug_names {};
+  dwarf2_section_info debug_aranges {};
 
   VEC (dwarf2_section_info_def) *types = NULL;
 
@@ -399,6 +440,9 @@ public:
   /* The mapped index, or NULL if .gdb_index is missing or not being used.  */
   mapped_index *index_table = NULL;
 
+  /* The mapped index, or NULL if .debug_names is missing or not being used.  */
+  std::unique_ptr<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.
@@ -453,6 +497,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
 };
 
@@ -1119,6 +1165,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;
@@ -1726,6 +1773,9 @@ static const char *read_indirect_line_string (bfd *, const gdb_byte *,
 					      const struct comp_unit_head *,
 					      unsigned int *);
 
+static const char *read_indirect_string_at_offset (bfd *abfd,
+						   LONGEST str_offset);
+
 static const char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST);
 
 static LONGEST read_signed_leb128 (bfd *, const gdb_byte *, unsigned int *);
@@ -2547,6 +2597,16 @@ dwarf2_per_objfile::locate_sections (bfd *abfd, asection *sectp,
       this->gdb_index.s.section = sectp;
       this->gdb_index.size = bfd_get_section_size (sectp);
     }
+  else if (section_is_p (sectp->name, &names.debug_names))
+    {
+      this->debug_names.s.section = sectp;
+      this->debug_names.size = bfd_get_section_size (sectp);
+    }
+  else if (section_is_p (sectp->name, &names.debug_aranges))
+    {
+      this->debug_aranges.s.section = sectp;
+      this->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)
@@ -2743,6 +2803,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
@@ -3192,6 +3257,65 @@ 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)
+{
+  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);
+
+  htab_t sig_types_hash = allocate_signatured_type_table (objfile);
+
+  for (uint32_t 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.  */
 
@@ -3247,6 +3371,165 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
 						    &objfile->objfile_obstack);
 }
 
+/* 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 CORE_ADDR baseaddr = ANOFFSET (objfile->section_offsets,
+				       SECT_OFF_TEXT (objfile));
+
+  auto_obstack temp_obstack;
+  addrmap *mutable_map = addrmap_create_mutable (&temp_obstack);
+
+  std::unordered_map<sect_offset,
+		     dwarf2_per_cu_data *,
+		     gdb::hash_enum<sect_offset>>
+    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));
+	  return;
+	}
+    }
+
+  dwarf2_read_section (objfile, section);
+
+  const bfd_endian dwarf5_byte_order = gdbarch_byte_order (gdbarch);
+
+  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));
+	  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);
+	  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));
+	  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);
+	  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);
+	  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);
+	    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);
+	      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);
+}
+
 /* 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
@@ -3457,8 +3740,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
@@ -5330,6 +5612,827 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
   dw2_map_symbol_filenames
 };
 
+/* DWARF-5 debug_names reader.  */
+
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
+static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
+
+/* A helper function that reads the .debug_names section in SECTION
+   and fills in MAP.  FILENAME is the name of the file containing the
+   section; it is used for error reporting.
+
+   Returns true if all went well, false otherwise.  */
+
+static bool
+read_debug_names_from_section (struct objfile *objfile,
+			       const char *filename,
+			       struct dwarf2_section_info *section,
+			       mapped_debug_names &map)
+{
+  if (dwarf2_section_empty_p (section))
+    return false;
+
+  /* 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));
+
+  const gdb_byte *addr = section->buffer;
+
+  bfd *const abfd = get_section_bfd_owner (section);
+
+  unsigned int bytes_read;
+  LONGEST length = read_initial_length (abfd, addr, &bytes_read);
+  addr += bytes_read;
+
+  map.dwarf5_is_dwarf64 = bytes_read != 4;
+  map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4;
+  if (bytes_read + length != section->size)
+    {
+      /* There may be multiple per-CU indices.  */
+      warning (_("Section .debug_names in %s length %s does not match "
+		 "section length %s, ignoring .debug_names."),
+	       filename, plongest (bytes_read + length),
+	       pulongest (section->size));
+      return false;
+    }
+
+  /* The version number.  */
+  uint16_t version = read_2_bytes (abfd, addr);
+  addr += 2;
+  if (version != 5)
+    {
+      warning (_("Section .debug_names in %s has unsupported version %d, "
+		 "ignoring .debug_names."),
+	       filename, version);
+      return false;
+    }
+
+  /* Padding.  */
+  uint16_t padding = read_2_bytes (abfd, addr);
+  addr += 2;
+  if (padding != 0)
+    {
+      warning (_("Section .debug_names in %s has unsupported padding %d, "
+		 "ignoring .debug_names."),
+	       filename, padding);
+      return false;
+    }
+
+  /* comp_unit_count - The number of CUs in the CU list.  */
+  map.cu_count = read_4_bytes (abfd, addr);
+  addr += 4;
+
+  /* local_type_unit_count - The number of TUs in the local TU
+     list.  */
+  map.tu_count = read_4_bytes (abfd, addr);
+  addr += 4;
+
+  /* foreign_type_unit_count - The number of TUs in the foreign TU
+     list.  */
+  uint32_t foreign_tu_count = read_4_bytes (abfd, addr);
+  addr += 4;
+  if (foreign_tu_count != 0)
+    {
+      warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, "
+		 "ignoring .debug_names."),
+	       filename, static_cast<unsigned long> (foreign_tu_count));
+      return false;
+    }
+
+  /* bucket_count - The number of hash buckets in the hash lookup
+     table.  */
+  map.bucket_count = read_4_bytes (abfd, addr);
+  addr += 4;
+
+  /* name_count - The number of unique names in the index.  */
+  map.name_count = read_4_bytes (abfd, addr);
+  addr += 4;
+
+  /* abbrev_table_size - The size in bytes of the abbreviations
+     table.  */
+  uint32_t abbrev_table_size = read_4_bytes (abfd, addr);
+  addr += 4;
+
+  /* augmentation_string_size - The size in bytes of the augmentation
+     string.  This value is rounded up to a multiple of 4.  */
+  uint32_t augmentation_string_size = read_4_bytes (abfd, addr);
+  addr += 4;
+  map.augmentation_is_gdb = ((augmentation_string_size
+			      == sizeof (dwarf5_augmentation))
+			     && memcmp (addr, dwarf5_augmentation,
+					sizeof (dwarf5_augmentation)) == 0);
+  augmentation_string_size += (-augmentation_string_size) & 3;
+  addr += augmentation_string_size;
+
+  /* List of CUs */
+  map.cu_table_reordered = addr;
+  addr += map.cu_count * map.offset_size;
+
+  /* List of Local TUs */
+  map.tu_table_reordered = addr;
+  addr += map.tu_count * map.offset_size;
+
+  /* Hash Lookup Table */
+  map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+  addr += map.bucket_count * 4;
+  map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+  addr += map.name_count * 4;
+
+  /* Name Table */
+  map.name_table_string_offs_reordered = addr;
+  addr += map.name_count * map.offset_size;
+  map.name_table_entry_offs_reordered = addr;
+  addr += map.name_count * map.offset_size;
+
+  const gdb_byte *abbrev_table_start = addr;
+  for (;;)
+    {
+      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)
+	{
+	  warning (_("Section .debug_names in %s has duplicate index %s, "
+		     "ignoring .debug_names."),
+		   filename, pulongest (index_num));
+	  return false;
+	}
+      mapped_debug_names::index_val &indexval = insertpair.first->second;
+      indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read);
+      addr += bytes_read;
+
+      for (;;)
+	{
+	  mapped_debug_names::index_val::attr attr;
+	  attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read);
+	  addr += bytes_read;
+	  attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read);
+	  addr += bytes_read;
+	  if (attr.form == DW_FORM_implicit_const)
+	    {
+	      attr.implicit_const = read_signed_leb128 (abfd, addr,
+							&bytes_read);
+	      addr += bytes_read;
+	    }
+	  if (attr.dw_idx == 0 && attr.form == 0)
+	    break;
+	  indexval.attr_vec.push_back (std::move (attr));
+	}
+    }
+  if (addr != abbrev_table_start + abbrev_table_size)
+    {
+      warning (_("Section .debug_names in %s has abbreviation_table "
+                 "of size %zu vs. written as %u, ignoring .debug_names."),
+	       filename, addr - abbrev_table_start, abbrev_table_size);
+      return false;
+    }
+  map.entry_pool = addr;
+
+  return true;
+}
+
+/* A helper for create_cus_from_debug_names that handles the MAP's CU
+   list.  */
+
+static void
+create_cus_from_debug_names_list (struct objfile *objfile,
+				  const mapped_debug_names &map,
+				  dwarf2_section_info &section,
+				  bool 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)
+{
+
+  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,
+				    false /* is_dwz */,
+				    0 /* base_offset */);
+
+  if (dwz_map.cu_count == 0)
+    return;
+
+  dwz_file *dwz = dwarf2_get_dwz_file ();
+  create_cus_from_debug_names_list (objfile, dwz_map, dwz->info,
+				    true /* 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;
+
+  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_file *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)
+    {
+      /* 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;
+
+      dwarf2_section_info *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.reset (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;
+}
+
+/* Symbol name hashing function as specified by DWARF-5.  */
+
+static uint32_t
+dwarf5_djb_hash (const char *str_)
+{
+  const unsigned char *str = (const unsigned char *) str_;
+
+  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+     See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
+
+  uint32_t hash = 5381;
+  while (int c = *str++)
+    hash = hash * 33 + tolower (c);
+  return hash;
+}
+
+/* Type used to manage iterating over all CUs looking for a symbol for
+   .debug_names.  */
+
+class dw2_debug_names_iterator
+{
+public:
+  /* If WANT_SPECIFIC_BLOCK is true, 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)
+    : m_map (map), m_want_specific_block (want_specific_block),
+      m_block_index (block_index), m_domain (domain),
+      m_addr (find_vec_in_debug_names (map, name))
+  {}
+
+  dw2_debug_names_iterator (const mapped_debug_names &map,
+			    search_domain search, uint32_t namei)
+    : m_map (map),
+      m_search (search),
+      m_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 ();
+
+private:
+  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);
+
+  /* The internalized form of .debug_names.  */
+  const mapped_debug_names &m_map;
+
+  /* If true, only look for symbols that match BLOCK_INDEX.  */
+  const bool m_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 m_block_index = FIRST_LOCAL_BLOCK;
+
+  /* The kind of symbol we're looking for.  */
+  const domain_enum m_domain = UNDEF_DOMAIN;
+  const search_domain m_search = ALL_DOMAIN;
+
+  /* The list of CUs from the index entry of the symbol, or NULL if
+     not found.  */
+  const gdb_byte *m_addr;
+};
+
+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)
+{
+  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
+	 .debug_names does not contain any.  */
+
+      if (strchr (name, '(') != NULL)
+	{
+	  gdb::unique_xmalloc_ptr<char> without_params
+	    = cp_remove_params (name);
+
+	  if (without_params != NULL)
+	    {
+	      name = without_params.get();
+	    }
+	}
+    }
+
+  cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+
+  const uint32_t full_hash = dwarf5_djb_hash (name);
+  uint32_t namei
+    = extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+				(map.bucket_table_reordered
+				 + (full_hash % map.bucket_count)), 4,
+				map.dwarf5_byte_order);
+  if (namei == 0)
+    return NULL;
+  --namei;
+  if (namei >= map.name_count)
+    {
+      complaint (&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;
+    }
+
+  for (;;)
+    {
+      const uint32_t namei_full_hash
+	= extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+				    (map.hash_table_reordered + namei), 4,
+				    map.dwarf5_byte_order);
+      if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count)
+	return NULL;
+
+      if (full_hash == namei_full_hash)
+	{
+	  const char *const namei_string = map.namei_to_name (namei);
+
+#if 0 /* An expensive sanity check.  */
+	  if (namei_full_hash != dwarf5_djb_hash (namei_string))
+	    {
+	      complaint (&symfile_complaints,
+			 _("Wrong .debug_names hash for string at index %u "
+			   "[in module %s]"),
+			 namei, objfile_name (dwarf2_per_objfile->objfile));
+	      return NULL;
+	    }
+#endif
+
+	  if (cmp (namei_string, name) == 0)
+	    {
+	      const ULONGEST namei_entry_offs
+		= extract_unsigned_integer ((map.name_table_entry_offs_reordered
+					     + namei * map.offset_size),
+					    map.offset_size, map.dwarf5_byte_order);
+	      return map.entry_pool + namei_entry_offs;
+	    }
+	}
+
+      ++namei;
+      if (namei >= map.name_count)
+	return NULL;
+    }
+}
+
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+  (const mapped_debug_names &map, uint32_t namei)
+{
+  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;
+}
+
+/* See dw2_debug_names_iterator.  */
+
+dwarf2_per_cu_data *
+dw2_debug_names_iterator::next ()
+{
+  if (m_addr == NULL)
+    return NULL;
+
+  bfd *const abfd = dwarf2_per_objfile->objfile->obfd;
+
+ again:
+
+  unsigned int bytes_read;
+  const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
+  m_addr += bytes_read;
+  if (abbrev == 0)
+    return NULL;
+
+  const auto indexval_it = m_map.abbrev_map.find (abbrev);
+  if (indexval_it == m_map.abbrev_map.cend ())
+    {
+      complaint (&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, m_addr, &bytes_read);
+	  m_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,
+			 _(".debug_names 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_internal:
+	  if (!m_map.augmentation_is_gdb)
+	    break;
+	  have_is_static = true;
+	  is_static = true;
+	  break;
+	case DW_IDX_GNU_external:
+	  if (!m_map.augmentation_is_gdb)
+	    break;
+	  have_is_static = true;
+	  is_static = false;
+	  break;
+	}
+    }
+
+  /* Skip if already read in.  */
+  if (per_cu->v.quick->compunit_symtab)
+    goto again;
+
+  /* Check static vs global.  */
+  if (have_is_static)
+    {
+      const bool want_static = m_block_index != GLOBAL_BLOCK;
+      if (m_want_specific_block && want_static != is_static)
+	goto again;
+    }
+
+  /* Match dw2_symtab_iter_next, symbol_kind
+     and debug_names::psymbol_tag.  */
+  switch (m_domain)
+    {
+    case VAR_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_variable:
+	case DW_TAG_subprogram:
+	/* Some types are also in VAR_DOMAIN.  */
+	case DW_TAG_typedef:
+	case DW_TAG_structure_type:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    case STRUCT_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_typedef:
+	case DW_TAG_structure_type:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    case LABEL_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case 0:
+	case DW_TAG_variable:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    default:
+      break;
+    }
+
+  /* Match dw2_expand_symtabs_matching, symbol_kind and
+     debug_names::psymbol_tag.  */
+  switch (m_search)
+    {
+    case VARIABLES_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_variable:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    case FUNCTIONS_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_subprogram:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    case TYPES_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_typedef:
+	case DW_TAG_structure_type:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
+    default:
+      break;
+    }
+
+  return per_cu;
+}
+
+static struct compunit_symtab *
+dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int,
+			       const char *name, domain_enum domain)
+{
+  const block_enum block_index = static_cast<block_enum> (block_index_int);
+  dw2_setup (objfile);
+
+  const auto &mapp = dwarf2_per_objfile->debug_names_table;
+  if (!mapp)
+    {
+      /* index is NULL if OBJF_READNOW.  */
+      return NULL;
+    }
+  const auto &map = *mapp;
+
+  dw2_debug_names_iterator iter (map, true /* want_specific_block */,
+				 block_index, domain, name);
+
+  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);
+
+      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".  The gdb.dwarf2/gdb-index.exp testcase
+   uses this to verify that .debug_names has been loaded.  */
+
+static void
+dw2_debug_names_dump (struct objfile *objfile)
+{
+  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");
+}
+
+static void
+dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
+					     const char *func_name)
+{
+  dw2_setup (objfile);
+
+  /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW.  */
+  if (dwarf2_per_objfile->debug_names_table)
+    {
+      const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
+
+      /* Note: It doesn't matter what we pass for block_index here.  */
+      dw2_debug_names_iterator iter (map, false /* want_specific_block */,
+				     GLOBAL_BLOCK, VAR_DOMAIN, func_name);
+
+      struct dwarf2_per_cu_data *per_cu;
+      while ((per_cu = iter.next ()) != NULL)
+	dw2_instantiate_symtab (per_cu);
+    }
+}
+
+static void
+dw2_debug_names_expand_symtabs_matching
+  (struct objfile *objfile,
+   gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+   const lookup_name_info &lookup_name,
+   gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+   gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
+   enum search_domain kind)
+{
+  dw2_setup (objfile);
+
+  /* debug_names_table is NULL if OBJF_READNOW.  */
+  if (!dwarf2_per_objfile->debug_names_table)
+    return;
+
+  dw_expand_symtabs_matching_file_matcher (file_matcher);
+
+  const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
+
+  for (uint32_t namei = 0; namei < map.name_count; ++namei)
+    {
+      QUIT;
+
+      const char *const namei_string = map.namei_to_name (namei);
+      if (symbol_matcher != NULL && !symbol_matcher (namei_string))
+	continue;
+
+      /* The name was matched, now expand corresponding CUs that were
+	 marked.  */
+      dw2_debug_names_iterator iter (map, kind, namei);
+
+      struct dwarf2_per_cu_data *per_cu;
+      while ((per_cu = iter.next ()) != NULL)
+	dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+					 expansion_notify);
+    }
+}
+
+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_debug_names_lookup_symbol,
+  dw2_print_stats,
+  dw2_debug_names_dump,
+  dw2_relocate,
+  dw2_debug_names_expand_symtabs_for_function,
+  dw2_expand_all_symtabs,
+  dw2_expand_symtabs_with_fullname,
+  dw2_map_matching_symbols,
+  dw2_debug_names_expand_symtabs_matching,
+  dw2_find_pc_sect_compunit_symtab,
+  NULL,
+  dw2_map_symbol_filenames
+};
+
 /* Initialize for reading DWARF for this objfile.  Return 0 if this
    file will use psymtabs, or 1 if using the GNU index.  */
 
@@ -5365,6 +6468,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;
 
@@ -24867,22 +25973,6 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
-/* Symbol name hashing function as specified by DWARF-5.  */
-
-static uint32_t
-dwarf5_djb_hash (const char *str_)
-{
-  const unsigned char *str = (const unsigned char *) str_;
-
-  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
-     See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
-
-  uint32_t hash = 5381;
-  while (int c = *str++)
-    hash = hash * 33 + tolower (c);
-  return hash;
-}
-
 /* DWARF-5 .debug_names builder.  */
 class debug_names
 {
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 904696f..31288a9 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -1403,6 +1403,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 194dccf..e903c60 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -582,6 +582,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..8d1a4d0 100644
--- a/gdb/testsuite/gdb.base/maint.exp
+++ b/gdb/testsuite/gdb.base/maint.exp
@@ -89,10 +89,13 @@ if ![runto_main] then {
         perror "tests suppressed"
 }
 
-# If we're using .gdb_index there will be no psymtabs.
+# If we're using .gdb_index or .debug_names 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..3b993db 100644
--- a/gdb/testsuite/gdb.dlang/watch-loc.c
+++ b/gdb/testsuite/gdb.dlang/watch-loc.c
@@ -34,3 +34,23 @@ main (void)
   return _Dmain ();
 }
 
+/* The .debug_names-based index support depends on .debug_aranges
+   generated by GCC.  (.gdb_index includes a gdb-generated map
+   instead.)  */
+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..ad19f81 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
+++ b/gdb/testsuite/gdb.dwarf2/dw2-case-insensitive-debug.S
@@ -57,6 +57,24 @@
 	.byte		0			/* End of children of CU */
 .Lcu1_end:
 
+	/* The .debug_names-based index support depends on
+	   .debug_aranges generated by GCC.  (.gdb_index includes a
+	   gdb-generated map instead.)	*/
+	.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..c7ddbbf 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
@@ -58,7 +58,7 @@ proc add_gdb_index { program } {
     return ${program_with_index}
 }
 
-# Build a copy of the program with .gdb_index.
+# Build a copy of the program with an index (.gdb_index/.debug_names).
 # But only if the toolchain didn't already create one: gdb doesn't support
 # building an index from a program already using one.
 
@@ -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} == "" } {
@@ -75,16 +78,16 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
     }
 }
 
-# Ok, we have a copy of $binfile with .gdb_index.
+# Ok, we have a copy of $binfile with an index.
 # Restart gdb and verify the index was used.
 
 clean_restart ${binfile_with_index}
 gdb_test "mt print objfiles ${testfile}" \
-    "gdb_index.*" \
-    ".gdb_index used"
+    "(gdb_index|debug_names).*" \
+    "index used"
 
-# Make gdb re-read symbols and see if .gdb_index still gets used.
-# symtab/15885
+# Make gdb re-read symbols and see if .gdb_index/.debug_names still
+# gets used.  symtab/15885
 
 # There is gdb_touch_execfile, but it doesn't handle remote hosts.
 # Is touch portable enough?
@@ -98,5 +101,5 @@ if ![runto_main] {
     return -1
 }
 gdb_test "mt print objfiles ${testfile}" \
-    "gdb_index.*" \
-    ".gdb_index used after symbol reloading"
+    "(gdb_index|debug_names).*" \
+    "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..785cf43 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,24 @@ asm ("func_loopfb_end:");
 
 asm (".globl cu_text_end");
 asm ("cu_text_end:");
+
+/* The .debug_names-based index support depends on .debug_aranges
+   generated by GCC.  (.gdb_index includes a gdb-generated map
+   instead.)  */
+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 b1c634c..142845b 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
 };
 
-- 
2.5.5


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

* [pushed] Add gdb::hash_enum (Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer)
  2017-12-08 23:59       ` Pedro Alves
@ 2017-12-09  0:07         ` Pedro Alves
  2017-12-12 16:52         ` [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
  1 sibling, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-09  0:07 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 12/08/2017 11:58 PM, Pedro Alves wrote:

>> +  std::unordered_map<sect_offset,
>> +		     dwarf2_per_cu_data *> debug_info_offset_to_per_cu;
> 
> This doesn't compile with 5.3.1 and earlier (at least):
> 
>       In file included from /usr/include/c++/5.3.1/bits/hashtable.h:35:0,
>                    from /usr/include/c++/5.3.1/unordered_set:47,
>                    from src/gdb/dwarf2read.c:79:
>       /usr/include/c++/5.3.1/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> >’:
>       /usr/include/c++/5.3.1/type_traits:137:12:   required from ‘struct std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > >’
>       /usr/include/c++/5.3.1/type_traits:148:38:   required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > > >’
>       /usr/include/c++/5.3.1/bits/unordered_map.h:100:66:   required from ‘class std::unordered_map<sect_offset, dwarf2_per_cu_data*>’
>       src/gdb/dwarf2read.c:3260:30:   required from here
>       /usr/include/c++/5.3.1/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<sect_offset>) (const sect_offset&)’
>         noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
>                                     ^
>       In file included from /usr/include/c++/5.3.1/bits/move.h:57:0,
>                    from /usr/include/c++/5.3.1/bits/stl_pair.h:59,
>                    from /usr/include/c++/5.3.1/bits/stl_algobase.h:64,
>                    from /usr/include/c++/5.3.1/bits/char_traits.h:39,
>                    from /usr/include/c++/5.3.1/string:40,
>                    from /home/pedro/gdb/mygit/src/gdb/common/common-utils.h:23,
>                    from /home/pedro/gdb/mygit/src/gdb/common/common-defs.h:78,
>                    from /home/pedro/gdb/mygit/src/gdb/defs.h:28,
>                    from /home/pedro/gdb/mygit/src/gdb/dwarf2read.c:31:
> 
> This is due to a C++11 language defect:
>      http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148
> 
> I've fixed this by adding a gdb::hash_enum type (in a separate
> preparatory patch).

I almost forgot to post this one.  Here it is.

From e5fa6583a7b1e5e0e0f33a4964a1f271e189cf35 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 8 Dec 2017 22:44:12 +0000
Subject: [PATCH 5/9] Add gdb::hash_enum
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The DWARF-5 .debug_names consumer patch will want to use an
std::unordered_map with an enum as key type, like:

	std::unordered_map<sect_offset, dwarf2_per_cu_data*>

That doesn't work in C++11 in non-recent compilers due to a language
defect:

 http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148

~~~
  In file included from /usr/include/c++/5.3.1/bits/hashtable.h:35:0,
		   from /usr/include/c++/5.3.1/unordered_set:47,
		   from src/gdb/dwarf2read.c:79:
  /usr/include/c++/5.3.1/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> >’:
  /usr/include/c++/5.3.1/type_traits:137:12:   required from ‘struct std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > >’
  /usr/include/c++/5.3.1/type_traits:148:38:   required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<sect_offset> >, std::__detail::__is_noexcept_hash<sect_offset, std::hash<sect_offset> > > >’
  /usr/include/c++/5.3.1/bits/unordered_map.h:100:66:   required from ‘class std::unordered_map<sect_offset, dwarf2_per_cu_data*>’
  src/gdb/dwarf2read.c:3260:30:   required from here
  /usr/include/c++/5.3.1/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<sect_offset>) (const sect_offset&)’
    noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
				    ^
  In file included from /usr/include/c++/5.3.1/bits/move.h:57:0,
		   from /usr/include/c++/5.3.1/bits/stl_pair.h:59,
		   from /usr/include/c++/5.3.1/bits/stl_algobase.h:64,
		   from /usr/include/c++/5.3.1/bits/char_traits.h:39,
		   from /usr/include/c++/5.3.1/string:40,
		   from /home/pedro/gdb/mygit/src/gdb/common/common-utils.h:23,
		   from /home/pedro/gdb/mygit/src/gdb/common/common-defs.h:78,
		   from /home/pedro/gdb/mygit/src/gdb/defs.h:28,
		   from /home/pedro/gdb/mygit/src/gdb/dwarf2read.c:31:
~~~

This commits adds a helper replacement.

gdb/ChangeLog:
2017-12-08  Pedro Alves  <palves@redhat.com>

	* common/hash_enum.h: New file.
---
 gdb/ChangeLog          |  4 ++++
 gdb/common/hash_enum.h | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 gdb/common/hash_enum.h

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5d596f0..09cafd0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2017-12-08  Pedro Alves  <palves@redhat.com>
+
+	* common/hash_enum.h: New file.
+
 2017-12-08  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* dwarf2read.c (create_cu_from_index_list): New from ...
diff --git a/gdb/common/hash_enum.h b/gdb/common/hash_enum.h
new file mode 100644
index 0000000..0ea3221
--- /dev/null
+++ b/gdb/common/hash_enum.h
@@ -0,0 +1,45 @@
+/* A hasher for enums.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef COMMON_HASH_ENUM_H
+#define COMMON_HASH_ENUM_H
+
+/* A hasher for enums, which was missing in C++11:
+    http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148
+*/
+
+namespace gdb {
+
+/* Helper struct for hashing enum types.  */
+template<typename T>
+struct hash_enum
+{
+  typedef size_t result_type;
+  typedef T argument_type;
+
+  size_t operator() (T val) const noexcept
+  {
+    using underlying = typename std::underlying_type<T>::type;
+    return std::hash<underlying> () (static_cast<underlying> (val));
+  }
+};
+
+} /* namespace gdb */
+
+#endif /* COMMON_HASH_ENUM_H */
-- 
2.5.5


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

* Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-12-08 23:52   ` Pedro Alves
@ 2017-12-11 13:04     ` Yao Qi
  2017-12-11 13:20       ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Yao Qi @ 2017-12-11 13:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Jan Kratochvil, GDB Patches, Victor Leschuk

On Fri, Dec 8, 2017 at 11:52 PM, Pedro Alves <palves@redhat.com> wrote:
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index a9daf1f..798af72 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -5291,7 +5291,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
> @@ -5320,13 +5320,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;
>  }
>

This breaks the arm-wince-pe build,

dwarf2read.o: In function `dwarf2_initialize_objfile(objfile*)':
/home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6486:
undefined reference to `elf_sym_fns_gdb_index'
/home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6490:
undefined reference to `elf_sym_fns_debug_names'
/home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6495:
undefined reference to `elf_sym_fns_lazy_psyms'
collect2: error: ld returned 1 exit status
Makefile:1920: recipe for target 'gdb' failed

https://ci.linaro.org/job/tcwg-binutils/4395/

-- 
Yao (齐尧)

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

* Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-12-11 13:04     ` Yao Qi
@ 2017-12-11 13:20       ` Pedro Alves
  2017-12-11 14:00         ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-12-11 13:20 UTC (permalink / raw)
  To: Yao Qi; +Cc: Jan Kratochvil, GDB Patches, Victor Leschuk

On 12/11/2017 01:03 PM, Yao Qi wrote:

> This breaks the arm-wince-pe build,
> 
> dwarf2read.o: In function `dwarf2_initialize_objfile(objfile*)':
> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6486:
> undefined reference to `elf_sym_fns_gdb_index'
> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6490:
> undefined reference to `elf_sym_fns_debug_names'
> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6495:
> undefined reference to `elf_sym_fns_lazy_psyms'
> collect2: error: ld returned 1 exit status
> Makefile:1920: recipe for target 'gdb' failed
> 
> https://ci.linaro.org/job/tcwg-binutils/4395/
> 

Eh, looks like the bridge was closer than I realized...  I forgot
the non-elf ports don't include elfread.c in the build.  So we
really need to do something else here.  Maybe an enum instead of
the original boolean.

Thanks,
Pedro Alves

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

* Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value
  2017-12-11 13:20       ` Pedro Alves
@ 2017-12-11 14:00         ` Pedro Alves
  2017-12-11 15:08           ` [pushed] Unbreak build for non-ELF ports (Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value) Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-12-11 14:00 UTC (permalink / raw)
  To: Yao Qi; +Cc: Jan Kratochvil, GDB Patches, Victor Leschuk

On 12/11/2017 01:20 PM, Pedro Alves wrote:
> On 12/11/2017 01:03 PM, Yao Qi wrote:
> 
>> This breaks the arm-wince-pe build,
>>
>> dwarf2read.o: In function `dwarf2_initialize_objfile(objfile*)':
>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6486:
>> undefined reference to `elf_sym_fns_gdb_index'
>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6490:
>> undefined reference to `elf_sym_fns_debug_names'
>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6495:
>> undefined reference to `elf_sym_fns_lazy_psyms'
>> collect2: error: ld returned 1 exit status
>> Makefile:1920: recipe for target 'gdb' failed
>>
>> https://ci.linaro.org/job/tcwg-binutils/4395/
>>
> 
> Eh, looks like the bridge was closer than I realized...  I forgot
> the non-elf ports don't include elfread.c in the build.  So we
> really need to do something else here.  Maybe an enum instead of
> the original boolean.

Something like this.  I had already added a boolean for the index
variant to dwarf2read.c, so this reuses that.

I haven't tried to build for --target=arm-wince-pe yet, but this
probably works.  I'll get back to this in a bit when I have a chance.

From 223c6e730f2f85ca4732335964b616006974e078 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 11 Dec 2017 13:24:32 +0000
Subject: [PATCH] Unbreak non-ELF ports

---
 gdb/dwarf2read.c | 32 ++++++++++++++------------------
 gdb/elfread.c    | 29 +++++++++++++++++++++++------
 gdb/symfile.h    | 17 ++++++++++++++++-
 3 files changed, 53 insertions(+), 25 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 2aeb506..b4e60a4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6451,11 +6451,10 @@ const struct quick_symbol_functions dwarf2_debug_names_functions =
   dw2_map_symbol_filenames
 };
 
-/* Initialize for reading DWARF for this objfile.  Return 0 if this
-   file will use psymtabs, or 1 if using the GNU index.  */
+/* See symfile.h.  */
 
-const sym_fns &
-dwarf2_initialize_objfile (struct objfile *objfile)
+bool
+dwarf2_initialize_objfile (struct objfile *objfile, dw_index_kind *index_kind)
 {
   /* If we're about to read full symbols, don't bother with the
      indices.  In this case we also don't care if some other debug
@@ -6483,16 +6482,23 @@ 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 elf_sym_fns_gdb_index;
+      *index_kind = dw_index_kind::GDB_INDEX;
+      return true;
     }
 
   if (dwarf2_read_debug_names (objfile))
-    return elf_sym_fns_debug_names;
+    {
+      *index_kind = dw_index_kind::DEBUG_NAMES;
+      return true;
+    }
 
   if (dwarf2_read_index (objfile))
-    return elf_sym_fns_gdb_index;
+    {
+      *index_kind = dw_index_kind::GDB_INDEX;
+      return true;
+    }
 
-  return elf_sym_fns_lazy_psyms;
+  return false;
 }
 
 \f
@@ -26799,16 +26805,6 @@ assert_file_size (FILE *file, const char *filename, size_t expected_size)
   gdb_assert (file_size == expected_size);
 }
 
-/* An index variant.  */
-enum dw_index_kind
-{
-  /* GDB's own .gdb_index format.   */
-  GDB_INDEX,
-
-  /* DWARF5 .debug_names.  */
-  DEBUG_NAMES,
-};
-
 /* Create an index file for OBJFILE in the directory DIR.  */
 
 static void
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 31288a9..7a41c26 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -48,6 +48,11 @@
 #include "location.h"
 #include "auxv.h"
 
+/* Forward declarations.  */
+extern const struct sym_fns elf_sym_fns_gdb_index;
+extern const struct sym_fns elf_sym_fns_debug_names;
+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.  */
@@ -1211,11 +1216,25 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 
   if (dwarf2_has_info (objfile, NULL))
     {
-      /* elf_sym_fns_gdb_index cannot handle simultaneous non-DWARF debug
-	 information present in OBJFILE.  If there is such debug info present
-	 never use .gdb_index.  */
+      dw_index_kind index_kind;
 
-      if (objfile_has_partial_symbols (objfile))
+      /* elf_sym_fns_gdb_index cannot handle simultaneous non-DWARF
+	 debug information present in OBJFILE.  If there is such debug
+	 info present never use an index.  */
+      if (!objfile_has_partial_symbols (objfile)
+	  && dwarf2_initialize_objfile (objfile, &index_kind))
+	{
+	  switch (index_kind)
+	    {
+	    case dw_index_kind::GDB_INDEX:
+	      objfile_set_sym_fns (objfile, &elf_sym_fns_gdb_index);
+	      break;
+	    case dw_index_kind::DEBUG_NAMES:
+	      objfile_set_sym_fns (objfile, &elf_sym_fns_debug_names);
+	      break;
+	    }
+	}
+      else
 	{
 	  /* It is ok to do this even if the stabs reader made some
 	     partial symbols, because OBJF_PSYMTABS_READ has not been
@@ -1223,8 +1242,6 @@ 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 e903c60..93fbe68 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -603,7 +603,22 @@ extern void dwarf2_get_section_info (struct objfile *,
 				     asection **, const gdb_byte **,
 				     bfd_size_type *);
 
-extern const sym_fns &dwarf2_initialize_objfile (struct objfile *);
+/* A DWARF names index variant.  */
+enum class dw_index_kind
+{
+  /* GDB's own .gdb_index format.   */
+  GDB_INDEX,
+
+  /* DWARF5 .debug_names.  */
+  DEBUG_NAMES,
+};
+
+/* Initialize for reading DWARF for OBJFILE.  Return false if this
+   file will use psymtabs, or true if using an index, in which case
+   *INDEX_KIND is set to the index variant in use.  */
+extern bool dwarf2_initialize_objfile (struct objfile *objfile,
+				       dw_index_kind *index_kind);
+
 extern void dwarf2_build_psymtabs (struct objfile *);
 extern void dwarf2_build_frame_info (struct objfile *);
 
-- 
2.5.5


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

* [pushed] Unbreak build for non-ELF ports (Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value)
  2017-12-11 14:00         ` Pedro Alves
@ 2017-12-11 15:08           ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-12-11 15:08 UTC (permalink / raw)
  To: Yao Qi; +Cc: Jan Kratochvil, GDB Patches, Victor Leschuk

On 12/11/2017 01:59 PM, Pedro Alves wrote:
> On 12/11/2017 01:20 PM, Pedro Alves wrote:
>> On 12/11/2017 01:03 PM, Yao Qi wrote:
>>
>>> This breaks the arm-wince-pe build,
>>>
>>> dwarf2read.o: In function `dwarf2_initialize_objfile(objfile*)':
>>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6486:
>>> undefined reference to `elf_sym_fns_gdb_index'
>>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6490:
>>> undefined reference to `elf_sym_fns_debug_names'
>>> /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6495:
>>> undefined reference to `elf_sym_fns_lazy_psyms'
>>> collect2: error: ld returned 1 exit status
>>> Makefile:1920: recipe for target 'gdb' failed
>>>
>>> https://ci.linaro.org/job/tcwg-binutils/4395/
>>>
>>
>> Eh, looks like the bridge was closer than I realized...  I forgot
>> the non-elf ports don't include elfread.c in the build.  So we
>> really need to do something else here.  Maybe an enum instead of
>> the original boolean.
> 
> Something like this.  I had already added a boolean for the index
> variant to dwarf2read.c, so this reuses that.
> 
> I haven't tried to build for --target=arm-wince-pe yet, but this
> probably works.  I'll get back to this in a bit when I have a chance.
> 

OK, confirmed now that this fixes the build for --target=arm-wince-pe,
and confirmed on x86-64 GNU/Linux that both .gdb_index and .debug_names
indexes continue working.  Below's what I pushed.

From 3c0aa29aab3949363f8b23d062c2e0cb1ccf017a Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 11 Dec 2017 13:24:32 +0000
Subject: [PATCH] Unbreak build for non-ELF ports

As reported at
<https://sourceware.org/ml/gdb-patches/2017-12/msg00229.html>, this
commit:

~~~~
 commit abccd1e7b7a37385159610ca4e0bc2632a547e9a
 Author:     Jan Kratochvil <jan.kratochvil@redhat.com>
 AuthorDate: Fri Dec 8 22:44:11 2017 +0000

     Change dwarf2_initialize_objfile's return value

     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.
~~~~

breaks non-ELF-target builds:

 dwarf2read.o: In function `dwarf2_initialize_objfile(objfile*)':
 /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6486:
 undefined reference to `elf_sym_fns_gdb_index'
 /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6490:
 undefined reference to `elf_sym_fns_debug_names'
 /home/yao.qi/SourceCode/gnu/binutils-gdb/gdb/dwarf2read.c:6495:
 undefined reference to `elf_sym_fns_lazy_psyms'
 collect2: error: ld returned 1 exit status
	 Makefile:1920: recipe for target 'gdb' failed

because gdb/elfread.c is not included in the gdb build unless bfd also
includes elf support.

Fix this by reverting the patch mentioned above and at the same time
re-adding .debug_names support by adding a new output parameter to
dwarf2_initialize_objfile to indicate the index variant in use.  We
can reuse the new dw_index_kind enum in dwarf2read.c for that.

gdb/ChangeLog:
2017-12-11  Pedro Alves  <palves@redhat.com>

	* defs.h (elf_sym_fns_lazy_psyms, elf_sym_fns_gdb_index)
	(elf_sym_fns_debug_names): Move to elfread.c.
	* dwarf2read.c (dwarf2_initialize_objfile): Return a boolean
	instead of a sym_fns and add 'index_kind' output parameter.  Fill
	the latter in with the index variant kind if using an index.
	(enum dw_index_kind): Moved to symfile.h.
	* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_debug_names)
	(elf_sym_fns_lazy_psyms): Move from defs.h.
	(elf_symfile_read): Adjust to new dwarf2_initialize_objfile
	interface.
	* symfile.h (enum class dw_index_kind): New, moved from
	dwarf2read.c.
	(dwarf2_initialize_objfile): Change prototype.
---
 gdb/ChangeLog    | 16 ++++++++++++++++
 gdb/defs.h       |  6 ------
 gdb/dwarf2read.c | 32 ++++++++++++++------------------
 gdb/elfread.c    | 29 +++++++++++++++++++++++------
 gdb/symfile.h    | 17 ++++++++++++++++-
 5 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b3c5b97..78fd713 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,19 @@
+2017-12-11  Pedro Alves  <palves@redhat.com>
+
+	* defs.h (elf_sym_fns_lazy_psyms, elf_sym_fns_gdb_index)
+	(elf_sym_fns_debug_names): Move to elfread.c.
+	* dwarf2read.c (dwarf2_initialize_objfile): Return a boolean
+	instead of a sym_fns and add 'index_kind' output parameter.  Fill
+	the latter in with the index variant kind if using an index.
+	(enum dw_index_kind): Moved to symfile.h.
+	* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_debug_names)
+	(elf_sym_fns_lazy_psyms): Move from defs.h.
+	(elf_symfile_read): Adjust to new dwarf2_initialize_objfile
+	interface.
+	* symfile.h (enum class dw_index_kind): New, moved from
+	dwarf2read.c.
+	(dwarf2_initialize_objfile): Change prototype.
+
 2017-12-11  Ulrich Weigand  <uweigand@de.ibm.com>
 
 	* target-float.c (mpfr_float_ops::from_target): Use mpfr_set_ui
diff --git a/gdb/defs.h b/gdb/defs.h
index c2e145e..f76293f 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -679,12 +679,6 @@ 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;
-extern const struct sym_fns elf_sym_fns_debug_names;
-
 /* * Special block numbers */
 
 enum block_enum
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 2aeb506..b4e60a4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6451,11 +6451,10 @@ const struct quick_symbol_functions dwarf2_debug_names_functions =
   dw2_map_symbol_filenames
 };
 
-/* Initialize for reading DWARF for this objfile.  Return 0 if this
-   file will use psymtabs, or 1 if using the GNU index.  */
+/* See symfile.h.  */
 
-const sym_fns &
-dwarf2_initialize_objfile (struct objfile *objfile)
+bool
+dwarf2_initialize_objfile (struct objfile *objfile, dw_index_kind *index_kind)
 {
   /* If we're about to read full symbols, don't bother with the
      indices.  In this case we also don't care if some other debug
@@ -6483,16 +6482,23 @@ 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 elf_sym_fns_gdb_index;
+      *index_kind = dw_index_kind::GDB_INDEX;
+      return true;
     }
 
   if (dwarf2_read_debug_names (objfile))
-    return elf_sym_fns_debug_names;
+    {
+      *index_kind = dw_index_kind::DEBUG_NAMES;
+      return true;
+    }
 
   if (dwarf2_read_index (objfile))
-    return elf_sym_fns_gdb_index;
+    {
+      *index_kind = dw_index_kind::GDB_INDEX;
+      return true;
+    }
 
-  return elf_sym_fns_lazy_psyms;
+  return false;
 }
 
 \f
@@ -26799,16 +26805,6 @@ assert_file_size (FILE *file, const char *filename, size_t expected_size)
   gdb_assert (file_size == expected_size);
 }
 
-/* An index variant.  */
-enum dw_index_kind
-{
-  /* GDB's own .gdb_index format.   */
-  GDB_INDEX,
-
-  /* DWARF5 .debug_names.  */
-  DEBUG_NAMES,
-};
-
 /* Create an index file for OBJFILE in the directory DIR.  */
 
 static void
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 31288a9..7a41c26 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -48,6 +48,11 @@
 #include "location.h"
 #include "auxv.h"
 
+/* Forward declarations.  */
+extern const struct sym_fns elf_sym_fns_gdb_index;
+extern const struct sym_fns elf_sym_fns_debug_names;
+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.  */
@@ -1211,11 +1216,25 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 
   if (dwarf2_has_info (objfile, NULL))
     {
-      /* elf_sym_fns_gdb_index cannot handle simultaneous non-DWARF debug
-	 information present in OBJFILE.  If there is such debug info present
-	 never use .gdb_index.  */
+      dw_index_kind index_kind;
 
-      if (objfile_has_partial_symbols (objfile))
+      /* elf_sym_fns_gdb_index cannot handle simultaneous non-DWARF
+	 debug information present in OBJFILE.  If there is such debug
+	 info present never use an index.  */
+      if (!objfile_has_partial_symbols (objfile)
+	  && dwarf2_initialize_objfile (objfile, &index_kind))
+	{
+	  switch (index_kind)
+	    {
+	    case dw_index_kind::GDB_INDEX:
+	      objfile_set_sym_fns (objfile, &elf_sym_fns_gdb_index);
+	      break;
+	    case dw_index_kind::DEBUG_NAMES:
+	      objfile_set_sym_fns (objfile, &elf_sym_fns_debug_names);
+	      break;
+	    }
+	}
+      else
 	{
 	  /* It is ok to do this even if the stabs reader made some
 	     partial symbols, because OBJF_PSYMTABS_READ has not been
@@ -1223,8 +1242,6 @@ 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 e903c60..93fbe68 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -603,7 +603,22 @@ extern void dwarf2_get_section_info (struct objfile *,
 				     asection **, const gdb_byte **,
 				     bfd_size_type *);
 
-extern const sym_fns &dwarf2_initialize_objfile (struct objfile *);
+/* A DWARF names index variant.  */
+enum class dw_index_kind
+{
+  /* GDB's own .gdb_index format.   */
+  GDB_INDEX,
+
+  /* DWARF5 .debug_names.  */
+  DEBUG_NAMES,
+};
+
+/* Initialize for reading DWARF for OBJFILE.  Return false if this
+   file will use psymtabs, or true if using an index, in which case
+   *INDEX_KIND is set to the index variant in use.  */
+extern bool dwarf2_initialize_objfile (struct objfile *objfile,
+				       dw_index_kind *index_kind);
+
 extern void dwarf2_build_psymtabs (struct objfile *);
 extern void dwarf2_build_frame_info (struct objfile *);
 
-- 
2.5.5


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

* Re: [PATCH v3.2 2/5] DWARF-5: .debug_names index producer
  2017-12-08 23:51           ` Pedro Alves
@ 2017-12-12 15:38             ` Jan Kratochvil
  2017-12-31  3:52             ` Simon Marchi
  1 sibling, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-12-12 15:38 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Eli Zaretskii, gdb-patches, vleschuk

On Sat, 09 Dec 2017 00:51:38 +0100, Pedro Alves wrote:
> When I started looking at this in detail this week, I was
> a bit surprised to learn that the names table is essentially the
> same as .gdb_index's, meaning full-qualified names with no
> overload/parameter info, and especially -- no indication
> of which language the name is for, which was a nuisance
> for making C++ wildmatching support work with .gdb_index.
> Somehow I had the impression that it was different from
> earlier chats.  OTOH, the upside is that that we'll manage
> to reuse the mapped_index::name_components code for .debug_names.

The features of splitting the components of fully qualified names was planned
as an add-on patch on top of this one.  Although GDB did not have real support
for that when I was writing this patchset and I expected it would be then
written more as a part of that components support even for the .debug_names
index.  The goal of the initial .debug_names implementation was to match
.gdb_index.


> > +      if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
> > +	return true;
> 
> These look like always return false, since per_cu.sect_off is 32-bit?
> I've left it as is, but it doesn't look right to me.  Seems like
> that makes all the 64-bit support dead as is.

I did not know GDB does not support 64-bit DWARF now:

/* * Offset relative to the start of its .debug_info or .debug_types
   section.  */
DEFINE_OFFSET_TYPE (sect_offset, unsigned int);


Jan

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

* Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer
  2017-12-08 23:59       ` Pedro Alves
  2017-12-09  0:07         ` [pushed] Add gdb::hash_enum (Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer) Pedro Alves
@ 2017-12-12 16:52         ` Jan Kratochvil
  2017-12-13 21:57           ` [patch] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer] Jan Kratochvil
  1 sibling, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-12-12 16:52 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Victor Leschuk

On Sat, 09 Dec 2017 00:58:47 +0100, Pedro Alves wrote:
> I'm seeing a few regressions compared to .gdb_index, using
> --target_board=dwarf4-gdb-index :
> 
> -PASS: gdb.base/enumval.exp: p ZERO 
> +FAIL: gdb.base/enumval.exp: p ZERO 
...
> etc.  There are a few more.  That board has:
> 
>  set_board_info debug_flags "-gdwarf-4 -fdebug-types-section"
> 
> and if I remove "-fdebug-types-section", then the series
> is regression-free compared to .gdb_index.  Have you seen this?

I have it reproducible even on my original development branch.

I do not know how it slipped through, I was testing -fdebug-types-section.

The .debug_names completely misses its support as it does not even produce
DW_IDX_type_unit.  But I will be able to fix it only in January.


Jan

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

* [patch] DWARF-5 .debug_names DW_IDX_type_unit fix  [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer]
  2017-12-12 16:52         ` [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
@ 2017-12-13 21:57           ` Jan Kratochvil
  2017-12-13 22:16             ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-12-13 21:57 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Victor Leschuk

[-- Attachment #1: Type: text/plain, Size: 753 bytes --]

On Tue, 12 Dec 2017 17:52:21 +0100, Jan Kratochvil wrote:
> On Sat, 09 Dec 2017 00:58:47 +0100, Pedro Alves wrote:
> > I'm seeing a few regressions compared to .gdb_index, using
> > --target_board=dwarf4-gdb-index :
> > 
> > -PASS: gdb.base/enumval.exp: p ZERO 
> > +FAIL: gdb.base/enumval.exp: p ZERO 
> ...
> > etc.  There are a few more.  That board has:
> > 
> >  set_board_info debug_flags "-gdwarf-4 -fdebug-types-section"
> > 
> > and if I remove "-fdebug-types-section", then the series
> > is regression-free compared to .gdb_index.  Have you seen this?
...
> The .debug_names completely misses its support as it does not even produce
> DW_IDX_type_unit.

Here you are, could you also verify my regression testing for this patch?


Thanks,
Jan

[-- Attachment #2: dwarf5fix.patch --]
[-- Type: text/plain, Size: 10050 bytes --]

gdb/ChangeLog
2017-12-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* dwarf2read.c (dw2_debug_names_iterator::next): Support
	DW_IDX_type_unit.
	(debug_names::dwarf5_offset_size, unit_kind): New.
	(debug_names::insert): Add parameter kind.
	(debug_names::build): Support DW_IDX_type_unit.
	(debug_names::recursively_write_psymbols): Update
	(debug_names::write_psymbols caller.
	(debug_names::write_one_signatured_type_data)
	(debug_names::write_one_signatured_type): New.
	(debug_names::index_key, debug_names::symbol_value)
	(debug_names::write_psymbols): Add kind.
	(debug_names::write_one_signatured_type): New.
	(write_debug_names): Move dwarf5_offset_size to debug_names.
	Use debug_names::write_one_signatured_type for type units.

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b4e60a4409..e65eac7acd 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6192,8 +6192,7 @@ dw2_debug_names_iterator::next ()
 	{
 	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))
+	  if (ull >= dwarf2_per_objfile->n_comp_units)
 	    {
 	      complaint (&symfile_complaints,
 			 _(".debug_names entry has bad CU index %s"
@@ -6204,6 +6203,19 @@ dw2_debug_names_iterator::next ()
 	    }
 	  per_cu = dw2_get_cutu (ull);
 	  break;
+	case DW_IDX_type_unit:
+	  /* Don't crash on bad data.  */
+	  if (ull >= dwarf2_per_objfile->n_type_units)
+	    {
+	      complaint (&symfile_complaints,
+			 _(".debug_names entry has bad TU index %s"
+			   " [in module %s]"),
+			 pulongest (ull),
+			 objfile_name (dwarf2_per_objfile->objfile));
+	      continue;
+	    }
+	  per_cu = dw2_get_cutu (dwarf2_per_objfile->n_comp_units + ull);
+	  break;
 	case DW_IDX_GNU_internal:
 	  if (!m_map.augmentation_is_gdb)
 	    break;
@@ -26012,8 +26024,17 @@ public:
       m_name_table_entry_offs (m_dwarf.name_table_entry_offs)
   {}
 
+  int dwarf5_offset_size () const {
+    const bool dwarf5_is_dwarf64 = &m_dwarf == &m_dwarf64;
+    return dwarf5_is_dwarf64 ? 8 : 4;
+  }
+
+  /* Is this symbol from DW_TAG_compile_unit or DW_TAG_type_unit?  */
+  enum class unit_kind { cu, tu };
+
   /* Insert one symbol.  */
-  void insert (const partial_symbol *psym, int cu_index, bool is_static)
+  void insert (const partial_symbol *psym, int cu_index, bool is_static,
+	       unit_kind kind)
   {
     const int dwarf_tag = psymbol_tag (psym);
     if (dwarf_tag == 0)
@@ -26023,7 +26044,7 @@ public:
       = 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));
+    value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static, kind));
   }
 
   /* Build all the tables.  All symbols must be already inserted.
@@ -26088,13 +26109,16 @@ public:
 	    for (const symbol_value &value : value_set)
 	      {
 		int &idx = m_indexkey_to_idx[index_key (value.dwarf_tag,
-							value.is_static)];
+							value.is_static,
+							value.kind)];
 		if (idx == 0)
 		  {
 		    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
+			      (value.kind == unit_kind::cu ? DW_IDX_compile_unit
+							   : DW_IDX_type_unit);
 		    m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
 		    m_abbrev_table.append_unsigned_leb128 (value.is_static
 							   ? DW_IDX_GNU_internal
@@ -26169,10 +26193,10 @@ public:
 
     write_psymbols (psyms_seen,
 		    &objfile->global_psymbols[psymtab->globals_offset],
-		    psymtab->n_global_syms, cu_index, false);
+		    psymtab->n_global_syms, cu_index, false, unit_kind::cu);
     write_psymbols (psyms_seen,
 		    &objfile->static_psymbols[psymtab->statics_offset],
-		    psymtab->n_static_syms, cu_index, true);
+		    psymtab->n_static_syms, cu_index, true, unit_kind::cu);
   }
 
   /* Return number of bytes the .debug_names section will have.  This
@@ -26207,6 +26231,30 @@ public:
     m_debugstrlookup.file_write (file_str);
   }
 
+  /* A helper user data for write_one_signatured_type.  */
+  class write_one_signatured_type_data
+  {
+  public:
+    write_one_signatured_type_data (debug_names &nametable_,
+                                    signatured_type_index_data &&info_)
+    : nametable (nametable_), info (std::move (info_))
+    {}
+    debug_names &nametable;
+    struct signatured_type_index_data info;
+  };
+
+  /* A helper function to pass write_one_signatured_type to
+     htab_traverse_noresize.  */
+  static int
+  write_one_signatured_type (void **slot, void *d)
+  {
+    write_one_signatured_type_data *data = (write_one_signatured_type_data *) d;
+    struct signatured_type_index_data *info = &data->info;
+    struct signatured_type *entry = (struct signatured_type *) *slot;
+
+    return data->nametable.write_one_signatured_type (entry, info);
+  }
+
 private:
 
   /* Storage for symbol names mapping them to their .debug_str section
@@ -26275,19 +26323,21 @@ private:
   class index_key
   {
   public:
-    index_key (int dwarf_tag_, bool is_static_)
-      : dwarf_tag (dwarf_tag_), is_static (is_static_)
+    index_key (int dwarf_tag_, bool is_static_, unit_kind kind_)
+      : dwarf_tag (dwarf_tag_), is_static (is_static_), kind (kind_)
     {
     }
 
     bool
     operator== (const index_key &other) const
     {
-      return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+      return (dwarf_tag == other.dwarf_tag && is_static == other.is_static
+	      && kind == other.kind);
     }
 
     const int dwarf_tag;
     const bool is_static;
+    const unit_kind kind;
   };
 
   /* Provide std::unordered_map::hasher for index_key.  */
@@ -26307,9 +26357,12 @@ private:
   public:
     const int dwarf_tag, cu_index;
     const bool is_static;
+    const unit_kind kind;
 
-    symbol_value (int dwarf_tag_, int cu_index_, bool is_static_)
-      : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+    symbol_value (int dwarf_tag_, int cu_index_, bool is_static_,
+		  unit_kind kind_)
+      : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_),
+        kind (kind_)
     {}
 
     bool
@@ -26326,6 +26379,7 @@ private:
   while (0)
       X (dwarf_tag);
       X (is_static);
+      X (kind);
       X (cu_index);
 #undef X
       return false;
@@ -26471,7 +26525,7 @@ private:
   /* 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)
+		       bool is_static, unit_kind kind)
   {
     for (; count-- > 0; ++psymp)
       {
@@ -26482,10 +26536,35 @@ private:
 
 	/* Only add a given psymbol once.  */
 	if (psyms_seen.insert (psym).second)
-	  insert (psym, cu_index, is_static);
+	  insert (psym, cu_index, is_static, kind);
       }
   }
 
+  /* A helper function that writes a single signatured_type to an
+     debug_names.  */
+  int
+  write_one_signatured_type (struct signatured_type *entry,
+			     struct signatured_type_index_data *info)
+  {
+    struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
+
+    write_psymbols (info->psyms_seen,
+		    &info->objfile->global_psymbols[psymtab->globals_offset],
+		    psymtab->n_global_syms, info->cu_index, false,
+		    unit_kind::tu);
+    write_psymbols (info->psyms_seen,
+		    &info->objfile->static_psymbols[psymtab->statics_offset],
+		    psymtab->n_static_syms, info->cu_index, true,
+		    unit_kind::tu);
+
+    info->types_list.append_uint (dwarf5_offset_size (), m_dwarf5_byte_order,
+				  to_underlying (entry->per_cu.sect_off));
+
+    ++info->cu_index;
+
+    return 1;
+  }
+
   /* Store value of each symbol.  */
   std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
     m_name_to_value_set;
@@ -26685,7 +26764,6 @@ 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));
 
@@ -26709,23 +26787,30 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
       if (psymtab->user == NULL)
 	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
 
-      cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+      cu_list.append_uint (nametable.dwarf5_offset_size (), dwarf5_byte_order,
 			   to_underlying (per_cu->sect_off));
     }
-  nametable.build ();
-
-  /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC.  */
 
+  /* Write out the .debug_type entries, if any.  */
   data_buf types_cu_list;
-  for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+  if (dwarf2_per_objfile->signatured_types)
     {
-      const signatured_type &sigtype = *dwarf2_per_objfile->all_type_units[i];
-      const dwarf2_per_cu_data &per_cu = sigtype.per_cu;
+      debug_names::write_one_signatured_type_data sig_data (nametable,
+			signatured_type_index_data (types_cu_list, psyms_seen));
 
-      types_cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
-				 to_underlying (per_cu.sect_off));
+      sig_data.info.objfile = objfile;
+      /* It is used only for gdb_index.  */
+      sig_data.info.symtab = nullptr;
+      sig_data.info.cu_index = 0;
+      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+			      debug_names::write_one_signatured_type,
+			      &sig_data);
     }
 
+  nametable.build ();
+
+  /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC.  */
+
   const offset_type bytes_of_header
     = ((dwarf5_is_dwarf64 ? 12 : 4)
        + 2 + 2 + 7 * 4

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

* Re: [patch] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer]
  2017-12-13 21:57           ` [patch] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer] Jan Kratochvil
@ 2017-12-13 22:16             ` Pedro Alves
  2017-12-13 23:03               ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-12-13 22:16 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, Victor Leschuk

On 12/13/2017 09:57 PM, Jan Kratochvil wrote:
> On Tue, 12 Dec 2017 17:52:21 +0100, Jan Kratochvil wrote:
>> On Sat, 09 Dec 2017 00:58:47 +0100, Pedro Alves wrote:
>>> I'm seeing a few regressions compared to .gdb_index, using
>>> --target_board=dwarf4-gdb-index :
>>>
>>> -PASS: gdb.base/enumval.exp: p ZERO 
>>> +FAIL: gdb.base/enumval.exp: p ZERO 
>> ...
>>> etc.  There are a few more.  That board has:
>>>
>>>  set_board_info debug_flags "-gdwarf-4 -fdebug-types-section"
>>>
>>> and if I remove "-fdebug-types-section", then the series
>>> is regression-free compared to .gdb_index.  Have you seen this?
> ...
>> The .debug_names completely misses its support as it does not even produce
>> DW_IDX_type_unit.
> 
> Here you are, could you also verify my regression testing for this patch?

Thanks!  I'm testing right away.

Pedro Alves

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

* Re: [patch] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer]
  2017-12-13 22:16             ` Pedro Alves
@ 2017-12-13 23:03               ` Pedro Alves
  2017-12-14  9:03                 ` [commit] " Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-12-13 23:03 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, Victor Leschuk

On 12/13/2017 10:15 PM, Pedro Alves wrote:
> On 12/13/2017 09:57 PM, Jan Kratochvil wrote:

>>> The .debug_names completely misses its support as it does not even produce
>>> DW_IDX_type_unit.
>>
>> Here you are, could you also verify my regression testing for this patch?
> 
> Thanks!  I'm testing right away.

Yep, it fixes all regressions compared to .gdb_index.

Please fix the following nits and push:

> +  int dwarf5_offset_size () const {

The '{' goes on the next line.

> +  /* A helper function that writes a single signatured_type to an
> +     debug_names.  */

Typo: "to an" => "to a".

OK with those fixed.

Thanks,
Pedro Alves

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

* [commit] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer]
  2017-12-13 23:03               ` Pedro Alves
@ 2017-12-14  9:03                 ` Jan Kratochvil
  0 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-12-14  9:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Victor Leschuk

[-- Attachment #1: Type: text/plain, Size: 105 bytes --]

On Thu, 14 Dec 2017 00:03:12 +0100, Pedro Alves wrote:
> OK with those fixed.

Checked in.


Thanks,
Jan

[-- Attachment #2: 1 --]
[-- Type: text/plain, Size: 11508 bytes --]

commit 8af5c486ea6153bb84b9257def4e5faa4bc72421
Author: Jan Kratochvil <jan.kratochvil@redhat.com>
Date:   Thu Dec 14 10:00:17 2017 +0100

    DWARF-5 .debug_names DW_IDX_type_unit fix
    
    The .debug_names completely misses its support as it did not even produce
    DW_IDX_type_unit.
    
    gdb/ChangeLog
    2017-12-14  Jan Kratochvil  <jan.kratochvil@redhat.com>
    
            * dwarf2read.c (dw2_debug_names_iterator::next): Support
            DW_IDX_type_unit.
            (debug_names::dwarf5_offset_size, unit_kind): New.
            (debug_names::insert): Add parameter kind.
            (debug_names::build): Support DW_IDX_type_unit.
            (debug_names::recursively_write_psymbols): Update
            (debug_names::write_psymbols caller.
            (debug_names::write_one_signatured_type_data)
            (debug_names::write_one_signatured_type): New.
            (debug_names::index_key, debug_names::symbol_value)
            (debug_names::write_psymbols): Add kind.
            (debug_names::write_one_signatured_type): New.
            (write_debug_names): Move dwarf5_offset_size to debug_names.
            Use debug_names::write_one_signatured_type for type units.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d15b732b98..cd9e29cc94 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@
+2017-12-14  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* dwarf2read.c (dw2_debug_names_iterator::next): Support
+	DW_IDX_type_unit.
+	(debug_names::dwarf5_offset_size, unit_kind): New.
+	(debug_names::insert): Add parameter kind.
+	(debug_names::build): Support DW_IDX_type_unit.
+	(debug_names::recursively_write_psymbols): Update
+	(debug_names::write_psymbols caller.
+	(debug_names::write_one_signatured_type_data)
+	(debug_names::write_one_signatured_type): New.
+	(debug_names::index_key, debug_names::symbol_value)
+	(debug_names::write_psymbols): Add kind.
+	(debug_names::write_one_signatured_type): New.
+	(write_debug_names): Move dwarf5_offset_size to debug_names.
+	Use debug_names::write_one_signatured_type for type units.
+
 2017-12-14  Joel Brobecker  <brobecker@adacore.com>
 
 	* ada-lang.c (ada_value_equal): Add handling of typedef types
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b4e60a4409..484cbcee18 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -6192,8 +6192,7 @@ dw2_debug_names_iterator::next ()
 	{
 	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))
+	  if (ull >= dwarf2_per_objfile->n_comp_units)
 	    {
 	      complaint (&symfile_complaints,
 			 _(".debug_names entry has bad CU index %s"
@@ -6204,6 +6203,19 @@ dw2_debug_names_iterator::next ()
 	    }
 	  per_cu = dw2_get_cutu (ull);
 	  break;
+	case DW_IDX_type_unit:
+	  /* Don't crash on bad data.  */
+	  if (ull >= dwarf2_per_objfile->n_type_units)
+	    {
+	      complaint (&symfile_complaints,
+			 _(".debug_names entry has bad TU index %s"
+			   " [in module %s]"),
+			 pulongest (ull),
+			 objfile_name (dwarf2_per_objfile->objfile));
+	      continue;
+	    }
+	  per_cu = dw2_get_cutu (dwarf2_per_objfile->n_comp_units + ull);
+	  break;
 	case DW_IDX_GNU_internal:
 	  if (!m_map.augmentation_is_gdb)
 	    break;
@@ -26012,8 +26024,18 @@ public:
       m_name_table_entry_offs (m_dwarf.name_table_entry_offs)
   {}
 
+  int dwarf5_offset_size () const
+  {
+    const bool dwarf5_is_dwarf64 = &m_dwarf == &m_dwarf64;
+    return dwarf5_is_dwarf64 ? 8 : 4;
+  }
+
+  /* Is this symbol from DW_TAG_compile_unit or DW_TAG_type_unit?  */
+  enum class unit_kind { cu, tu };
+
   /* Insert one symbol.  */
-  void insert (const partial_symbol *psym, int cu_index, bool is_static)
+  void insert (const partial_symbol *psym, int cu_index, bool is_static,
+	       unit_kind kind)
   {
     const int dwarf_tag = psymbol_tag (psym);
     if (dwarf_tag == 0)
@@ -26023,7 +26045,7 @@ public:
       = 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));
+    value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static, kind));
   }
 
   /* Build all the tables.  All symbols must be already inserted.
@@ -26088,13 +26110,16 @@ public:
 	    for (const symbol_value &value : value_set)
 	      {
 		int &idx = m_indexkey_to_idx[index_key (value.dwarf_tag,
-							value.is_static)];
+							value.is_static,
+							value.kind)];
 		if (idx == 0)
 		  {
 		    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
+			      (value.kind == unit_kind::cu ? DW_IDX_compile_unit
+							   : DW_IDX_type_unit);
 		    m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
 		    m_abbrev_table.append_unsigned_leb128 (value.is_static
 							   ? DW_IDX_GNU_internal
@@ -26169,10 +26194,10 @@ public:
 
     write_psymbols (psyms_seen,
 		    &objfile->global_psymbols[psymtab->globals_offset],
-		    psymtab->n_global_syms, cu_index, false);
+		    psymtab->n_global_syms, cu_index, false, unit_kind::cu);
     write_psymbols (psyms_seen,
 		    &objfile->static_psymbols[psymtab->statics_offset],
-		    psymtab->n_static_syms, cu_index, true);
+		    psymtab->n_static_syms, cu_index, true, unit_kind::cu);
   }
 
   /* Return number of bytes the .debug_names section will have.  This
@@ -26207,6 +26232,32 @@ public:
     m_debugstrlookup.file_write (file_str);
   }
 
+  /* A helper user data for write_one_signatured_type.  */
+  class write_one_signatured_type_data
+  {
+  public:
+    write_one_signatured_type_data (debug_names &nametable_,
+                                    signatured_type_index_data &&info_)
+    : nametable (nametable_), info (std::move (info_))
+    {}
+    debug_names &nametable;
+    struct signatured_type_index_data info;
+  };
+
+  /* A helper function to pass write_one_signatured_type to
+     htab_traverse_noresize.  */
+  static int
+  write_one_signatured_type (void **slot, void *d)
+  {
+    write_one_signatured_type_data *data = (write_one_signatured_type_data *) d;
+    struct signatured_type_index_data *info = &data->info;
+    struct signatured_type *entry = (struct signatured_type *) *slot;
+
+    data->nametable.write_one_signatured_type (entry, info);
+
+    return 1;
+  }
+
 private:
 
   /* Storage for symbol names mapping them to their .debug_str section
@@ -26275,19 +26326,21 @@ private:
   class index_key
   {
   public:
-    index_key (int dwarf_tag_, bool is_static_)
-      : dwarf_tag (dwarf_tag_), is_static (is_static_)
+    index_key (int dwarf_tag_, bool is_static_, unit_kind kind_)
+      : dwarf_tag (dwarf_tag_), is_static (is_static_), kind (kind_)
     {
     }
 
     bool
     operator== (const index_key &other) const
     {
-      return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+      return (dwarf_tag == other.dwarf_tag && is_static == other.is_static
+	      && kind == other.kind);
     }
 
     const int dwarf_tag;
     const bool is_static;
+    const unit_kind kind;
   };
 
   /* Provide std::unordered_map::hasher for index_key.  */
@@ -26307,9 +26360,12 @@ private:
   public:
     const int dwarf_tag, cu_index;
     const bool is_static;
+    const unit_kind kind;
 
-    symbol_value (int dwarf_tag_, int cu_index_, bool is_static_)
-      : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+    symbol_value (int dwarf_tag_, int cu_index_, bool is_static_,
+		  unit_kind kind_)
+      : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_),
+        kind (kind_)
     {}
 
     bool
@@ -26326,6 +26382,7 @@ private:
   while (0)
       X (dwarf_tag);
       X (is_static);
+      X (kind);
       X (cu_index);
 #undef X
       return false;
@@ -26471,7 +26528,7 @@ private:
   /* 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)
+		       bool is_static, unit_kind kind)
   {
     for (; count-- > 0; ++psymp)
       {
@@ -26482,10 +26539,33 @@ private:
 
 	/* Only add a given psymbol once.  */
 	if (psyms_seen.insert (psym).second)
-	  insert (psym, cu_index, is_static);
+	  insert (psym, cu_index, is_static, kind);
       }
   }
 
+  /* A helper function that writes a single signatured_type
+     to a debug_names.  */
+  void
+  write_one_signatured_type (struct signatured_type *entry,
+			     struct signatured_type_index_data *info)
+  {
+    struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
+
+    write_psymbols (info->psyms_seen,
+		    &info->objfile->global_psymbols[psymtab->globals_offset],
+		    psymtab->n_global_syms, info->cu_index, false,
+		    unit_kind::tu);
+    write_psymbols (info->psyms_seen,
+		    &info->objfile->static_psymbols[psymtab->statics_offset],
+		    psymtab->n_static_syms, info->cu_index, true,
+		    unit_kind::tu);
+
+    info->types_list.append_uint (dwarf5_offset_size (), m_dwarf5_byte_order,
+				  to_underlying (entry->per_cu.sect_off));
+
+    ++info->cu_index;
+  }
+
   /* Store value of each symbol.  */
   std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
     m_name_to_value_set;
@@ -26685,7 +26765,6 @@ 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));
 
@@ -26709,23 +26788,30 @@ write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
       if (psymtab->user == NULL)
 	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
 
-      cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
+      cu_list.append_uint (nametable.dwarf5_offset_size (), dwarf5_byte_order,
 			   to_underlying (per_cu->sect_off));
     }
-  nametable.build ();
-
-  /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC.  */
 
+  /* Write out the .debug_type entries, if any.  */
   data_buf types_cu_list;
-  for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+  if (dwarf2_per_objfile->signatured_types)
     {
-      const signatured_type &sigtype = *dwarf2_per_objfile->all_type_units[i];
-      const dwarf2_per_cu_data &per_cu = sigtype.per_cu;
+      debug_names::write_one_signatured_type_data sig_data (nametable,
+			signatured_type_index_data (types_cu_list, psyms_seen));
 
-      types_cu_list.append_uint (dwarf5_offset_size, dwarf5_byte_order,
-				 to_underlying (per_cu.sect_off));
+      sig_data.info.objfile = objfile;
+      /* It is used only for gdb_index.  */
+      sig_data.info.symtab = nullptr;
+      sig_data.info.cu_index = 0;
+      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+			      debug_names::write_one_signatured_type,
+			      &sig_data);
     }
 
+  nametable.build ();
+
+  /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC.  */
+
   const offset_type bytes_of_header
     = ((dwarf5_is_dwarf64 ? 12 : 4)
        + 2 + 2 + 7 * 4

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

* Re: [PATCH v3.2 2/5] DWARF-5: .debug_names index producer
  2017-12-08 23:51           ` Pedro Alves
  2017-12-12 15:38             ` Jan Kratochvil
@ 2017-12-31  3:52             ` Simon Marchi
  1 sibling, 0 replies; 31+ messages in thread
From: Simon Marchi @ 2017-12-31  3:52 UTC (permalink / raw)
  To: Pedro Alves, Jan Kratochvil, Eli Zaretskii; +Cc: gdb-patches, vleschuk

On 2017-12-08 06:51 PM, Pedro Alves wrote:
>> +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;
> These look like always return false, since per_cu.sect_off is 32-bit?
> I've left it as is, but it doesn't look right to me.  Seems like
> that makes all the 64-bit support dead as is.

Clang indeed complains about this tautology.

I made a patch that makes sect_offset 64-bits, if you want to take a look:
https://sourceware.org/ml/gdb-patches/2017-12/msg00530.html

Simon

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

end of thread, other threads:[~2017-12-31  3:52 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-19 20:55 [PATCH v3 0/5] DWARF-5: .debug_names index Jan Kratochvil
2017-06-19 20:55 ` [PATCH v3 1/5] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
2017-06-29 19:40   ` Simon Marchi
2017-07-01 15:23     ` [PATCH v3.1 " Jan Kratochvil
2017-12-08 23:43       ` Pedro Alves
2017-06-19 20:55 ` [PATCH v3 2/5] DWARF-5: .debug_names index producer Jan Kratochvil
2017-06-20 15:19   ` Eli Zaretskii
2017-06-22 18:35     ` [PATCH v3.1 " Jan Kratochvil
2017-06-22 19:18       ` Eli Zaretskii
2017-06-22 20:03         ` [PATCH v3.2 " Jan Kratochvil
2017-12-08 23:51           ` Pedro Alves
2017-12-12 15:38             ` Jan Kratochvil
2017-12-31  3:52             ` Simon Marchi
2017-06-19 20:56 ` [PATCH v3 4/5] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
2017-12-08 23:53   ` Pedro Alves
2017-06-19 20:56 ` [PATCH v3 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
2017-06-28 21:21   ` [PATCH v3.1 " Jan Kratochvil
2017-07-02 14:30     ` [PATCH v3.2 " Jan Kratochvil
2017-12-08 23:59       ` Pedro Alves
2017-12-09  0:07         ` [pushed] Add gdb::hash_enum (Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer) Pedro Alves
2017-12-12 16:52         ` [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer Jan Kratochvil
2017-12-13 21:57           ` [patch] DWARF-5 .debug_names DW_IDX_type_unit fix [Re: [PATCH v3.2 5/5] DWARF-5: .debug_names index consumer] Jan Kratochvil
2017-12-13 22:16             ` Pedro Alves
2017-12-13 23:03               ` Pedro Alves
2017-12-14  9:03                 ` [commit] " Jan Kratochvil
2017-06-19 20:56 ` [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
2017-12-08 23:52   ` Pedro Alves
2017-12-11 13:04     ` Yao Qi
2017-12-11 13:20       ` Pedro Alves
2017-12-11 14:00         ` Pedro Alves
2017-12-11 15:08           ` [pushed] Unbreak build for non-ELF ports (Re: [PATCH v3 3/5] Code cleanup: dwarf2_initialize_objfile return value) Pedro Alves

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