public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/6] DWARF-5: .debug_names index
@ 2017-05-26 18:25 Jan Kratochvil
  2017-05-26 18:25 ` [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
                   ` (6 more replies)
  0 siblings, 7 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:25 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.


Jan

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

* [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
@ 2017-05-26 18:25 ` Jan Kratochvil
  2017-06-12 16:08   ` [pushed] " Pedro Alves
  2017-05-26 18:25 ` [PATCH 2/6] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

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

	Code cleanup: C++ify .gdb_index producer.
	* common/common-defs.h <c++11> (std::make_unique): New.
	* dwarf2read.c: Remove include common/gdb_unlinker.h.  Add includes
	unordered_set and unordered_map.
	(MAYBE_SWAP): Cast it to offset_type.
	(struct strtab_entry, hash_strtab_entry, eq_strtab_entry)
	(create_strtab, add_string): Remove.
	(file_write, file_write, DataBuf): New.
	(struct symtab_index_entry): Use std::vector for cu_indices.
	(struct mapped_symtab): Use std::vector for data.
	(hash_symtab_entry, eq_symtab_entry, delete_symtab_entry)
	(create_symbol_hash_table, create_mapped_symtab, cleanup_mapped_symtab):
	Remove.
	(find_slot): Change return type.  Update it to the new data structures.
	(hash_expand, add_index_entry): Update it to the new data structures.
	(offset_type_compare): Remove.
	(uniquify_cu_indices): Update it to the new data structures.
	(CstrView, CstrViewHasher, VectorHasher): New.
	(add_indices_to_cpool): Remove.
	(write_hash_table): Update it to the new data structures.
	(struct psymtab_cu_index_map, hash_psymtab_cu_index)
	(eq_psymtab_cu_index): Remove.
	(struct addrmap_index_data): Change addr_obstack pointer to DataBuf
	reference and std::unordered_map for cu_index_htab.
	(add_address_entry, add_address_entry_worker, write_address_map)
	(write_psymbols): Update it to the new data structures.
	(write_obstack): Remove.
	(struct signatured_type_index_data): Change types_list to a DataBuf
	reference and psyms_seen to a std::unordered_set reference.
	(write_one_signatured_type, recursively_write_psymbols)
	(write_psymtabs_to_index): Update it to the new data structures.
---
 gdb/common/common-defs.h |   14 +
 gdb/dwarf2read.c         |  793 ++++++++++++++++++----------------------------
 2 files changed, 328 insertions(+), 479 deletions(-)

diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h
index 439bce6..e624c5e 100644
--- a/gdb/common/common-defs.h
+++ b/gdb/common/common-defs.h
@@ -91,4 +91,18 @@
 /* Pull in gdb::unique_xmalloc_ptr.  */
 #include "common/gdb_unique_ptr.h"
 
+// Provide C++14 std::make_unique<> for C++11 compilation mode.
+// A copy from: gcc/libstdc++-v3/include/bits/unique_ptr.h
+#if __cplusplus <= 201103L
+namespace std {
+  template<typename _Tp>
+    struct _MakeUniq
+    { typedef unique_ptr<_Tp> __single_object; };
+  template<typename _Tp, typename... _Args>
+    inline typename _MakeUniq<_Tp>::__single_object
+    make_unique(_Args&&... __args)
+    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
+}
+#endif
+
 #endif /* COMMON_DEFS_H */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b58d0fc..12a194a 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -69,7 +69,6 @@
 #include "filestuff.h"
 #include "build-id.h"
 #include "namespace.h"
-#include "common/gdb_unlinker.h"
 #include "common/function-view.h"
 #include "common/gdb_optional.h"
 #include "common/underlying.h"
@@ -77,6 +76,8 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <algorithm>
+#include <unordered_set>
+#include <unordered_map>
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -2146,7 +2147,7 @@ byte_swap (offset_type value)
 #define MAYBE_SWAP(V)  byte_swap (V)
 
 #else
-#define MAYBE_SWAP(V) (V)
+#define MAYBE_SWAP(V) static_cast<offset_type> (V)
 #endif /* WORDS_BIGENDIAN */
 
 /* Read the given attribute value as an address, taking the attribute's
@@ -23193,69 +23194,76 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
-/* The contents of the hash table we create when building the string
-   table.  */
-struct strtab_entry
-{
-  offset_type offset;
-  const char *str;
-};
-
-/* Hash function for a strtab_entry.
-
-   Function is used only during write_hash_table so no index format backward
-   compatibility is needed.  */
+// Write to FILE bytes starting at DATA of length SIZE with error checking.
 
-static hashval_t
-hash_strtab_entry (const void *e)
+static void
+file_write (FILE *file, const void *data, size_t size)
 {
-  const struct strtab_entry *entry = (const struct strtab_entry *) e;
-  return mapped_index_string_hash (INT_MAX, entry->str);
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
 }
 
-/* Equality function for a strtab_entry.  */
+// Write to FILE bytes of std::vector VEC with error checking.
 
-static int
-eq_strtab_entry (const void *a, const void *b)
+template<class Elem> static void
+file_write (FILE *file, const std::vector<Elem> &vec)
 {
-  const struct strtab_entry *ea = (const struct strtab_entry *) a;
-  const struct strtab_entry *eb = (const struct strtab_entry *) b;
-  return !strcmp (ea->str, eb->str);
+  file_write (file, vec.data (), vec.size() * sizeof (vec[0]));
 }
 
-/* Create a strtab_entry hash table.  */
-
-static htab_t
-create_strtab (void)
+// In-memory buffer to prepare data to be written later to a file.
+class DataBuf
 {
-  return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry,
-			    xfree, xcalloc, xfree);
-}
+private:
+  std::vector<gdb_byte> vec;
+public:
 
-/* Add a string to the constant pool.  Return the string's offset in
-   host order.  */
+  // Append space of SIZE number of bytes to the end of buffer.
+  // Return pointer to its start.
 
-static offset_type
-add_string (htab_t table, struct obstack *cpool, const char *str)
-{
-  void **slot;
-  struct strtab_entry entry;
-  struct strtab_entry *result;
+  gdb_byte *
+  append_space (size_t size)
+  {
+    vec.resize (vec.size () + size);
+    return &*vec.end () - size;
+  }
 
-  entry.str = str;
-  slot = htab_find_slot (table, &entry, INSERT);
-  if (*slot)
-    result = (struct strtab_entry *) *slot;
-  else
-    {
-      result = XNEW (struct strtab_entry);
-      result->offset = obstack_object_size (cpool);
-      result->str = str;
-      obstack_grow_str0 (cpool, str);
-      *slot = result;
-    }
-  return result->offset;
-}
+  // Copy DATA to the end of buffer.
+
+  template<typename T> void
+  append_data (const T &data)
+  {
+    std::copy (reinterpret_cast<const gdb_byte *> (&data),
+	       reinterpret_cast<const gdb_byte *> (&data + 1),
+	       append_space (sizeof (data)));
+  }
+
+  // Copy CSTR zero-terminated string to the end of buffer including its
+  // terminating zero.
+
+  void
+  append_cstr0 (const char *cstr)
+  {
+    const size_t size (strlen (cstr) + 1);
+    std::copy (cstr, cstr + size, append_space (size));
+  }
+
+  // Return size of the buffer.
+
+  size_t
+  size () const
+  {
+    return vec.size ();
+  }
+
+  /* Write the buffer to FILE.  */
+
+  void
+  file_write (FILE *file) const
+  {
+    ::file_write (file, vec);
+  }
+};
 
 /* An entry in the symbol table.  */
 struct symtab_index_entry
@@ -23266,107 +23274,40 @@ struct symtab_index_entry
   offset_type index_offset;
   /* A sorted vector of the indices of all the CUs that hold an object
      of this name.  */
-  VEC (offset_type) *cu_indices;
+  std::vector<offset_type> cu_indices;
 };
 
 /* The symbol table.  This is a power-of-2-sized hash table.  */
 struct mapped_symtab
 {
-  offset_type n_elements;
-  offset_type size;
-  struct symtab_index_entry **data;
+public:
+  offset_type n_elements = 0;
+  std::vector<std::unique_ptr<symtab_index_entry>> data;
+  mapped_symtab ()
+  {
+    data.resize (1024);
+  }
 };
 
-/* Hash function for a symtab_index_entry.  */
-
-static hashval_t
-hash_symtab_entry (const void *e)
-{
-  const struct symtab_index_entry *entry
-    = (const struct symtab_index_entry *) e;
-  return iterative_hash (VEC_address (offset_type, entry->cu_indices),
-			 sizeof (offset_type) * VEC_length (offset_type,
-							    entry->cu_indices),
-			 0);
-}
-
-/* Equality function for a symtab_index_entry.  */
-
-static int
-eq_symtab_entry (const void *a, const void *b)
-{
-  const struct symtab_index_entry *ea = (const struct symtab_index_entry *) a;
-  const struct symtab_index_entry *eb = (const struct symtab_index_entry *) b;
-  int len = VEC_length (offset_type, ea->cu_indices);
-  if (len != VEC_length (offset_type, eb->cu_indices))
-    return 0;
-  return !memcmp (VEC_address (offset_type, ea->cu_indices),
-		  VEC_address (offset_type, eb->cu_indices),
-		  sizeof (offset_type) * len);
-}
-
-/* Destroy a symtab_index_entry.  */
-
-static void
-delete_symtab_entry (void *p)
-{
-  struct symtab_index_entry *entry = (struct symtab_index_entry *) p;
-  VEC_free (offset_type, entry->cu_indices);
-  xfree (entry);
-}
-
-/* Create a hash table holding symtab_index_entry objects.  */
-
-static htab_t
-create_symbol_hash_table (void)
-{
-  return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry,
-			    delete_symtab_entry, xcalloc, xfree);
-}
-
-/* Create a new mapped symtab object.  */
-
-static struct mapped_symtab *
-create_mapped_symtab (void)
-{
-  struct mapped_symtab *symtab = XNEW (struct mapped_symtab);
-  symtab->n_elements = 0;
-  symtab->size = 1024;
-  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
-  return symtab;
-}
-
-/* Destroy a mapped_symtab.  */
-
-static void
-cleanup_mapped_symtab (void *p)
-{
-  struct mapped_symtab *symtab = (struct mapped_symtab *) p;
-  /* The contents of the array are freed when the other hash table is
-     destroyed.  */
-  xfree (symtab->data);
-  xfree (symtab);
-}
-
-/* Find a slot in SYMTAB for the symbol NAME.  Returns a pointer to
+/* Find a slot in SYMTAB for the symbol NAME.  Returns a reference to
    the slot.
    
    Function is used only during write_hash_table so no index format backward
    compatibility is needed.  */
 
-static struct symtab_index_entry **
+static std::unique_ptr<symtab_index_entry> &
 find_slot (struct mapped_symtab *symtab, const char *name)
 {
   offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
 
-  index = hash & (symtab->size - 1);
-  step = ((hash * 17) & (symtab->size - 1)) | 1;
+  index = hash & (symtab->data.size () - 1);
+  step = ((hash * 17) & (symtab->data.size () - 1)) | 1;
 
   for (;;)
     {
       if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
-	return &symtab->data[index];
-      index = (index + step) & (symtab->size - 1);
+	return symtab->data[index];
+      index = (index + step) & (symtab->data.size () - 1);
     }
 }
 
@@ -23375,24 +23316,17 @@ find_slot (struct mapped_symtab *symtab, const char *name)
 static void
 hash_expand (struct mapped_symtab *symtab)
 {
-  offset_type old_size = symtab->size;
-  offset_type i;
-  struct symtab_index_entry **old_entries = symtab->data;
-
-  symtab->size *= 2;
-  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+  auto old_entries (std::move (symtab->data));
 
-  for (i = 0; i < old_size; ++i)
-    {
-      if (old_entries[i])
-	{
-	  struct symtab_index_entry **slot = find_slot (symtab,
-							old_entries[i]->name);
-	  *slot = old_entries[i];
-	}
-    }
+  symtab->data.clear ();
+  symtab->data.resize (old_entries.size () * 2);
 
-  xfree (old_entries);
+  for (auto &it:old_entries)
+    if (it)
+      {
+	auto &ref (find_slot (symtab, it->name));
+	ref = std::move (it);
+      }
 }
 
 /* Add an entry to SYMTAB.  NAME is the name of the symbol.
@@ -23404,20 +23338,18 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
 		 int is_static, gdb_index_symbol_kind kind,
 		 offset_type cu_index)
 {
-  struct symtab_index_entry **slot;
   offset_type cu_index_and_attrs;
 
   ++symtab->n_elements;
-  if (4 * symtab->n_elements / 3 >= symtab->size)
+  if (4 * symtab->n_elements / 3 >= symtab->data.size ())
     hash_expand (symtab);
 
-  slot = find_slot (symtab, name);
-  if (!*slot)
+  std::unique_ptr<symtab_index_entry> &slot (find_slot (symtab, name));
+  if (!slot)
     {
-      *slot = XNEW (struct symtab_index_entry);
-      (*slot)->name = name;
+      slot = std::make_unique<symtab_index_entry> ();
+      slot->name = name;
       /* index_offset is set later.  */
-      (*slot)->cu_indices = NULL;
     }
 
   cu_index_and_attrs = 0;
@@ -23432,18 +23364,7 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
      the last entry pushed), but a symbol could have multiple kinds in one CU.
      To keep things simple we don't worry about the duplication here and
      sort and uniqufy the list after we've processed all symbols.  */
-  VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index_and_attrs);
-}
-
-/* qsort helper routine for uniquify_cu_indices.  */
-
-static int
-offset_type_compare (const void *ap, const void *bp)
-{
-  offset_type a = *(offset_type *) ap;
-  offset_type b = *(offset_type *) bp;
-
-  return (a > b) - (b > a);
+  slot->cu_indices.push_back (cu_index_and_attrs);
 }
 
 /* Sort and remove duplicates of all symbols' cu_indices lists.  */
@@ -23451,112 +23372,116 @@ offset_type_compare (const void *ap, const void *bp)
 static void
 uniquify_cu_indices (struct mapped_symtab *symtab)
 {
-  int i;
-
-  for (i = 0; i < symtab->size; ++i)
+  for (const auto &entry:symtab->data)
     {
-      struct symtab_index_entry *entry = symtab->data[i];
-
-      if (entry
-	  && entry->cu_indices != NULL)
+      if (entry && !entry->cu_indices.empty ())
 	{
 	  unsigned int next_to_insert, next_to_check;
 	  offset_type last_value;
 
-	  qsort (VEC_address (offset_type, entry->cu_indices),
-		 VEC_length (offset_type, entry->cu_indices),
-		 sizeof (offset_type), offset_type_compare);
+	  std::sort (entry->cu_indices.begin (), entry->cu_indices.end ());
 
-	  last_value = VEC_index (offset_type, entry->cu_indices, 0);
+	  last_value = entry->cu_indices[0];
 	  next_to_insert = 1;
 	  for (next_to_check = 1;
-	       next_to_check < VEC_length (offset_type, entry->cu_indices);
+	       next_to_check < entry->cu_indices.size ();
 	       ++next_to_check)
-	    {
-	      if (VEC_index (offset_type, entry->cu_indices, next_to_check)
-		  != last_value)
-		{
-		  last_value = VEC_index (offset_type, entry->cu_indices,
-					  next_to_check);
-		  VEC_replace (offset_type, entry->cu_indices, next_to_insert,
-			       last_value);
-		  ++next_to_insert;
-		}
-	    }
-	  VEC_truncate (offset_type, entry->cu_indices, next_to_insert);
+	    if (entry->cu_indices[next_to_check] != last_value)
+	      {
+		last_value = entry->cu_indices[next_to_check];
+		entry->cu_indices[next_to_insert] = last_value;
+		++next_to_insert;
+	      }
+	  entry->cu_indices.resize (next_to_insert);
 	}
     }
 }
 
-/* Add a vector of indices to the constant pool.  */
+// Provide form of const char * suitable for container keys.
+// Only the pointer is being stored.
+// Comparison is done for the strings themselves - not for the pointer.
+class CstrView {
+private:
+  friend class CstrViewHasher;
+  const char *const cstr;
+public:
+  CstrView (const char *cstr_) : cstr (cstr_)
+  {
+  }
+  bool
+  operator == (const CstrView &other) const
+  {
+    return !strcmp (cstr, other.cstr);
+  }
+};
 
-static offset_type
-add_indices_to_cpool (htab_t symbol_hash_table, struct obstack *cpool,
-		      struct symtab_index_entry *entry)
+// Provide std::unordered_map::hasher for CstrView.
+class CstrViewHasher
 {
-  void **slot;
-
-  slot = htab_find_slot (symbol_hash_table, entry, INSERT);
-  if (!*slot)
-    {
-      offset_type len = VEC_length (offset_type, entry->cu_indices);
-      offset_type val = MAYBE_SWAP (len);
-      offset_type iter;
-      int i;
-
-      *slot = entry;
-      entry->index_offset = obstack_object_size (cpool);
+public:
+  size_t
+  operator () (const CstrView &x) const
+  {
+    return mapped_index_string_hash (INT_MAX, x.cstr);
+  }
+};
 
-      obstack_grow (cpool, &val, sizeof (val));
-      for (i = 0;
-	   VEC_iterate (offset_type, entry->cu_indices, i, iter);
-	   ++i)
-	{
-	  val = MAYBE_SWAP (iter);
-	  obstack_grow (cpool, &val, sizeof (val));
-	}
-    }
-  else
-    {
-      struct symtab_index_entry *old_entry
-	= (struct symtab_index_entry *) *slot;
-      entry->index_offset = old_entry->index_offset;
-      entry = old_entry;
-    }
-  return entry->index_offset;
-}
+// Provide std::unordered_map::hasher for std::vector<>.
+template<class T> class VectorHasher
+{
+public:
+  size_t
+  operator () (const std::vector<T> &key) const
+  {
+    // return boost::hash_value<std::vector<T>> (key);
+    return iterative_hash (key.data (),
+			   sizeof (key.front ()) * key.size (), 0);
+  }
+};
 
 /* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
    constant pool entries going into the obstack CPOOL.  */
 
 static void
-write_hash_table (struct mapped_symtab *symtab,
-		  struct obstack *output, struct obstack *cpool)
+write_hash_table (struct mapped_symtab *symtab, DataBuf &output, DataBuf &cpool)
 {
-  offset_type i;
-  htab_t symbol_hash_table;
-  htab_t str_table;
-
-  symbol_hash_table = create_symbol_hash_table ();
-  str_table = create_strtab ();
-
-  /* We add all the index vectors to the constant pool first, to
-     ensure alignment is ok.  */
-  for (i = 0; i < symtab->size; ++i)
-    {
-      if (symtab->data[i])
-	add_indices_to_cpool (symbol_hash_table, cpool, symtab->data[i]);
-    }
+  {
+    /* Elements are sorted vectors of the indices of all the CUs that hold
+       an object of this name.  */
+    std::unordered_map<std::vector<offset_type>, offset_type,
+		       VectorHasher<offset_type>> symbol_hash_table;
+
+    /* We add all the index vectors to the constant pool first, to
+       ensure alignment is ok.  */
+    for (const std::unique_ptr<symtab_index_entry> &it:symtab->data)
+      {
+	if (!it)
+	  continue;
+	gdb_assert (it->index_offset == 0);
+	const auto insertpair (symbol_hash_table.emplace (it->cu_indices,
+							  cpool.size ()));
+	it->index_offset = insertpair.first->second;
+	if (!insertpair.second)
+	  continue;
+	cpool.append_data (MAYBE_SWAP (it->cu_indices.size ()));
+	for (const auto iter:it->cu_indices)
+	  cpool.append_data (MAYBE_SWAP (iter));
+      }
+  }
 
   /* Now write out the hash table.  */
-  for (i = 0; i < symtab->size; ++i)
+  std::unordered_map<CstrView, offset_type, CstrViewHasher> str_table;
+  for (const auto &it:symtab->data)
     {
       offset_type str_off, vec_off;
 
-      if (symtab->data[i])
+      if (it)
 	{
-	  str_off = add_string (str_table, cpool, symtab->data[i]->name);
-	  vec_off = symtab->data[i]->index_offset;
+	  const auto insertpair (str_table.emplace (it->name, cpool.size ()));
+	  if (insertpair.second)
+	    cpool.append_cstr0 (it->name);
+	  str_off = insertpair.first->second;
+	  vec_off = it->index_offset;
 	}
       else
 	{
@@ -23566,50 +23491,17 @@ write_hash_table (struct mapped_symtab *symtab,
 	  vec_off = 0;
 	}
 
-      str_off = MAYBE_SWAP (str_off);
-      vec_off = MAYBE_SWAP (vec_off);
-
-      obstack_grow (output, &str_off, sizeof (str_off));
-      obstack_grow (output, &vec_off, sizeof (vec_off));
+      output.append_data (MAYBE_SWAP (str_off));
+      output.append_data (MAYBE_SWAP (vec_off));
     }
-
-  htab_delete (str_table);
-  htab_delete (symbol_hash_table);
-}
-
-/* Struct to map psymtab to CU index in the index file.  */
-struct psymtab_cu_index_map
-{
-  struct partial_symtab *psymtab;
-  unsigned int cu_index;
-};
-
-static hashval_t
-hash_psymtab_cu_index (const void *item)
-{
-  const struct psymtab_cu_index_map *map
-    = (const struct psymtab_cu_index_map *) item;
-
-  return htab_hash_pointer (map->psymtab);
-}
-
-static int
-eq_psymtab_cu_index (const void *item_lhs, const void *item_rhs)
-{
-  const struct psymtab_cu_index_map *lhs
-    = (const struct psymtab_cu_index_map *) item_lhs;
-  const struct psymtab_cu_index_map *rhs
-    = (const struct psymtab_cu_index_map *) item_rhs;
-
-  return lhs->psymtab == rhs->psymtab;
 }
 
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
   struct objfile *objfile;
-  struct obstack *addr_obstack;
-  htab_t cu_index_htab;
+  DataBuf &addr_vec;
+  std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab;
 
   /* Non-zero if the previous_* fields are valid.
      We can't write an entry until we see the next entry (since it is only then
@@ -23619,26 +23511,28 @@ struct addrmap_index_data
   unsigned int previous_cu_index;
   /* Start address of the CU.  */
   CORE_ADDR previous_cu_start;
+
+  addrmap_index_data (DataBuf &addr_vec_,
+      std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab_)
+  : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
+  {}
 };
 
 /* Write an address entry to OBSTACK.  */
 
 static void
-add_address_entry (struct objfile *objfile, struct obstack *obstack,
+add_address_entry (struct objfile *objfile, DataBuf &addr_vec,
 		   CORE_ADDR start, CORE_ADDR end, unsigned int cu_index)
 {
-  offset_type cu_index_to_write;
-  gdb_byte addr[8];
   CORE_ADDR baseaddr;
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, start - baseaddr);
-  obstack_grow (obstack, addr, 8);
-  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, end - baseaddr);
-  obstack_grow (obstack, addr, 8);
-  cu_index_to_write = MAYBE_SWAP (cu_index);
-  obstack_grow (obstack, &cu_index_to_write, sizeof (offset_type));
+  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
+			  start - baseaddr);
+  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
+			  end - baseaddr);
+  addr_vec.append_data (MAYBE_SWAP (cu_index));
 }
 
 /* Worker function for traversing an addrmap to build the address table.  */
@@ -23650,19 +23544,16 @@ add_address_entry_worker (void *datap, CORE_ADDR start_addr, void *obj)
   struct partial_symtab *pst = (struct partial_symtab *) obj;
 
   if (data->previous_valid)
-    add_address_entry (data->objfile, data->addr_obstack,
+    add_address_entry (data->objfile, data->addr_vec,
 		       data->previous_cu_start, start_addr,
 		       data->previous_cu_index);
 
   data->previous_cu_start = start_addr;
   if (pst != NULL)
     {
-      struct psymtab_cu_index_map find_map, *map;
-      find_map.psymtab = pst;
-      map = ((struct psymtab_cu_index_map *)
-	     htab_find (data->cu_index_htab, &find_map));
-      gdb_assert (map != NULL);
-      data->previous_cu_index = map->cu_index;
+      const auto it (data->cu_index_htab.find (pst));
+      gdb_assert (it != data->cu_index_htab.cend ());
+      data->previous_cu_index = it->second;
       data->previous_valid = 1;
     }
   else
@@ -23676,18 +23567,16 @@ add_address_entry_worker (void *datap, CORE_ADDR start_addr, void *obj)
    in the index file.  */
 
 static void
-write_address_map (struct objfile *objfile, struct obstack *obstack,
-		   htab_t cu_index_htab)
+write_address_map (struct objfile *objfile, DataBuf &addr_vec,
+       std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab)
 {
-  struct addrmap_index_data addrmap_index_data;
+  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
   /* When writing the address table, we have to cope with the fact that
      the addrmap iterator only provides the start of a region; we have to
      wait until the next invocation to get the start of the next region.  */
 
   addrmap_index_data.objfile = objfile;
-  addrmap_index_data.addr_obstack = obstack;
-  addrmap_index_data.cu_index_htab = cu_index_htab;
   addrmap_index_data.previous_valid = 0;
 
   addrmap_foreach (objfile->psymtabs_addrmap, add_address_entry_worker,
@@ -23699,7 +23588,7 @@ write_address_map (struct objfile *objfile, struct obstack *obstack,
      doesn't work here.  To cope we pass 0xff...ff, this is a rare situation
      anyway.  */
   if (addrmap_index_data.previous_valid)
-    add_address_entry (objfile, obstack,
+    add_address_entry (objfile, addr_vec,
 		       addrmap_index_data.previous_cu_start, (CORE_ADDR) -1,
 		       addrmap_index_data.previous_cu_index);
 }
@@ -23746,7 +23635,7 @@ symbol_kind (struct partial_symbol *psym)
 
 static void
 write_psymbols (struct mapped_symtab *symtab,
-		htab_t psyms_seen,
+		std::unordered_set<partial_symbol *> &psyms_seen,
 		struct partial_symbol **psymp,
 		int count,
 		offset_type cu_index,
@@ -23755,44 +23644,34 @@ write_psymbols (struct mapped_symtab *symtab,
   for (; count-- > 0; ++psymp)
     {
       struct partial_symbol *psym = *psymp;
-      void **slot;
 
       if (SYMBOL_LANGUAGE (psym) == language_ada)
 	error (_("Ada is not currently supported by the index"));
 
       /* Only add a given psymbol once.  */
-      slot = htab_find_slot (psyms_seen, psym, INSERT);
-      if (!*slot)
+      if (psyms_seen.insert (psym).second)
 	{
 	  gdb_index_symbol_kind kind = symbol_kind (psym);
 
-	  *slot = psym;
 	  add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym),
 			   is_static, kind, cu_index);
 	}
     }
 }
 
-/* Write the contents of an ("unfinished") obstack to FILE.  Throw an
-   exception if there is an error.  */
-
-static void
-write_obstack (FILE *file, struct obstack *obstack)
-{
-  if (fwrite (obstack_base (obstack), 1, obstack_object_size (obstack),
-	      file)
-      != obstack_object_size (obstack))
-    error (_("couldn't data write to file"));
-}
-
 /* A helper struct used when iterating over debug_types.  */
 struct signatured_type_index_data
 {
   struct objfile *objfile;
   struct mapped_symtab *symtab;
-  struct obstack *types_list;
-  htab_t psyms_seen;
+  DataBuf &types_list;
+  std::unordered_set<partial_symbol *> &psyms_seen;
   int cu_index;
+
+  signatured_type_index_data (DataBuf &types_list_,
+                              std::unordered_set<partial_symbol *> &psyms_seen_)
+  :types_list (types_list_), psyms_seen (psyms_seen_)
+  {}
 };
 
 /* A helper function that writes a single signatured_type to an
@@ -23805,7 +23684,6 @@ write_one_signatured_type (void **slot, void *d)
     = (struct signatured_type_index_data *) d;
   struct signatured_type *entry = (struct signatured_type *) *slot;
   struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
-  gdb_byte val[8];
 
   write_psymbols (info->symtab,
 		  info->psyms_seen,
@@ -23820,14 +23698,14 @@ write_one_signatured_type (void **slot, void *d)
 		  psymtab->n_static_syms, info->cu_index,
 		  1);
 
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE,
 			  to_underlying (entry->per_cu.sect_off));
-  obstack_grow (info->types_list, val, 8);
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE,
 			  to_underlying (entry->type_offset_in_tu));
-  obstack_grow (info->types_list, val, 8);
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->signature);
-  obstack_grow (info->types_list, val, 8);
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE, entry->signature);
 
   ++info->cu_index;
 
@@ -23841,7 +23719,7 @@ static void
 recursively_write_psymbols (struct objfile *objfile,
 			    struct partial_symtab *psymtab,
 			    struct mapped_symtab *symtab,
-			    htab_t psyms_seen,
+			    std::unordered_set<partial_symbol *> &psyms_seen,
 			    offset_type cu_index)
 {
   int i;
@@ -23868,17 +23746,6 @@ recursively_write_psymbols (struct objfile *objfile,
 static void
 write_psymtabs_to_index (struct objfile *objfile, const char *dir)
 {
-  struct cleanup *cleanup;
-  char *filename;
-  struct obstack contents, addr_obstack, constant_pool, symtab_obstack;
-  struct obstack cu_list, types_cu_list;
-  int i;
-  FILE *out_file;
-  struct mapped_symtab *symtab;
-  offset_type val, size_of_contents, total_len;
-  struct stat st;
-  struct psymtab_cu_index_map *psymtab_cu_index_map;
-
   if (dwarf2_per_objfile->using_index)
     error (_("Cannot use an index to create the index"));
 
@@ -23888,160 +23755,128 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
     return;
 
+  struct stat st;
   if (stat (objfile_name (objfile), &st) < 0)
     perror_with_name (objfile_name (objfile));
 
-  filename = concat (dir, SLASH_STRING, lbasename (objfile_name (objfile)),
-		     INDEX_SUFFIX, (char *) NULL);
-  cleanup = make_cleanup (xfree, filename);
+  std::string filename (std::string (dir) + SLASH_STRING
+			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
 
-  out_file = gdb_fopen_cloexec (filename, "wb");
+  FILE *out_file (gdb_fopen_cloexec (filename.c_str (), "wb"));
   if (!out_file)
-    error (_("Can't open `%s' for writing"), filename);
+    error (_("Can't open `%s' for writing"), filename.c_str ());
 
-  gdb::unlinker unlink_file (filename);
+  TRY
+    {
+      mapped_symtab symtab;
+      DataBuf cu_list;
+      std::unordered_set<partial_symbol *> psyms_seen;
+
+      /* 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.  */
+      std::unordered_map<struct partial_symtab *, unsigned int> 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.  */
+      for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+	{
+	  struct dwarf2_per_cu_data *per_cu
+	    = dwarf2_per_objfile->all_comp_units[i];
+	  struct 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;
 
-  symtab = create_mapped_symtab ();
-  make_cleanup (cleanup_mapped_symtab, symtab);
+	  if (psymtab->user == NULL)
+	    recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
+					i);
 
-  obstack_init (&addr_obstack);
-  make_cleanup_obstack_free (&addr_obstack);
+	  const auto insertpair (cu_index_htab.emplace (psymtab, i));
+	  gdb_assert (insertpair.second);
 
-  obstack_init (&cu_list);
-  make_cleanup_obstack_free (&cu_list);
+	  store_unsigned_integer (cu_list.append_space (8), 8,
+				  BFD_ENDIAN_LITTLE,
+				  to_underlying (per_cu->sect_off));
+	  store_unsigned_integer (cu_list.append_space (8), 8,
+				  BFD_ENDIAN_LITTLE, per_cu->length);
+	}
 
-  obstack_init (&types_cu_list);
-  make_cleanup_obstack_free (&types_cu_list);
+      /* Dump the address map.  */
+      DataBuf addr_vec;
+      write_address_map (objfile, addr_vec, cu_index_htab);
 
-  htab_up psyms_seen (htab_create_alloc (100, htab_hash_pointer,
-					 htab_eq_pointer,
-					 NULL, xcalloc, xfree));
+      /* Write out the .debug_type entries, if any.  */
+      DataBuf types_cu_list;
+      if (dwarf2_per_objfile->signatured_types)
+	{
+	  struct signatured_type_index_data sig_data (types_cu_list,
+						      psyms_seen);
+
+	  sig_data.objfile = objfile;
+	  sig_data.symtab = &symtab;
+	  sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
+	  htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+				  write_one_signatured_type, &sig_data);
+	}
 
-  /* 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.  */
-  htab_up cu_index_htab (htab_create_alloc (100,
-					    hash_psymtab_cu_index,
-					    eq_psymtab_cu_index,
-					    NULL, xcalloc, xfree));
-  psymtab_cu_index_map = XNEWVEC (struct psymtab_cu_index_map,
-				  dwarf2_per_objfile->n_comp_units);
-  make_cleanup (xfree, psymtab_cu_index_map);
+      /* Now that we've processed all symbols we can shrink their cu_indices
+	 lists.  */
+      uniquify_cu_indices (&symtab);
 
-  /* 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.  */
-  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
-    {
-      struct dwarf2_per_cu_data *per_cu
-	= dwarf2_per_objfile->all_comp_units[i];
-      struct partial_symtab *psymtab = per_cu->v.psymtab;
-      gdb_byte val[8];
-      struct psymtab_cu_index_map *map;
-      void **slot;
+      DataBuf symtab_vec, constant_pool;
+      write_hash_table (&symtab, symtab_vec, constant_pool);
 
-      /* 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;
+      DataBuf contents;
+      const offset_type size_of_contents (6 * sizeof (offset_type));
+      offset_type total_len (size_of_contents);
 
-      if (psymtab->user == NULL)
-	recursively_write_psymbols (objfile, psymtab, symtab,
-				    psyms_seen.get (), i);
+      /* The version number.  */
+      contents.append_data (MAYBE_SWAP (8));
 
-      map = &psymtab_cu_index_map[i];
-      map->psymtab = psymtab;
-      map->cu_index = i;
-      slot = htab_find_slot (cu_index_htab.get (), map, INSERT);
-      gdb_assert (slot != NULL);
-      gdb_assert (*slot == NULL);
-      *slot = map;
-
-      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
-			      to_underlying (per_cu->sect_off));
-      obstack_grow (&cu_list, val, 8);
-      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, per_cu->length);
-      obstack_grow (&cu_list, val, 8);
-    }
-
-  /* Dump the address map.  */
-  write_address_map (objfile, &addr_obstack, cu_index_htab.get ());
-
-  /* Write out the .debug_type entries, if any.  */
-  if (dwarf2_per_objfile->signatured_types)
-    {
-      struct signatured_type_index_data sig_data;
-
-      sig_data.objfile = objfile;
-      sig_data.symtab = symtab;
-      sig_data.types_list = &types_cu_list;
-      sig_data.psyms_seen = psyms_seen.get ();
-      sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
-      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
-			      write_one_signatured_type, &sig_data);
-    }
-
-  /* Now that we've processed all symbols we can shrink their cu_indices
-     lists.  */
-  uniquify_cu_indices (symtab);
-
-  obstack_init (&constant_pool);
-  make_cleanup_obstack_free (&constant_pool);
-  obstack_init (&symtab_obstack);
-  make_cleanup_obstack_free (&symtab_obstack);
-  write_hash_table (symtab, &symtab_obstack, &constant_pool);
-
-  obstack_init (&contents);
-  make_cleanup_obstack_free (&contents);
-  size_of_contents = 6 * sizeof (offset_type);
-  total_len = size_of_contents;
-
-  /* The version number.  */
-  val = MAYBE_SWAP (8);
-  obstack_grow (&contents, &val, sizeof (val));
-
-  /* The offset of the CU list from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&cu_list);
-
-  /* The offset of the types CU list from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&types_cu_list);
-
-  /* The offset of the address table from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&addr_obstack);
-
-  /* The offset of the symbol table from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&symtab_obstack);
-
-  /* The offset of the constant pool from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&constant_pool);
-
-  gdb_assert (obstack_object_size (&contents) == size_of_contents);
-
-  write_obstack (out_file, &contents);
-  write_obstack (out_file, &cu_list);
-  write_obstack (out_file, &types_cu_list);
-  write_obstack (out_file, &addr_obstack);
-  write_obstack (out_file, &symtab_obstack);
-  write_obstack (out_file, &constant_pool);
+      /* The offset of the CU list from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += cu_list.size ();
 
-  fclose (out_file);
+      /* The offset of the types CU list from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += types_cu_list.size ();
 
-  /* We want to keep the file.  */
-  unlink_file.keep ();
+      /* The offset of the address table from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += addr_vec.size ();
 
-  do_cleanups (cleanup);
+      /* The offset of the symbol table from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += symtab_vec.size ();
+
+      /* The offset of the constant pool from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += constant_pool.size ();
+
+      gdb_assert (contents.size () == size_of_contents);
+
+      contents.file_write (out_file);
+      cu_list.file_write (out_file);
+      types_cu_list.file_write (out_file);
+      addr_vec.file_write (out_file);
+      symtab_vec.file_write (out_file);
+      constant_pool.file_write (out_file);
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      fclose (out_file);
+      unlink (filename.c_str ());
+      throw_exception (except);
+    }
+  END_CATCH
+  fclose (out_file);
 }
 
 /* Implementation of the `save gdb-index' command.

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

* [PATCH 2/6] cc-with-tweaks.sh: Use gdb-add-index.sh
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
  2017-05-26 18:25 ` [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
@ 2017-05-26 18:25 ` Jan Kratochvil
  2017-05-26 18:26 ` [PATCH 4/6] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:25 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..a756c3d 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_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 3/6] DWARF-5: .debug_names index producer
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
                   ` (3 preceding siblings ...)
  2017-05-26 18:26 ` [PATCH 5/6] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
@ 2017-05-26 18:26 ` Jan Kratochvil
  2017-06-09  5:58   ` [PATCH 3.1/6] " Jan Kratochvil
  2017-05-26 18:26 ` [PATCH 6/6] DWARF-5: .debug_names index consumer Jan Kratochvil
  2017-06-18 19:37 ` obsolete: [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
  6 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:26 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.
	(DataBuf::append_unsigned_leb128, DataBuf::empty)
	(DataBuf::operator const char *, DebugNamesNameTable, check_dwarf64_offsets): New.
	(write_gdbindex): New from write_psymtabs_to_index code.
	(write_debug_names): New.
	(write_psymtabs_to_index): New parameter is_dwarf5.  Support
	filename_str and out_file_str.  Move code to write_gdbindex, possibly
	call write_debug_names.
	(save_gdb_index_command): New parameter -dwarf-4.
	(_initialize_dwarf2_read): Document the new parameter -dwarf-4.

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

	* gdb.texinfo (Index Files): Document .debug_names and -dwarf-4.
	(Index Section Format): Mention .debug_names.
---
 gdb/contrib/gdb-add-index.sh |   53 ++
 gdb/doc/gdb.texinfo          |   22 +
 gdb/dwarf2read.c             | 1002 +++++++++++++++++++++++++++++++++++++-----
 3 files changed, 958 insertions(+), 119 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 9fb70f6..17c0ec8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19243,18 +19243,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
@@ -41657,7 +41668,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 12a194a..4f5eb08 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -78,6 +78,10 @@
 #include <algorithm>
 #include <unordered_set>
 #include <unordered_map>
+#include <cmath>
+#include <locale>
+#include <set>
+#include <list>
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -2181,7 +2185,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.
@@ -23248,6 +23254,23 @@ public:
     std::copy (cstr, cstr + size, append_space (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;
+      }
+  }
+
   // Return size of the buffer.
 
   size_t
@@ -23256,6 +23279,14 @@ public:
     return vec.size ();
   }
 
+  // Return true iff the buffer has size zero.
+
+  bool
+  empty () const
+  {
+    return vec.empty ();
+  }
+
   /* Write the buffer to FILE.  */
 
   void
@@ -23413,6 +23444,13 @@ public:
   {
     return !strcmp (cstr, other.cstr);
   }
+
+  // Returned string is only a reference with lifetime of this object.
+
+  operator const char * () const
+  {
+    return cstr;
+  }
 };
 
 // Provide std::unordered_map::hasher for CstrView.
@@ -23741,142 +23779,874 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
-/* Create an index file for OBJFILE in the directory DIR.  */
+// DWARF-5 .debug_names builder.
+class DebugNamesNameTable
+{
+private:
 
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+  // Storage for symbol names mapping them to their .debug_str section offsets.
+  class DebugStrLookup
+  {
+  private:
+    std::unordered_map<CstrView, size_t, CstrViewHasher> str_table;
+    bfd *const abfd;
+
+    // Data to add at the end of .debug_str for new needed symbol names.
+    DataBuf str_add_buf;
+  public:
+
+    // Object costructor to be called for current DWARF2_PER_OBJFILE.
+    // All .debug_str section strings are automatically stored.
+
+    DebugStrLookup () : 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
+		    (str_table.emplace (CstrView (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 (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 (str_table.find (CstrView (s)));
+      if (it != str_table.end ())
+	return it->second;
+      const size_t offset (dwarf2_per_objfile->str.size + str_add_buf.size ());
+      str_table.emplace (CstrView (s), offset);
+      str_add_buf.append_cstr0 (s);
+      return offset;
+    }
+
+    /* Write appended end of .debug_str section to FILE.  */
+
+    void
+    file_write (FILE *file) const
+    {
+      str_add_buf.file_write (file);
+    }
+  };
+
+  // Container to map used DWARF tags to their .debug_names abbreviation tags.
+  class IndexKey
+  {
+  public:
+    const int dwarf_tag;
+    const bool is_static;
+    IndexKey (int dwarf_tag_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), is_static (is_static_)
+    {
+    }
+    bool
+    operator == (const IndexKey &other) const
+    {
+      return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+    }
+  };
+
+  // Provide std::unordered_map::hasher for IndexKey.
+  class IndexKeyHasher
+  {
+  public:
+    size_t
+    operator () (const IndexKey &key) const
+    {
+      return (std::hash<int>() (key.dwarf_tag) << 1) | key.is_static;
+    }
+  };
+
+  // Parameters of one symbol entry.
+  class SymbolValue
+  {
+  public:
+    const int dwarf_tag, cu_index;
+    const bool is_static;
+    SymbolValue (int dwarf_tag_, int cu_index_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+    {
+    }
+    bool
+    operator < (const SymbolValue &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;
+    }
+  };
+
+  // Store value of each symbol.
+  std::unordered_map<CstrView, std::set<SymbolValue>, CstrViewHasher>
+							      name_to_value_set;
+
+  // Tables of DWARF-5 .debug_names.  They are in object file byte order.
+  std::vector<uint32_t> bucket_table;
+  std::vector<uint32_t> hash_table;
+
+  // Abstract base class to unify DWARF-32 and DWARF-64 name table output.
+  class OffsetVec
+  {
+  protected:
+    const bfd_endian dwarf5_byte_order;
+  public:
+    OffsetVec (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 OffsetVecTmpl:public OffsetVec
+  {
+  private:
+    std::vector<OffsetSize> vec;
+  public:
+    OffsetVecTmpl (bfd_endian dwarf5_byte_order_)
+    : OffsetVec (dwarf5_byte_order_)
+    {
+    }
+
+    // Implement OffsetVec::reserve.
+    virtual void
+    reserve (size_t nelem) override
+    {
+      vec.reserve (nelem);
+    }
+
+    // Implement OffsetVec::push_back_reorder.
+    virtual void
+    push_back_reorder (size_t elem) override
+    {
+      vec.push_back (elem);
+      // Check for overflow.
+      gdb_assert (vec.back () == elem);
+      store_unsigned_integer (reinterpret_cast<gdb_byte *> (&vec.back ()),
+			      sizeof (vec.back ()), dwarf5_byte_order, elem);
+    }
+
+    // Implement OffsetVec::bytes.
+    virtual size_t
+    bytes () const override
+    {
+      return vec.size () * sizeof (vec[0]);
+    }
+
+    // Implement OffsetVec::file_write.
+    virtual void
+    file_write (FILE *file) const override
+    {
+      ::file_write (file, vec);
+    }
+  };
+
+  // Base class to unify DWARF-32 and DWARF-64 .debug_names output
+  // respecting name table width.
+  class Dwarf
+  {
+  public:
+    OffsetVec &name_table_string_offs, &name_table_entry_offs;
+    Dwarf (OffsetVec &name_table_string_offs_,
+	   OffsetVec &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 DwarfTmpl:public Dwarf
+  {
+  private:
+    OffsetVecTmpl<OffsetSize> name_table_string_offs, name_table_entry_offs;
+  public:
+    DwarfTmpl (bfd_endian dwarf5_byte_order_)
+    : Dwarf(name_table_string_offs, name_table_entry_offs),
+    name_table_string_offs (dwarf5_byte_order_),
+    name_table_entry_offs (dwarf5_byte_order_)
+    {
+    }
+  };
+
+  const bfd_endian dwarf5_byte_order;
+  DwarfTmpl<uint32_t> dwarf32;
+  DwarfTmpl<uint64_t> dwarf64;
+  Dwarf &dwarf;
+  OffsetVec &name_table_string_offs, &name_table_entry_offs;
+  DebugStrLookup debugstrlookup;
+
+  // Map each used .debug_names abbreviation tag parameters to its index value.
+  std::unordered_map<IndexKey, int, IndexKeyHasher> indexkey_to_idx;
+
+  // Next unused .debug_names abbreviation tag for indexkey_to_idx.
+  int idx_next = 1;
+
+  // .debug_names abbreviation table.
+  DataBuf abbrev_table;
+
+  // .debug_names entry pool.
+  DataBuf entry_pool;
+
+  // 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;
+      }
+  }
+
+public:
+  DebugNamesNameTable (bool is_dwarf64, bfd_endian dwarf5_byte_order_)
+  : dwarf5_byte_order (dwarf5_byte_order_), dwarf32 (dwarf5_byte_order_),
+  dwarf64 (dwarf5_byte_order_),
+  dwarf (is_dwarf64 ? static_cast<Dwarf &> (dwarf64)
+		    : static_cast<Dwarf &> (dwarf32)),
+  name_table_string_offs (dwarf.name_table_string_offs),
+  name_table_entry_offs (dwarf.name_table_entry_offs)
+  {
+  }
+
+  // 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 (name_to_value_set.emplace (CstrView (name),
+						      std::set<SymbolValue> ()));
+    std::set<SymbolValue> &value_set (insertpair.first->second);
+    value_set.emplace (SymbolValue (dwarf_tag, cu_index, is_static));
+  }
+
+  // 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 (abbrev_table.empty ());
+    const size_t name_count (name_to_value_set.size ());
+    bucket_table.resize
+		     (std::pow (2, std::ceil (std::log2 (name_count * 4 / 3))));
+    hash_table.reserve (name_count);
+    name_table_string_offs.reserve (name_count);
+    name_table_entry_offs.reserve (name_count);
+
+    // Map each hash of symbol to its name and value.
+    class HashItPair
+    {
+    public:
+      uint32_t hash;
+      decltype (name_to_value_set)::const_iterator it;
+    };
+    std::vector<std::list<HashItPair>> bucket_hash;
+    bucket_hash.resize (bucket_table.size ());
+    for (decltype (name_to_value_set)::const_iterator it =
+						    name_to_value_set.cbegin ();
+	 it != 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));
+	HashItPair hashitpair;
+	hashitpair.hash = hash;
+	hashitpair.it = it;
+	bucket_hash[hash % bucket_hash.size()].push_back (std::move (hashitpair));
+      }
+    for (size_t bucket_ix = 0; bucket_ix < bucket_hash.size (); ++bucket_ix)
+      {
+	const std::list<HashItPair> &hashitlist (bucket_hash[bucket_ix]);
+	if (hashitlist.empty ())
+	  continue;
+	uint32_t &bucket_slot (bucket_table[bucket_ix]);
+	// The hashes array is indexed starting at 1.
+	store_unsigned_integer (reinterpret_cast<gdb_byte *> (&bucket_slot),
+				sizeof (bucket_slot), dwarf5_byte_order,
+				hash_table.size () + 1);
+	for (const HashItPair &hashitpair:hashitlist)
+	  {
+	    hash_table.push_back (0);
+	    store_unsigned_integer (reinterpret_cast<gdb_byte *>
+							      (&hash_table.back ()),
+				    sizeof (hash_table.back ()), dwarf5_byte_order,
+				    hashitpair.hash);
+	    const CstrView &name (hashitpair.it->first);
+	    const std::set<SymbolValue> &value_set (hashitpair.it->second);
+	    name_table_string_offs.push_back_reorder (debugstrlookup.lookup (name));
+	    name_table_entry_offs.push_back_reorder (entry_pool.size ());
+	    gdb_assert (!value_set.empty ());
+	    for (const SymbolValue &value:value_set)
+	      {
+		int &idx (indexkey_to_idx[IndexKey (value.dwarf_tag,
+						    value.is_static)]);
+		if (!idx) {
+		  idx = idx_next++;
+		  abbrev_table.append_unsigned_leb128 (idx);
+		  abbrev_table.append_unsigned_leb128 (value.dwarf_tag);
+		  abbrev_table.append_unsigned_leb128 (DW_IDX_compile_unit);
+		  abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+		  abbrev_table.append_unsigned_leb128 (value.is_static
+						    ? DW_IDX_GNU_static
+						    : DW_IDX_GNU_external);
+		  abbrev_table.append_unsigned_leb128 (DW_FORM_flag_present);
+
+		  // Terminate attributes list.
+		  abbrev_table.append_unsigned_leb128 (0);
+		  abbrev_table.append_unsigned_leb128 (0);
+		}
+
+		entry_pool.append_unsigned_leb128 (idx);
+		entry_pool.append_unsigned_leb128 (value.cu_index);
+	      }
+
+	    // Terminate the list of CUs.
+	    entry_pool.append_unsigned_leb128 (0);
+	  }
+      }
+    gdb_assert (hash_table.size () == name_count);
+
+    // Terminate tags list.
+    abbrev_table.append_unsigned_leb128 (0);
+  }
+
+  // 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 (!abbrev_table.empty ());
+    const uint32_t retval (bucket_table.size ());
+
+    // Check for overflow; to use boost::numeric_cast.
+    gdb_assert (retval == bucket_table.size ());
+    return retval;
+  }
+
+  // Return .debug_names names count.
+  // It must be called only after calling build method.
+
+  uint32_t
+  name_count () const
+  {
+    // Verify the build method has been already called.
+    gdb_assert (!abbrev_table.empty ());
+    const uint32_t retval (hash_table.size ());
+
+    // Check for overflow; to use boost::numeric_cast.
+    gdb_assert (retval == 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 (!abbrev_table.empty ());
+    return abbrev_table.size ();
+  }
+
+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)
+  {
+    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);
+      }
+  }
+
+public:
+
+  // 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);
+  }
+
+public:
+
+  // 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 (!abbrev_table.empty ());
+    size_t expected_bytes (0);
+    expected_bytes += bucket_table.size () * sizeof (bucket_table[0]);
+    expected_bytes += hash_table.size () * sizeof (hash_table[0]);
+    expected_bytes += name_table_string_offs.bytes ();
+    expected_bytes += name_table_entry_offs.bytes ();
+    expected_bytes += abbrev_table.size ();
+    expected_bytes += 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 (!abbrev_table.empty ());
+    ::file_write (file, bucket_table);
+    ::file_write (file, hash_table);
+    name_table_string_offs.file_write (file);
+    name_table_entry_offs.file_write (file);
+    abbrev_table.file_write (file);
+    entry_pool.file_write (file);
+    debugstrlookup.file_write (file_str);
+  }
+};
+
+// Return iff any of the needed offsets does not fit into 32-bit
+// .debug_names section.
+
+static bool
+check_dwarf64_offsets ()
 {
-  if (dwarf2_per_objfile->using_index)
-    error (_("Cannot use an index to create the index"));
+  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 (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 (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 (!objfile->psymtabs || !objfile->psymtabs_addrmap)
-    return;
+      if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+	return true;
+    }
+  return false;
+}
 
-  struct stat st;
-  if (stat (objfile_name (objfile), &st) < 0)
-    perror_with_name (objfile_name (objfile));
+// 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.
 
-  std::string filename (std::string (dir) + SLASH_STRING
-			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
+  mapped_symtab symtab;
+  DataBuf cu_list;
+  std::unordered_set<partial_symbol *> psyms_seen;
 
-  FILE *out_file (gdb_fopen_cloexec (filename.c_str (), "wb"));
-  if (!out_file)
-    error (_("Can't open `%s' for writing"), filename.c_str ());
+  /* 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.  */
+  std::unordered_map<struct partial_symtab *, unsigned int> cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
 
-  TRY
+  /* 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.  */
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
-      mapped_symtab symtab;
-      DataBuf cu_list;
-      std::unordered_set<partial_symbol *> psyms_seen;
-
-      /* 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.  */
-      std::unordered_map<struct partial_symtab *, unsigned int> 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.  */
-      for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
-	{
-	  struct dwarf2_per_cu_data *per_cu
-	    = dwarf2_per_objfile->all_comp_units[i];
-	  struct 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;
+      struct dwarf2_per_cu_data *per_cu
+	= dwarf2_per_objfile->all_comp_units[i];
+      struct 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)
-	    recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
-					i);
+      if (psymtab->user == NULL)
+	recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
+				    i);
 
-	  const auto insertpair (cu_index_htab.emplace (psymtab, i));
-	  gdb_assert (insertpair.second);
+      const auto insertpair (cu_index_htab.emplace (psymtab, i));
+      gdb_assert (insertpair.second);
 
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE,
-				  to_underlying (per_cu->sect_off));
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE, per_cu->length);
-	}
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE,
+			      to_underlying (per_cu->sect_off));
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE, per_cu->length);
+    }
 
-      /* Dump the address map.  */
-      DataBuf addr_vec;
-      write_address_map (objfile, addr_vec, cu_index_htab);
+  /* Dump the address map.  */
+  DataBuf addr_vec;
+  write_address_map (objfile, addr_vec, cu_index_htab);
 
-      /* Write out the .debug_type entries, if any.  */
-      DataBuf types_cu_list;
-      if (dwarf2_per_objfile->signatured_types)
-	{
-	  struct signatured_type_index_data sig_data (types_cu_list,
-						      psyms_seen);
-
-	  sig_data.objfile = objfile;
-	  sig_data.symtab = &symtab;
-	  sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
-	  htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
-				  write_one_signatured_type, &sig_data);
-	}
+  /* Write out the .debug_type entries, if any.  */
+  DataBuf types_cu_list;
+  if (dwarf2_per_objfile->signatured_types)
+    {
+      struct signatured_type_index_data sig_data (types_cu_list,
+						  psyms_seen);
+
+      sig_data.objfile = objfile;
+      sig_data.symtab = &symtab;
+      sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
+      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+			      write_one_signatured_type, &sig_data);
+    }
+
+  /* Now that we've processed all symbols we can shrink their cu_indices
+     lists.  */
+  uniquify_cu_indices (&symtab);
+
+  DataBuf symtab_vec, constant_pool;
+  write_hash_table (&symtab, symtab_vec, constant_pool);
+
+  const offset_type size_of_header (6 * sizeof (offset_type));
+  size_t total_len (size_of_header);
+  DataBuf header;
+
+  /* The version number.  */
+  header.append_data (MAYBE_SWAP (8));
+
+  /* The offset of the CU list from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += cu_list.size ();
+
+  /* The offset of the types CU list from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += types_cu_list.size ();
+
+  /* The offset of the address table from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += addr_vec.size ();
+
+  /* The offset of the symbol table from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += symtab_vec.size ();
+
+  /* The offset of the constant pool from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += constant_pool.size ();
+
+  gdb_assert (header.size () == size_of_header);
+
+  header.file_write (out_file);
+  cu_list.file_write (out_file);
+  types_cu_list.file_write (out_file);
+  addr_vec.file_write (out_file);
+  symtab_vec.file_write (out_file);
+  constant_pool.file_write (out_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.  */
+  DataBuf cu_list;
+  DebugNamesNameTable nametable (dwarf5_is_dwarf64, dwarf5_byte_order);
+  std::unordered_set<partial_symbol *> psyms_seen;
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      const dwarf2_per_cu_data *per_cu (dwarf2_per_objfile->all_comp_units[i]);
+      partial_symtab *psymtab = per_cu->v.psymtab;
+
+      /* CU of a shared file from 'dwz -m' may be unused by this main file.
+	 It may be referenced from a local scope but in such case it does
+	 not need to be present in .gdb_index.  */
+      if (psymtab == NULL)
+	continue;
+
+      if (psymtab->user == NULL)
+	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
+
+      store_unsigned_integer (cu_list.append_space (dwarf5_offset_size),
+			      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.  */
+
+  DataBuf 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);
+
+      store_unsigned_integer (types_cu_list.append_space (dwarf5_offset_size),
+			      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 ();
+  DataBuf header;
+
+  if (!dwarf5_is_dwarf64)
+    {
+      const uint64_t size64 (expected_bytes - 4);
+      gdb_assert (size64 < 0xfffffff0);
+      store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			      size64);
+    }
+  else
+    {
+      store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			      0xffffffff);
+      store_unsigned_integer (header.append_space (8), 8, dwarf5_byte_order,
+			      expected_bytes - 12);
+    }
+
+  /* The version number.  */
+  store_unsigned_integer (header.append_space (2), 2, dwarf5_byte_order, 5);
+
+  /* Padding.  */
+  store_unsigned_integer (header.append_space (2), 2, dwarf5_byte_order, 0);
+
+  /* comp_unit_count - The number of CUs in the CU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  dwarf2_per_objfile->n_comp_units);
+
+  /* local_type_unit_count - The number of TUs
+     in the local TU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  dwarf2_per_objfile->n_type_units);
 
-      /* Now that we've processed all symbols we can shrink their cu_indices
-	 lists.  */
-      uniquify_cu_indices (&symtab);
+  /* foreign_type_unit_count - The number of TUs
+     in the foreign TU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order, 0);
 
-      DataBuf symtab_vec, constant_pool;
-      write_hash_table (&symtab, symtab_vec, constant_pool);
+  /* bucket_count - The number of hash buckets
+     in the hash lookup table.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  nametable.bucket_count ());
+
+  /* name_count - The number of unique names in the index.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  nametable.name_count ());
+
+  /* abbrev_table_size - The size in bytes
+     of the abbreviations table.  */
+  store_unsigned_integer (header.append_space (4), 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);
+  store_unsigned_integer (header.append_space (4), 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.  */
 
-      DataBuf contents;
-      const offset_type size_of_contents (6 * sizeof (offset_type));
-      offset_type total_len (size_of_contents);
+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"));
 
-      /* The version number.  */
-      contents.append_data (MAYBE_SWAP (8));
+  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"));
 
-      /* The offset of the CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += cu_list.size ();
+  if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
+    return;
 
-      /* The offset of the types CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += types_cu_list.size ();
+  struct stat st;
+  if (stat (objfile_name (objfile), &st) < 0)
+    perror_with_name (objfile_name (objfile));
 
-      /* The offset of the address table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += addr_vec.size ();
+  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);
 
-      /* The offset of the symbol table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += symtab_vec.size ();
+  FILE *out_file (NULL);
+  FILE *out_file_str (NULL);
 
-      /* The offset of the constant pool from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += constant_pool.size ();
+  TRY
+    {
+      out_file = (gdb_fopen_cloexec (filename.c_str (), "wb"));
+      if (!out_file)
+	error (_("Can't open `%s' for writing"), filename.c_str ());
 
-      gdb_assert (contents.size () == size_of_contents);
+      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 ());
 
-      contents.file_write (out_file);
-      cu_list.file_write (out_file);
-      types_cu_list.file_write (out_file);
-      addr_vec.file_write (out_file);
-      symtab_vec.file_write (out_file);
-      constant_pool.file_write (out_file);
+      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);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      fclose (out_file);
+      if (out_file != NULL)
+	fclose (out_file);
       unlink (filename.c_str ());
+      if (out_file_str != NULL)
+	fclose (out_file_str);
+      unlink (filename_str.c_str ());
       throw_exception (except);
     }
   END_CATCH
   fclose (out_file);
+  fclose (out_file_str);
 }
 
 /* Implementation of the `save gdb-index' command.
@@ -23885,12 +24655,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)
   {
@@ -23908,7 +24692,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)
 	  {
@@ -24042,7 +24826,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 4/6] Code cleanup: dwarf2_initialize_objfile return value
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
  2017-05-26 18:25 ` [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
  2017-05-26 18:25 ` [PATCH 2/6] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
@ 2017-05-26 18:26 ` Jan Kratochvil
  2017-05-26 18:26 ` [PATCH 5/6] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:26 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 a0b586f..78f98e0 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -724,6 +724,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 4f5eb08..e7c3643 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4354,7 +4354,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
@@ -4383,13 +4383,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 ab536e8..8725796 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 6/6] DWARF-5: .debug_names index consumer
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
                   ` (4 preceding siblings ...)
  2017-05-26 18:26 ` [PATCH 3/6] DWARF-5: .debug_names index producer Jan Kratochvil
@ 2017-05-26 18:26 ` Jan Kratochvil
  2017-06-18 19:37 ` obsolete: [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
  6 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:26 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;
	(DebugNamesNameTable::djb_hash): Rename it to dwarf5_djb_hash.
	(DebugNamesNameTable::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                                   | 1466 +++++++++++++++++---
 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(+), 191 deletions(-)

diff --git a/gdb/defs.h b/gdb/defs.h
index 78f98e0..79648ca 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -728,6 +728,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 2823428..f3c8ddb 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -209,6 +209,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 IndexVal
+  {
+  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, IndexVal> 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);
 
@@ -241,6 +276,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;
 
@@ -306,6 +343,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.
@@ -356,6 +396,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
 };
 
@@ -1017,6 +1059,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;
@@ -2422,6 +2465,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)
@@ -2618,6 +2671,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
@@ -3069,6 +3127,57 @@ 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)
+{
+  uint32_t i;
+  htab_t sig_types_hash;
+
+  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);
+
+      sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+				 struct signatured_type);
+      sig_type->signature = 0; // FIXME
+      sig_type->type_offset_in_tu = (cu_offset) 0; // FIXME
+      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.  */
 
@@ -3127,6 +3236,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
@@ -3343,8 +3622,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
@@ -3420,98 +3698,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::IndexVal ()));
+      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::IndexVal &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::IndexVal::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);
+    }
+
+  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)
@@ -4230,163 +4818,676 @@ 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.  */
+  const block_enum block_index = FIRST_LOCAL_BLOCK; // invalid
+  /* 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));
+
+	  // Expensive sanity check; FIXME: Disable it.
+	  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;
+	    }
+
+	  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::IndexVal &indexval (indexval_it->second);
+  bool have_is_static (false);
+  bool is_static;
+  dwarf2_per_cu_data *per_cu (NULL);
+  for (const Mapped_debug_names::IndexVal::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
 };
@@ -4426,6 +5527,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;
 
@@ -22911,6 +24015,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.
@@ -24068,20 +25174,6 @@ private:
   // .debug_names entry pool.
   DataBuf entry_pool;
 
-  // 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.
@@ -24179,7 +25271,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));
 	HashItPair hashitpair;
 	hashitpair.hash = hash;
 	hashitpair.it = it;
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 8725796..41be82f 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

* [PATCH 5/6] Refactor: Move some generic code out of .gdb_index code
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
                   ` (2 preceding siblings ...)
  2017-05-26 18:26 ` [PATCH 4/6] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
@ 2017-05-26 18:26 ` Jan Kratochvil
  2017-05-26 18:26 ` [PATCH 3/6] DWARF-5: .debug_names index producer Jan Kratochvil
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-05-26 18:26 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 e7c3643..2823428 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2939,6 +2939,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.  */
 
@@ -2960,17 +2982,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);
     }
 }
 
@@ -4013,96 +4026,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)
     {
@@ -4185,20 +4237,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 3.1/6] DWARF-5: .debug_names index producer
  2017-05-26 18:26 ` [PATCH 3/6] DWARF-5: .debug_names index producer Jan Kratochvil
@ 2017-06-09  5:58   ` Jan Kratochvil
  0 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-09  5:58 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

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

s/std::list/std::forward_list/

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

From: Jan Kratochvil <jan.kratochvil@redhat.com>
Subject: [PATCH] DWARF-5: .debug_names index producer
Date: Thu, 25 May 2017 15:47:08 +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.
	(DataBuf::append_unsigned_leb128, DataBuf::empty)
	(DataBuf::operator const char *, DebugNamesNameTable, check_dwarf64_offsets): New.
	(write_gdbindex): New from write_psymtabs_to_index code.
	(write_debug_names): New.
	(write_psymtabs_to_index): New parameter is_dwarf5.  Support
	filename_str and out_file_str.  Move code to write_gdbindex, possibly
	call write_debug_names.
	(save_gdb_index_command): New parameter -dwarf-4.
	(_initialize_dwarf2_read): Document the new parameter -dwarf-4.

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

	* gdb.texinfo (Index Files): Document .debug_names and -dwarf-4.
	(Index Section Format): Mention .debug_names.
---
 gdb/contrib/gdb-add-index.sh |   53 ++-
 gdb/doc/gdb.texinfo          |   22 +-
 gdb/dwarf2read.c             | 1004 +++++++++++++++++++++++++++++++++++++-----
 3 files changed, 960 insertions(+), 119 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 9fb70f6..17c0ec8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19243,18 +19243,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
@@ -41657,7 +41668,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 12a194a..b7413f3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -78,6 +78,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);
@@ -2181,7 +2185,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.
@@ -23248,6 +23254,23 @@ public:
     std::copy (cstr, cstr + size, append_space (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;
+      }
+  }
+
   // Return size of the buffer.
 
   size_t
@@ -23256,6 +23279,14 @@ public:
     return vec.size ();
   }
 
+  // Return true iff the buffer has size zero.
+
+  bool
+  empty () const
+  {
+    return vec.empty ();
+  }
+
   /* Write the buffer to FILE.  */
 
   void
@@ -23413,6 +23444,13 @@ public:
   {
     return !strcmp (cstr, other.cstr);
   }
+
+  // Returned string is only a reference with lifetime of this object.
+
+  operator const char * () const
+  {
+    return cstr;
+  }
 };
 
 // Provide std::unordered_map::hasher for CstrView.
@@ -23741,142 +23779,876 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
-/* Create an index file for OBJFILE in the directory DIR.  */
+// DWARF-5 .debug_names builder.
+class DebugNamesNameTable
+{
+private:
 
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+  // Storage for symbol names mapping them to their .debug_str section offsets.
+  class DebugStrLookup
+  {
+  private:
+    std::unordered_map<CstrView, size_t, CstrViewHasher> str_table;
+    bfd *const abfd;
+
+    // Data to add at the end of .debug_str for new needed symbol names.
+    DataBuf str_add_buf;
+  public:
+
+    // Object costructor to be called for current DWARF2_PER_OBJFILE.
+    // All .debug_str section strings are automatically stored.
+
+    DebugStrLookup () : 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
+		    (str_table.emplace (CstrView (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 (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 (str_table.find (CstrView (s)));
+      if (it != str_table.end ())
+	return it->second;
+      const size_t offset (dwarf2_per_objfile->str.size + str_add_buf.size ());
+      str_table.emplace (CstrView (s), offset);
+      str_add_buf.append_cstr0 (s);
+      return offset;
+    }
+
+    /* Write appended end of .debug_str section to FILE.  */
+
+    void
+    file_write (FILE *file) const
+    {
+      str_add_buf.file_write (file);
+    }
+  };
+
+  // Container to map used DWARF tags to their .debug_names abbreviation tags.
+  class IndexKey
+  {
+  public:
+    const int dwarf_tag;
+    const bool is_static;
+    IndexKey (int dwarf_tag_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), is_static (is_static_)
+    {
+    }
+    bool
+    operator == (const IndexKey &other) const
+    {
+      return dwarf_tag == other.dwarf_tag && is_static == other.is_static;
+    }
+  };
+
+  // Provide std::unordered_map::hasher for IndexKey.
+  class IndexKeyHasher
+  {
+  public:
+    size_t
+    operator () (const IndexKey &key) const
+    {
+      return (std::hash<int>() (key.dwarf_tag) << 1) | key.is_static;
+    }
+  };
+
+  // Parameters of one symbol entry.
+  class SymbolValue
+  {
+  public:
+    const int dwarf_tag, cu_index;
+    const bool is_static;
+    SymbolValue (int dwarf_tag_, int cu_index_, bool is_static_)
+    : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_)
+    {
+    }
+    bool
+    operator < (const SymbolValue &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;
+    }
+  };
+
+  // Store value of each symbol.
+  std::unordered_map<CstrView, std::set<SymbolValue>, CstrViewHasher>
+							      name_to_value_set;
+
+  // Tables of DWARF-5 .debug_names.  They are in object file byte order.
+  std::vector<uint32_t> bucket_table;
+  std::vector<uint32_t> hash_table;
+
+  // Abstract base class to unify DWARF-32 and DWARF-64 name table output.
+  class OffsetVec
+  {
+  protected:
+    const bfd_endian dwarf5_byte_order;
+  public:
+    OffsetVec (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 OffsetVecTmpl:public OffsetVec
+  {
+  private:
+    std::vector<OffsetSize> vec;
+  public:
+    OffsetVecTmpl (bfd_endian dwarf5_byte_order_)
+    : OffsetVec (dwarf5_byte_order_)
+    {
+    }
+
+    // Implement OffsetVec::reserve.
+    virtual void
+    reserve (size_t nelem) override
+    {
+      vec.reserve (nelem);
+    }
+
+    // Implement OffsetVec::push_back_reorder.
+    virtual void
+    push_back_reorder (size_t elem) override
+    {
+      vec.push_back (elem);
+      // Check for overflow.
+      gdb_assert (vec.back () == elem);
+      store_unsigned_integer (reinterpret_cast<gdb_byte *> (&vec.back ()),
+			      sizeof (vec.back ()), dwarf5_byte_order, elem);
+    }
+
+    // Implement OffsetVec::bytes.
+    virtual size_t
+    bytes () const override
+    {
+      return vec.size () * sizeof (vec[0]);
+    }
+
+    // Implement OffsetVec::file_write.
+    virtual void
+    file_write (FILE *file) const override
+    {
+      ::file_write (file, vec);
+    }
+  };
+
+  // Base class to unify DWARF-32 and DWARF-64 .debug_names output
+  // respecting name table width.
+  class Dwarf
+  {
+  public:
+    OffsetVec &name_table_string_offs, &name_table_entry_offs;
+    Dwarf (OffsetVec &name_table_string_offs_,
+	   OffsetVec &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 DwarfTmpl:public Dwarf
+  {
+  private:
+    OffsetVecTmpl<OffsetSize> name_table_string_offs, name_table_entry_offs;
+  public:
+    DwarfTmpl (bfd_endian dwarf5_byte_order_)
+    : Dwarf(name_table_string_offs, name_table_entry_offs),
+    name_table_string_offs (dwarf5_byte_order_),
+    name_table_entry_offs (dwarf5_byte_order_)
+    {
+    }
+  };
+
+  const bfd_endian dwarf5_byte_order;
+  DwarfTmpl<uint32_t> dwarf32;
+  DwarfTmpl<uint64_t> dwarf64;
+  Dwarf &dwarf;
+  OffsetVec &name_table_string_offs, &name_table_entry_offs;
+  DebugStrLookup debugstrlookup;
+
+  // Map each used .debug_names abbreviation tag parameters to its index value.
+  std::unordered_map<IndexKey, int, IndexKeyHasher> indexkey_to_idx;
+
+  // Next unused .debug_names abbreviation tag for indexkey_to_idx.
+  int idx_next = 1;
+
+  // .debug_names abbreviation table.
+  DataBuf abbrev_table;
+
+  // .debug_names entry pool.
+  DataBuf entry_pool;
+
+  // 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;
+      }
+  }
+
+public:
+  DebugNamesNameTable (bool is_dwarf64, bfd_endian dwarf5_byte_order_)
+  : dwarf5_byte_order (dwarf5_byte_order_), dwarf32 (dwarf5_byte_order_),
+  dwarf64 (dwarf5_byte_order_),
+  dwarf (is_dwarf64 ? static_cast<Dwarf &> (dwarf64)
+		    : static_cast<Dwarf &> (dwarf32)),
+  name_table_string_offs (dwarf.name_table_string_offs),
+  name_table_entry_offs (dwarf.name_table_entry_offs)
+  {
+  }
+
+  // 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 (name_to_value_set.emplace (CstrView (name),
+						      std::set<SymbolValue> ()));
+    std::set<SymbolValue> &value_set (insertpair.first->second);
+    value_set.emplace (SymbolValue (dwarf_tag, cu_index, is_static));
+  }
+
+  // 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 (abbrev_table.empty ());
+    const size_t name_count (name_to_value_set.size ());
+    bucket_table.resize
+		     (std::pow (2, std::ceil (std::log2 (name_count * 4 / 3))));
+    hash_table.reserve (name_count);
+    name_table_string_offs.reserve (name_count);
+    name_table_entry_offs.reserve (name_count);
+
+    // Map each hash of symbol to its name and value.
+    class HashItPair
+    {
+    public:
+      uint32_t hash;
+      decltype (name_to_value_set)::const_iterator it;
+    };
+    std::vector<std::forward_list<HashItPair>> bucket_hash;
+    bucket_hash.resize (bucket_table.size ());
+    for (decltype (name_to_value_set)::const_iterator it =
+						    name_to_value_set.cbegin ();
+	 it != 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));
+	HashItPair 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<HashItPair> &hashitlist
+						       (bucket_hash[bucket_ix]);
+	if (hashitlist.empty ())
+	  continue;
+	uint32_t &bucket_slot (bucket_table[bucket_ix]);
+	// The hashes array is indexed starting at 1.
+	store_unsigned_integer (reinterpret_cast<gdb_byte *> (&bucket_slot),
+				sizeof (bucket_slot), dwarf5_byte_order,
+				hash_table.size () + 1);
+	for (const HashItPair &hashitpair:hashitlist)
+	  {
+	    hash_table.push_back (0);
+	    store_unsigned_integer (reinterpret_cast<gdb_byte *>
+							      (&hash_table.back ()),
+				    sizeof (hash_table.back ()), dwarf5_byte_order,
+				    hashitpair.hash);
+	    const CstrView &name (hashitpair.it->first);
+	    const std::set<SymbolValue> &value_set (hashitpair.it->second);
+	    name_table_string_offs.push_back_reorder (debugstrlookup.lookup (name));
+	    name_table_entry_offs.push_back_reorder (entry_pool.size ());
+	    gdb_assert (!value_set.empty ());
+	    for (const SymbolValue &value:value_set)
+	      {
+		int &idx (indexkey_to_idx[IndexKey (value.dwarf_tag,
+						    value.is_static)]);
+		if (!idx) {
+		  idx = idx_next++;
+		  abbrev_table.append_unsigned_leb128 (idx);
+		  abbrev_table.append_unsigned_leb128 (value.dwarf_tag);
+		  abbrev_table.append_unsigned_leb128 (DW_IDX_compile_unit);
+		  abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+		  abbrev_table.append_unsigned_leb128 (value.is_static
+						    ? DW_IDX_GNU_static
+						    : DW_IDX_GNU_external);
+		  abbrev_table.append_unsigned_leb128 (DW_FORM_flag_present);
+
+		  // Terminate attributes list.
+		  abbrev_table.append_unsigned_leb128 (0);
+		  abbrev_table.append_unsigned_leb128 (0);
+		}
+
+		entry_pool.append_unsigned_leb128 (idx);
+		entry_pool.append_unsigned_leb128 (value.cu_index);
+	      }
+
+	    // Terminate the list of CUs.
+	    entry_pool.append_unsigned_leb128 (0);
+	  }
+      }
+    gdb_assert (hash_table.size () == name_count);
+
+    // Terminate tags list.
+    abbrev_table.append_unsigned_leb128 (0);
+  }
+
+  // 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 (!abbrev_table.empty ());
+    const uint32_t retval (bucket_table.size ());
+
+    // Check for overflow; to use boost::numeric_cast.
+    gdb_assert (retval == bucket_table.size ());
+    return retval;
+  }
+
+  // Return .debug_names names count.
+  // It must be called only after calling build method.
+
+  uint32_t
+  name_count () const
+  {
+    // Verify the build method has been already called.
+    gdb_assert (!abbrev_table.empty ());
+    const uint32_t retval (hash_table.size ());
+
+    // Check for overflow; to use boost::numeric_cast.
+    gdb_assert (retval == 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 (!abbrev_table.empty ());
+    return abbrev_table.size ();
+  }
+
+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)
+  {
+    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);
+      }
+  }
+
+public:
+
+  // 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);
+  }
+
+public:
+
+  // 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 (!abbrev_table.empty ());
+    size_t expected_bytes (0);
+    expected_bytes += bucket_table.size () * sizeof (bucket_table[0]);
+    expected_bytes += hash_table.size () * sizeof (hash_table[0]);
+    expected_bytes += name_table_string_offs.bytes ();
+    expected_bytes += name_table_entry_offs.bytes ();
+    expected_bytes += abbrev_table.size ();
+    expected_bytes += 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 (!abbrev_table.empty ());
+    ::file_write (file, bucket_table);
+    ::file_write (file, hash_table);
+    name_table_string_offs.file_write (file);
+    name_table_entry_offs.file_write (file);
+    abbrev_table.file_write (file);
+    entry_pool.file_write (file);
+    debugstrlookup.file_write (file_str);
+  }
+};
+
+// Return iff any of the needed offsets does not fit into 32-bit
+// .debug_names section.
+
+static bool
+check_dwarf64_offsets ()
 {
-  if (dwarf2_per_objfile->using_index)
-    error (_("Cannot use an index to create the index"));
+  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 (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 (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 (!objfile->psymtabs || !objfile->psymtabs_addrmap)
-    return;
+      if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+	return true;
+    }
+  return false;
+}
 
-  struct stat st;
-  if (stat (objfile_name (objfile), &st) < 0)
-    perror_with_name (objfile_name (objfile));
+// 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.
 
-  std::string filename (std::string (dir) + SLASH_STRING
-			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
+  mapped_symtab symtab;
+  DataBuf cu_list;
+  std::unordered_set<partial_symbol *> psyms_seen;
 
-  FILE *out_file (gdb_fopen_cloexec (filename.c_str (), "wb"));
-  if (!out_file)
-    error (_("Can't open `%s' for writing"), filename.c_str ());
+  /* 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.  */
+  std::unordered_map<struct partial_symtab *, unsigned int> cu_index_htab;
+  cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
 
-  TRY
+  /* 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.  */
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
-      mapped_symtab symtab;
-      DataBuf cu_list;
-      std::unordered_set<partial_symbol *> psyms_seen;
-
-      /* 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.  */
-      std::unordered_map<struct partial_symtab *, unsigned int> 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.  */
-      for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
-	{
-	  struct dwarf2_per_cu_data *per_cu
-	    = dwarf2_per_objfile->all_comp_units[i];
-	  struct 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;
+      struct dwarf2_per_cu_data *per_cu
+	= dwarf2_per_objfile->all_comp_units[i];
+      struct 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)
-	    recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
-					i);
+      if (psymtab->user == NULL)
+	recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
+				    i);
 
-	  const auto insertpair (cu_index_htab.emplace (psymtab, i));
-	  gdb_assert (insertpair.second);
+      const auto insertpair (cu_index_htab.emplace (psymtab, i));
+      gdb_assert (insertpair.second);
 
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE,
-				  to_underlying (per_cu->sect_off));
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE, per_cu->length);
-	}
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE,
+			      to_underlying (per_cu->sect_off));
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE, per_cu->length);
+    }
 
-      /* Dump the address map.  */
-      DataBuf addr_vec;
-      write_address_map (objfile, addr_vec, cu_index_htab);
+  /* Dump the address map.  */
+  DataBuf addr_vec;
+  write_address_map (objfile, addr_vec, cu_index_htab);
 
-      /* Write out the .debug_type entries, if any.  */
-      DataBuf types_cu_list;
-      if (dwarf2_per_objfile->signatured_types)
-	{
-	  struct signatured_type_index_data sig_data (types_cu_list,
-						      psyms_seen);
-
-	  sig_data.objfile = objfile;
-	  sig_data.symtab = &symtab;
-	  sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
-	  htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
-				  write_one_signatured_type, &sig_data);
-	}
+  /* Write out the .debug_type entries, if any.  */
+  DataBuf types_cu_list;
+  if (dwarf2_per_objfile->signatured_types)
+    {
+      struct signatured_type_index_data sig_data (types_cu_list,
+						  psyms_seen);
+
+      sig_data.objfile = objfile;
+      sig_data.symtab = &symtab;
+      sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
+      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+			      write_one_signatured_type, &sig_data);
+    }
+
+  /* Now that we've processed all symbols we can shrink their cu_indices
+     lists.  */
+  uniquify_cu_indices (&symtab);
+
+  DataBuf symtab_vec, constant_pool;
+  write_hash_table (&symtab, symtab_vec, constant_pool);
+
+  const offset_type size_of_header (6 * sizeof (offset_type));
+  size_t total_len (size_of_header);
+  DataBuf header;
+
+  /* The version number.  */
+  header.append_data (MAYBE_SWAP (8));
+
+  /* The offset of the CU list from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += cu_list.size ();
+
+  /* The offset of the types CU list from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += types_cu_list.size ();
+
+  /* The offset of the address table from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += addr_vec.size ();
+
+  /* The offset of the symbol table from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += symtab_vec.size ();
+
+  /* The offset of the constant pool from the start of the file.  */
+  header.append_data (MAYBE_SWAP (total_len));
+  total_len += constant_pool.size ();
+
+  gdb_assert (header.size () == size_of_header);
+
+  header.file_write (out_file);
+  cu_list.file_write (out_file);
+  types_cu_list.file_write (out_file);
+  addr_vec.file_write (out_file);
+  symtab_vec.file_write (out_file);
+  constant_pool.file_write (out_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.  */
+  DataBuf cu_list;
+  DebugNamesNameTable nametable (dwarf5_is_dwarf64, dwarf5_byte_order);
+  std::unordered_set<partial_symbol *> psyms_seen;
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      const dwarf2_per_cu_data *per_cu (dwarf2_per_objfile->all_comp_units[i]);
+      partial_symtab *psymtab = per_cu->v.psymtab;
+
+      /* CU of a shared file from 'dwz -m' may be unused by this main file.
+	 It may be referenced from a local scope but in such case it does
+	 not need to be present in .gdb_index.  */
+      if (psymtab == NULL)
+	continue;
+
+      if (psymtab->user == NULL)
+	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
+
+      store_unsigned_integer (cu_list.append_space (dwarf5_offset_size),
+			      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.  */
+
+  DataBuf 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);
+
+      store_unsigned_integer (types_cu_list.append_space (dwarf5_offset_size),
+			      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 ();
+  DataBuf header;
+
+  if (!dwarf5_is_dwarf64)
+    {
+      const uint64_t size64 (expected_bytes - 4);
+      gdb_assert (size64 < 0xfffffff0);
+      store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			      size64);
+    }
+  else
+    {
+      store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			      0xffffffff);
+      store_unsigned_integer (header.append_space (8), 8, dwarf5_byte_order,
+			      expected_bytes - 12);
+    }
+
+  /* The version number.  */
+  store_unsigned_integer (header.append_space (2), 2, dwarf5_byte_order, 5);
+
+  /* Padding.  */
+  store_unsigned_integer (header.append_space (2), 2, dwarf5_byte_order, 0);
+
+  /* comp_unit_count - The number of CUs in the CU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  dwarf2_per_objfile->n_comp_units);
+
+  /* local_type_unit_count - The number of TUs
+     in the local TU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  dwarf2_per_objfile->n_type_units);
 
-      /* Now that we've processed all symbols we can shrink their cu_indices
-	 lists.  */
-      uniquify_cu_indices (&symtab);
+  /* foreign_type_unit_count - The number of TUs
+     in the foreign TU list.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order, 0);
 
-      DataBuf symtab_vec, constant_pool;
-      write_hash_table (&symtab, symtab_vec, constant_pool);
+  /* bucket_count - The number of hash buckets
+     in the hash lookup table.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  nametable.bucket_count ());
+
+  /* name_count - The number of unique names in the index.  */
+  store_unsigned_integer (header.append_space (4), 4, dwarf5_byte_order,
+			  nametable.name_count ());
+
+  /* abbrev_table_size - The size in bytes
+     of the abbreviations table.  */
+  store_unsigned_integer (header.append_space (4), 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);
+  store_unsigned_integer (header.append_space (4), 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.  */
 
-      DataBuf contents;
-      const offset_type size_of_contents (6 * sizeof (offset_type));
-      offset_type total_len (size_of_contents);
+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"));
 
-      /* The version number.  */
-      contents.append_data (MAYBE_SWAP (8));
+  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"));
 
-      /* The offset of the CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += cu_list.size ();
+  if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
+    return;
 
-      /* The offset of the types CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += types_cu_list.size ();
+  struct stat st;
+  if (stat (objfile_name (objfile), &st) < 0)
+    perror_with_name (objfile_name (objfile));
 
-      /* The offset of the address table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += addr_vec.size ();
+  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);
 
-      /* The offset of the symbol table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += symtab_vec.size ();
+  FILE *out_file (NULL);
+  FILE *out_file_str (NULL);
 
-      /* The offset of the constant pool from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += constant_pool.size ();
+  TRY
+    {
+      out_file = (gdb_fopen_cloexec (filename.c_str (), "wb"));
+      if (!out_file)
+	error (_("Can't open `%s' for writing"), filename.c_str ());
 
-      gdb_assert (contents.size () == size_of_contents);
+      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 ());
 
-      contents.file_write (out_file);
-      cu_list.file_write (out_file);
-      types_cu_list.file_write (out_file);
-      addr_vec.file_write (out_file);
-      symtab_vec.file_write (out_file);
-      constant_pool.file_write (out_file);
+      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);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      fclose (out_file);
+      if (out_file != NULL)
+	fclose (out_file);
       unlink (filename.c_str ());
+      if (out_file_str != NULL)
+	fclose (out_file_str);
+      unlink (filename_str.c_str ());
       throw_exception (except);
     }
   END_CATCH
   fclose (out_file);
+  fclose (out_file_str);
 }
 
 /* Implementation of the `save gdb-index' command.
@@ -23885,12 +24657,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)
   {
@@ -23908,7 +24694,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)
 	  {
@@ -24042,7 +24828,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);
 
-- 
2.9.4

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

* [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-05-26 18:25 ` [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
@ 2017-06-12 16:08   ` Pedro Alves
  2017-06-12 16:14     ` [PATCH 6/6] .gdb_index prod perf regression: mapped_symtab now vector of values Pedro Alves
                       ` (8 more replies)
  0 siblings, 9 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:08 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 05/26/2017 07:25 PM, Jan Kratochvil wrote:
> gdb/ChangeLog
> 2017-05-26  Jan Kratochvil  <jan.kratochvil@redhat.com>
> 
> 	Code cleanup: C++ify .gdb_index producer.
> 	* common/common-defs.h <c++11> (std::make_unique): New.
> 	* dwarf2read.c: Remove include common/gdb_unlinker.h.  Add includes
> 	unordered_set and unordered_map.
> 	(MAYBE_SWAP): Cast it to offset_type.
> 	(struct strtab_entry, hash_strtab_entry, eq_strtab_entry)
> 	(create_strtab, add_string): Remove.
> 	(file_write, file_write, DataBuf): New.
> 	(struct symtab_index_entry): Use std::vector for cu_indices.
> 	(struct mapped_symtab): Use std::vector for data.
> 	(hash_symtab_entry, eq_symtab_entry, delete_symtab_entry)
> 	(create_symbol_hash_table, create_mapped_symtab, cleanup_mapped_symtab):
> 	Remove.
> 	(find_slot): Change return type.  Update it to the new data structures.
> 	(hash_expand, add_index_entry): Update it to the new data structures.
> 	(offset_type_compare): Remove.
> 	(uniquify_cu_indices): Update it to the new data structures.
> 	(CstrView, CstrViewHasher, VectorHasher): New.
> 	(add_indices_to_cpool): Remove.
> 	(write_hash_table): Update it to the new data structures.
> 	(struct psymtab_cu_index_map, hash_psymtab_cu_index)
> 	(eq_psymtab_cu_index): Remove.
> 	(struct addrmap_index_data): Change addr_obstack pointer to DataBuf
> 	reference and std::unordered_map for cu_index_htab.
> 	(add_address_entry, add_address_entry_worker, write_address_map)
> 	(write_psymbols): Update it to the new data structures.
> 	(write_obstack): Remove.
> 	(struct signatured_type_index_data): Change types_list to a DataBuf
> 	reference and psyms_seen to a std::unordered_set reference.
> 	(write_one_signatured_type, recursively_write_psymbols)
> 	(write_psymtabs_to_index): Update it to the new data structures.

Thanks.  This looks generally good.

It had a number of GDB/GCC code convention issues though.

- Should use /**/ for comments.
- CamelCase should only used in template parameters.
- Function/ctors should be placed before data members.
- Private data members should be prefixed with "m_".
- Some function intro comments still referred to
  obstacks, while the functions now take a DataBuf.

Also, the big TRY block would be better done with a RAII type.
Tromey posted a patch to add a unique_ptr with a deleter that calls
fclose, and makes that code use it, but that's not merged yet.
Meanwhile we can add a little RAII class locally that does the
same thing, still avoiding the churn.

The std::vector<gdb_byte> in DataBuf introduces a subtle
pessimization compared to obstacks -- std::vector value-initializes its
elements, which for gdb_byte means zero initialization.  But
DataBuf _always_ overwrites those zeros anyway...  I've suggested
adding a custom allocator that default-initializes instead before,
and this new case made me go do it.  I'll post it in its own thread.

>  
> +// Provide C++14 std::make_unique<> for C++11 compilation mode.
> +// A copy from: gcc/libstdc++-v3/include/bits/unique_ptr.h
> +#if __cplusplus <= 201103L
> +namespace std {
> +  template<typename _Tp>
> +    struct _MakeUniq
> +    { typedef unique_ptr<_Tp> __single_object; };
> +  template<typename _Tp, typename... _Args>
> +    inline typename _MakeUniq<_Tp>::__single_object
> +    make_unique(_Args&&... __args)
> +    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
> +}
> +#endif

We've been putting replacements for > C++11 bits in the gdb namespace,
while taking care not to abuse the implementation namespace.

The _MakeUniq type above is used in the original implementation
as SFINAE helper to pick the right version of make_unique between
single object and array version.   But since this didn't import the
array MakeUniq<_Tp[]> specializations, that type seems kind of pointless
to whoever reads the imported code as is.

I think that if we want to start using make_unique, it'd be better to
introduce it as a separate patch, add it under the gdb namespace, and
adjust the multiple places in the codebase that do either:

 std::unique_ptr<type> ptr (new type());
 ptr.reset (new type ());

to use gdb::make_unique at the same time.
I'll post a patch for that later.

Since the series only uses make_unique in a single place, and it's
not actually the main problematic use case that make_unique
protects against, we can just simply drop that std::make_unique
bit and use ptr.reset(new type()) there for now.
Actually, I'm going to remove that heap allocation anyway in
a following patch.

Note that this patch as is actually causes a ~10% performance
drop in .gdb_index generation that can be significant when
running gdb index on big binaries or in a a batch of binaries.

Running "save gdb-index" on a "-g3 -O2" build of gdb, on x86-64
we can see it:

 $ ./gdb -data-directory=data-directory --batch -q ./gdb.cxx-ified -ex "save gdb-index ." 

Before:

 real    0m0.738s
 user    0m0.700s
 sys     0m0.042s

After:

 real    0m0.810s
 user    0m0.767s
 sys     0m0.045s

There's some variation between the runs, but the drop is
consistent.  The above are representative of the average
I get.

With this script that loops 100 times generating the
same index, we can better observe the effects of just
saving the index:

 $ cat save-index.cmd
 set $i = 0
 while $i < 100
   save gdb-index .
   set $i = $i + 1
 end
 $ time ./gdb -data-directory=data-directory -nx --batch -q -x save-index.cmd  ./gdb.cxx-ified

Before C++ification (average of 5 runs):

 ~5.7s real time

After (average of 5 runs):

 ~7.0s real time

At first I suspected that most of the regression could be
solely explained by the fact that libiberty's hash is just more
efficient than the std::unordered_map/std::unordered_set,
because the latter have unfortunately (widely known) bad cache
locality due to use of separate chaining, and that there would
not be much we could do if we use these types.

But running perf on gdb I saw some hot spots that could be fixed
without having to change the data structures implementations used.

(For performance critical code, it may still be a good idea to reuse
for example gcc's hash table/map, which are C++fied versions of
libiberty's open addressing hash tables; I expect they'll have no
trouble beating unordered_map/unordered_set for use cases like
e.g., sets of pointers.)

Anyway, in interest of forward progress:

- I fixed up the style issues mentioned above, and pushed the
  result in, as below.  I'll post the diff as a reply to this
  email.

  I'd much appreciate it if you'd adjust the rest of the series
  similarly.

- I'll also push in a series of follow up patches that fixes the
  performance regression and makes index generation a bit faster
  than before this patch, actually; and also cleans up a few things
  further while at it.  

Tested with --target_board=dwarf4-gdb-index.

Thanks,
Pedro Alves

From bc8f2430e08cc2a520db49a42686e0529be4a3bc Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Mon, 12 Jun 2017 16:29:53 +0100
Subject: [PATCH] Code cleanup: C++ify .gdb_index producer

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

	Code cleanup: C++ify .gdb_index producer.
	* dwarf2read.c: Include <unordered_set> and <unordered_map>.
	(MAYBE_SWAP) [WORDS_BIGENDIAN]: Cast to offset_type.
	(struct strtab_entry, hash_strtab_entry, eq_strtab_entry)
	(create_strtab, add_string): Remove.
	(file_write, data_buf): New.
	(struct symtab_index_entry): Use std::vector for cu_indices.
	(struct mapped_symtab): Use std::vector for data.
	(hash_symtab_entry, eq_symtab_entry, delete_symtab_entry)
	(create_symbol_hash_table, create_mapped_symtab, cleanup_mapped_symtab):
	Remove.
	(find_slot): Change return type.  Update it to the new data structures.
	(hash_expand, add_index_entry): Update it to the new data structures.
	(offset_type_compare): Remove.
	(uniquify_cu_indices): Update it to the new data structures.
	(c_str_view, c_str_view_hasher, vector_hasher): New.
	(add_indices_to_cpool): Remove.
	(write_hash_table): Update it to the new data structures.
	(struct psymtab_cu_index_map, hash_psymtab_cu_index)
	(eq_psymtab_cu_index): Remove.
	(psym_index_map): New typedef.
	(struct addrmap_index_data): Change addr_obstack pointer to data_buf
	reference and std::unordered_map for cu_index_htab.
	(add_address_entry, add_address_entry_worker, write_address_map)
	(write_psymbols): Update it to the new data structures.
	(write_obstack): Remove.
	(struct signatured_type_index_data): Change types_list to a data_buf
	reference and psyms_seen to a std::unordered_set reference.
	(write_one_signatured_type, recursively_write_psymbols)
	(write_psymtabs_to_index): Update it to the new data structures.
---
 gdb/ChangeLog    |  33 +++
 gdb/dwarf2read.c | 709 +++++++++++++++++++++----------------------------------
 2 files changed, 308 insertions(+), 434 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 38a40e1..037fa0c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,36 @@
+2017-06-12  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	Code cleanup: C++ify .gdb_index producer.
+	* dwarf2read.c: Include <unordered_set> and <unordered_map>.
+	(MAYBE_SWAP) [WORDS_BIGENDIAN]: Cast to offset_type.
+	(struct strtab_entry, hash_strtab_entry, eq_strtab_entry)
+	(create_strtab, add_string): Remove.
+	(file_write, data_buf): New.
+	(struct symtab_index_entry): Use std::vector for cu_indices.
+	(struct mapped_symtab): Use std::vector for data.
+	(hash_symtab_entry, eq_symtab_entry, delete_symtab_entry)
+	(create_symbol_hash_table, create_mapped_symtab, cleanup_mapped_symtab):
+	Remove.
+	(find_slot): Change return type.  Update it to the new data structures.
+	(hash_expand, add_index_entry): Update it to the new data structures.
+	(offset_type_compare): Remove.
+	(uniquify_cu_indices): Update it to the new data structures.
+	(c_str_view, c_str_view_hasher, vector_hasher): New.
+	(add_indices_to_cpool): Remove.
+	(write_hash_table): Update it to the new data structures.
+	(struct psymtab_cu_index_map, hash_psymtab_cu_index)
+	(eq_psymtab_cu_index): Remove.
+	(psym_index_map): New typedef.
+	(struct addrmap_index_data): Change addr_obstack pointer to data_buf
+	reference and std::unordered_map for cu_index_htab.
+	(add_address_entry, add_address_entry_worker, write_address_map)
+	(write_psymbols): Update it to the new data structures.
+	(write_obstack): Remove.
+	(struct signatured_type_index_data): Change types_list to a data_buf
+	reference and psyms_seen to a std::unordered_set reference.
+	(write_one_signatured_type, recursively_write_psymbols)
+	(write_psymtabs_to_index): Update it to the new data structures.
+
 2017-06-11  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* NEWS (Changes since GDB 8.0): Announce {set,show} debug
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b58d0fc..ef21092 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -77,6 +77,8 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <algorithm>
+#include <unordered_set>
+#include <unordered_map>
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -2146,7 +2148,7 @@ byte_swap (offset_type value)
 #define MAYBE_SWAP(V)  byte_swap (V)
 
 #else
-#define MAYBE_SWAP(V) (V)
+#define MAYBE_SWAP(V) static_cast<offset_type> (V)
 #endif /* WORDS_BIGENDIAN */
 
 /* Read the given attribute value as an address, taking the attribute's
@@ -23193,69 +23195,69 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
-/* The contents of the hash table we create when building the string
-   table.  */
-struct strtab_entry
-{
-  offset_type offset;
-  const char *str;
-};
-
-/* Hash function for a strtab_entry.
-
-   Function is used only during write_hash_table so no index format backward
-   compatibility is needed.  */
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+   error checking.  */
 
-static hashval_t
-hash_strtab_entry (const void *e)
+static void
+file_write (FILE *file, const void *data, size_t size)
 {
-  const struct strtab_entry *entry = (const struct strtab_entry *) e;
-  return mapped_index_string_hash (INT_MAX, entry->str);
+  if (fwrite (data, 1, size, file) != size)
+    error (_("couldn't data write to file"));
 }
 
-/* Equality function for a strtab_entry.  */
+/* Write the contents of VEC to FILE, with error checking.  */
 
-static int
-eq_strtab_entry (const void *a, const void *b)
+template<class Elem>
+static void
+file_write (FILE *file, const std::vector<Elem> &vec)
 {
-  const struct strtab_entry *ea = (const struct strtab_entry *) a;
-  const struct strtab_entry *eb = (const struct strtab_entry *) b;
-  return !strcmp (ea->str, eb->str);
+  file_write (file, vec.data (), vec.size() * sizeof (vec[0]));
 }
 
-/* Create a strtab_entry hash table.  */
-
-static htab_t
-create_strtab (void)
+/* In-memory buffer to prepare data to be written later to a file.  */
+class data_buf
 {
-  return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry,
-			    xfree, xcalloc, xfree);
-}
+public:
+  /* Add SIZE bytes at the end of the buffer.  Returns a pointer to
+     the start of the new block.  */
+  gdb_byte *append_space (size_t size)
+  {
+    m_vec.resize (m_vec.size () + size);
+    return &*m_vec.end () - size;
+  }
 
-/* Add a string to the constant pool.  Return the string's offset in
-   host order.  */
+  /* Copy DATA to the end of the buffer.  */
+  template<typename T>
+  void append_data (const T &data)
+  {
+    std::copy (reinterpret_cast<const gdb_byte *> (&data),
+	       reinterpret_cast<const gdb_byte *> (&data + 1),
+	       append_space (sizeof (data)));
+  }
 
-static offset_type
-add_string (htab_t table, struct obstack *cpool, const char *str)
-{
-  void **slot;
-  struct strtab_entry entry;
-  struct strtab_entry *result;
+  /* Copy CSTR (a null-terminated string) to the end of the buffer.
+     The terminating null is appended too.  */
+  void append_cstr0 (const char *cstr)
+  {
+    const size_t size = strlen (cstr) + 1;
+    std::copy (cstr, cstr + size, append_space (size));
+  }
 
-  entry.str = str;
-  slot = htab_find_slot (table, &entry, INSERT);
-  if (*slot)
-    result = (struct strtab_entry *) *slot;
-  else
-    {
-      result = XNEW (struct strtab_entry);
-      result->offset = obstack_object_size (cpool);
-      result->str = str;
-      obstack_grow_str0 (cpool, str);
-      *slot = result;
-    }
-  return result->offset;
-}
+  /* Return the size of the buffer.  */
+  size_t size () const
+  {
+    return m_vec.size ();
+  }
+
+  /* Write the buffer to FILE.  */
+  void file_write (FILE *file) const
+  {
+    ::file_write (file, m_vec);
+  }
+
+private:
+  std::vector<gdb_byte> m_vec;
+};
 
 /* An entry in the symbol table.  */
 struct symtab_index_entry
@@ -23266,107 +23268,40 @@ struct symtab_index_entry
   offset_type index_offset;
   /* A sorted vector of the indices of all the CUs that hold an object
      of this name.  */
-  VEC (offset_type) *cu_indices;
+  std::vector<offset_type> cu_indices;
 };
 
 /* The symbol table.  This is a power-of-2-sized hash table.  */
 struct mapped_symtab
 {
-  offset_type n_elements;
-  offset_type size;
-  struct symtab_index_entry **data;
-};
-
-/* Hash function for a symtab_index_entry.  */
-
-static hashval_t
-hash_symtab_entry (const void *e)
-{
-  const struct symtab_index_entry *entry
-    = (const struct symtab_index_entry *) e;
-  return iterative_hash (VEC_address (offset_type, entry->cu_indices),
-			 sizeof (offset_type) * VEC_length (offset_type,
-							    entry->cu_indices),
-			 0);
-}
-
-/* Equality function for a symtab_index_entry.  */
-
-static int
-eq_symtab_entry (const void *a, const void *b)
-{
-  const struct symtab_index_entry *ea = (const struct symtab_index_entry *) a;
-  const struct symtab_index_entry *eb = (const struct symtab_index_entry *) b;
-  int len = VEC_length (offset_type, ea->cu_indices);
-  if (len != VEC_length (offset_type, eb->cu_indices))
-    return 0;
-  return !memcmp (VEC_address (offset_type, ea->cu_indices),
-		  VEC_address (offset_type, eb->cu_indices),
-		  sizeof (offset_type) * len);
-}
-
-/* Destroy a symtab_index_entry.  */
-
-static void
-delete_symtab_entry (void *p)
-{
-  struct symtab_index_entry *entry = (struct symtab_index_entry *) p;
-  VEC_free (offset_type, entry->cu_indices);
-  xfree (entry);
-}
-
-/* Create a hash table holding symtab_index_entry objects.  */
-
-static htab_t
-create_symbol_hash_table (void)
-{
-  return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry,
-			    delete_symtab_entry, xcalloc, xfree);
-}
-
-/* Create a new mapped symtab object.  */
-
-static struct mapped_symtab *
-create_mapped_symtab (void)
-{
-  struct mapped_symtab *symtab = XNEW (struct mapped_symtab);
-  symtab->n_elements = 0;
-  symtab->size = 1024;
-  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
-  return symtab;
-}
-
-/* Destroy a mapped_symtab.  */
+  mapped_symtab ()
+  {
+    data.resize (1024);
+  }
 
-static void
-cleanup_mapped_symtab (void *p)
-{
-  struct mapped_symtab *symtab = (struct mapped_symtab *) p;
-  /* The contents of the array are freed when the other hash table is
-     destroyed.  */
-  xfree (symtab->data);
-  xfree (symtab);
-}
+  offset_type n_elements = 0;
+  std::vector<std::unique_ptr<symtab_index_entry>> data;
+};
 
-/* Find a slot in SYMTAB for the symbol NAME.  Returns a pointer to
+/* Find a slot in SYMTAB for the symbol NAME.  Returns a reference to
    the slot.
    
    Function is used only during write_hash_table so no index format backward
    compatibility is needed.  */
 
-static struct symtab_index_entry **
+static std::unique_ptr<symtab_index_entry> &
 find_slot (struct mapped_symtab *symtab, const char *name)
 {
   offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
 
-  index = hash & (symtab->size - 1);
-  step = ((hash * 17) & (symtab->size - 1)) | 1;
+  index = hash & (symtab->data.size () - 1);
+  step = ((hash * 17) & (symtab->data.size () - 1)) | 1;
 
   for (;;)
     {
       if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
-	return &symtab->data[index];
-      index = (index + step) & (symtab->size - 1);
+	return symtab->data[index];
+      index = (index + step) & (symtab->data.size () - 1);
     }
 }
 
@@ -23375,24 +23310,17 @@ find_slot (struct mapped_symtab *symtab, const char *name)
 static void
 hash_expand (struct mapped_symtab *symtab)
 {
-  offset_type old_size = symtab->size;
-  offset_type i;
-  struct symtab_index_entry **old_entries = symtab->data;
-
-  symtab->size *= 2;
-  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+  auto old_entries = std::move (symtab->data);
 
-  for (i = 0; i < old_size; ++i)
-    {
-      if (old_entries[i])
-	{
-	  struct symtab_index_entry **slot = find_slot (symtab,
-							old_entries[i]->name);
-	  *slot = old_entries[i];
-	}
-    }
+  symtab->data.clear ();
+  symtab->data.resize (old_entries.size () * 2);
 
-  xfree (old_entries);
+  for (auto &it : old_entries)
+    if (it != NULL)
+      {
+	auto &ref = find_slot (symtab, it->name);
+	ref = std::move (it);
+      }
 }
 
 /* Add an entry to SYMTAB.  NAME is the name of the symbol.
@@ -23404,20 +23332,18 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
 		 int is_static, gdb_index_symbol_kind kind,
 		 offset_type cu_index)
 {
-  struct symtab_index_entry **slot;
   offset_type cu_index_and_attrs;
 
   ++symtab->n_elements;
-  if (4 * symtab->n_elements / 3 >= symtab->size)
+  if (4 * symtab->n_elements / 3 >= symtab->data.size ())
     hash_expand (symtab);
 
-  slot = find_slot (symtab, name);
-  if (!*slot)
+  std::unique_ptr<symtab_index_entry> &slot = find_slot (symtab, name);
+  if (slot == NULL)
     {
-      *slot = XNEW (struct symtab_index_entry);
-      (*slot)->name = name;
+      slot.reset (new symtab_index_entry ());
+      slot->name = name;
       /* index_offset is set later.  */
-      (*slot)->cu_indices = NULL;
     }
 
   cu_index_and_attrs = 0;
@@ -23432,18 +23358,7 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
      the last entry pushed), but a symbol could have multiple kinds in one CU.
      To keep things simple we don't worry about the duplication here and
      sort and uniqufy the list after we've processed all symbols.  */
-  VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index_and_attrs);
-}
-
-/* qsort helper routine for uniquify_cu_indices.  */
-
-static int
-offset_type_compare (const void *ap, const void *bp)
-{
-  offset_type a = *(offset_type *) ap;
-  offset_type b = *(offset_type *) bp;
-
-  return (a > b) - (b > a);
+  slot->cu_indices.push_back (cu_index_and_attrs);
 }
 
 /* Sort and remove duplicates of all symbols' cu_indices lists.  */
@@ -23451,112 +23366,118 @@ offset_type_compare (const void *ap, const void *bp)
 static void
 uniquify_cu_indices (struct mapped_symtab *symtab)
 {
-  int i;
-
-  for (i = 0; i < symtab->size; ++i)
+  for (const auto &entry : symtab->data)
     {
-      struct symtab_index_entry *entry = symtab->data[i];
-
-      if (entry
-	  && entry->cu_indices != NULL)
+      if (entry && !entry->cu_indices.empty ())
 	{
 	  unsigned int next_to_insert, next_to_check;
 	  offset_type last_value;
 
-	  qsort (VEC_address (offset_type, entry->cu_indices),
-		 VEC_length (offset_type, entry->cu_indices),
-		 sizeof (offset_type), offset_type_compare);
+	  std::sort (entry->cu_indices.begin (), entry->cu_indices.end ());
 
-	  last_value = VEC_index (offset_type, entry->cu_indices, 0);
+	  last_value = entry->cu_indices[0];
 	  next_to_insert = 1;
 	  for (next_to_check = 1;
-	       next_to_check < VEC_length (offset_type, entry->cu_indices);
+	       next_to_check < entry->cu_indices.size ();
 	       ++next_to_check)
-	    {
-	      if (VEC_index (offset_type, entry->cu_indices, next_to_check)
-		  != last_value)
-		{
-		  last_value = VEC_index (offset_type, entry->cu_indices,
-					  next_to_check);
-		  VEC_replace (offset_type, entry->cu_indices, next_to_insert,
-			       last_value);
-		  ++next_to_insert;
-		}
-	    }
-	  VEC_truncate (offset_type, entry->cu_indices, next_to_insert);
+	    if (entry->cu_indices[next_to_check] != last_value)
+	      {
+		last_value = entry->cu_indices[next_to_check];
+		entry->cu_indices[next_to_insert] = last_value;
+		++next_to_insert;
+	      }
+	  entry->cu_indices.resize (next_to_insert);
 	}
     }
 }
 
-/* Add a vector of indices to the constant pool.  */
-
-static offset_type
-add_indices_to_cpool (htab_t symbol_hash_table, struct obstack *cpool,
-		      struct symtab_index_entry *entry)
+/* A form of 'const char *' suitable for container keys.  Only the
+   pointer is stored.  The strings themselves are compared, not the
+   pointers.  */
+class c_str_view
 {
-  void **slot;
-
-  slot = htab_find_slot (symbol_hash_table, entry, INSERT);
-  if (!*slot)
-    {
-      offset_type len = VEC_length (offset_type, entry->cu_indices);
-      offset_type val = MAYBE_SWAP (len);
-      offset_type iter;
-      int i;
+public:
+  c_str_view (const char *cstr)
+    : m_cstr (cstr)
+  {}
 
-      *slot = entry;
-      entry->index_offset = obstack_object_size (cpool);
+  bool operator== (const c_str_view &other) const
+  {
+    return strcmp (m_cstr, other.m_cstr) == 0;
+  }
 
-      obstack_grow (cpool, &val, sizeof (val));
-      for (i = 0;
-	   VEC_iterate (offset_type, entry->cu_indices, i, iter);
-	   ++i)
-	{
-	  val = MAYBE_SWAP (iter);
-	  obstack_grow (cpool, &val, sizeof (val));
-	}
-    }
-  else
-    {
-      struct symtab_index_entry *old_entry
-	= (struct symtab_index_entry *) *slot;
-      entry->index_offset = old_entry->index_offset;
-      entry = old_entry;
-    }
-  return entry->index_offset;
-}
+private:
+  friend class c_str_view_hasher;
+  const char *const m_cstr;
+};
 
-/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
-   constant pool entries going into the obstack CPOOL.  */
+/* A std::unordered_map::hasher for c_str_view that uses the right
+   hash function for strings in a mapped index.  */
+class c_str_view_hasher
+{
+public:
+  size_t operator () (const c_str_view &x) const
+  {
+    return mapped_index_string_hash (INT_MAX, x.m_cstr);
+  }
+};
 
-static void
-write_hash_table (struct mapped_symtab *symtab,
-		  struct obstack *output, struct obstack *cpool)
+/* A std::unordered_map::hasher for std::vector<>.  */
+template<typename T>
+class vector_hasher
 {
-  offset_type i;
-  htab_t symbol_hash_table;
-  htab_t str_table;
+public:
+  size_t operator () (const std::vector<T> &key) const
+  {
+    return iterative_hash (key.data (),
+			   sizeof (key.front ()) * key.size (), 0);
+  }
+};
 
-  symbol_hash_table = create_symbol_hash_table ();
-  str_table = create_strtab ();
+/* Write the mapped hash table SYMTAB to the data buffer OUTPUT, with
+   constant pool entries going into the data buffer CPOOL.  */
 
-  /* We add all the index vectors to the constant pool first, to
-     ensure alignment is ok.  */
-  for (i = 0; i < symtab->size; ++i)
-    {
-      if (symtab->data[i])
-	add_indices_to_cpool (symbol_hash_table, cpool, symtab->data[i]);
-    }
+static void
+write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
+{
+  {
+    /* Elements are sorted vectors of the indices of all the CUs that
+       hold an object of this name.  */
+    std::unordered_map<std::vector<offset_type>, offset_type,
+		       vector_hasher<offset_type>>
+      symbol_hash_table;
+
+    /* We add all the index vectors to the constant pool first, to
+       ensure alignment is ok.  */
+    for (const std::unique_ptr<symtab_index_entry> &it : symtab->data)
+      {
+	if (it == NULL)
+	  continue;
+	gdb_assert (it->index_offset == 0);
+	const auto insertpair
+	  = symbol_hash_table.emplace (it->cu_indices, cpool.size ());
+	it->index_offset = insertpair.first->second;
+	if (!insertpair.second)
+	  continue;
+	cpool.append_data (MAYBE_SWAP (it->cu_indices.size ()));
+	for (const auto iter : it->cu_indices)
+	  cpool.append_data (MAYBE_SWAP (iter));
+      }
+  }
 
   /* Now write out the hash table.  */
-  for (i = 0; i < symtab->size; ++i)
+  std::unordered_map<c_str_view, offset_type, c_str_view_hasher> str_table;
+  for (const auto &it : symtab->data)
     {
       offset_type str_off, vec_off;
 
-      if (symtab->data[i])
+      if (it != NULL)
 	{
-	  str_off = add_string (str_table, cpool, symtab->data[i]->name);
-	  vec_off = symtab->data[i]->index_offset;
+	  const auto insertpair = str_table.emplace (it->name, cpool.size ());
+	  if (insertpair.second)
+	    cpool.append_cstr0 (it->name);
+	  str_off = insertpair.first->second;
+	  vec_off = it->index_offset;
 	}
       else
 	{
@@ -23566,50 +23487,23 @@ write_hash_table (struct mapped_symtab *symtab,
 	  vec_off = 0;
 	}
 
-      str_off = MAYBE_SWAP (str_off);
-      vec_off = MAYBE_SWAP (vec_off);
-
-      obstack_grow (output, &str_off, sizeof (str_off));
-      obstack_grow (output, &vec_off, sizeof (vec_off));
+      output.append_data (MAYBE_SWAP (str_off));
+      output.append_data (MAYBE_SWAP (vec_off));
     }
-
-  htab_delete (str_table);
-  htab_delete (symbol_hash_table);
 }
 
-/* Struct to map psymtab to CU index in the index file.  */
-struct psymtab_cu_index_map
-{
-  struct partial_symtab *psymtab;
-  unsigned int cu_index;
-};
-
-static hashval_t
-hash_psymtab_cu_index (const void *item)
-{
-  const struct psymtab_cu_index_map *map
-    = (const struct psymtab_cu_index_map *) item;
-
-  return htab_hash_pointer (map->psymtab);
-}
-
-static int
-eq_psymtab_cu_index (const void *item_lhs, const void *item_rhs)
-{
-  const struct psymtab_cu_index_map *lhs
-    = (const struct psymtab_cu_index_map *) item_lhs;
-  const struct psymtab_cu_index_map *rhs
-    = (const struct psymtab_cu_index_map *) item_rhs;
-
-  return lhs->psymtab == rhs->psymtab;
-}
+typedef std::unordered_map<partial_symtab *, unsigned int> psym_index_map;
 
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
+  addrmap_index_data (data_buf &addr_vec_, psym_index_map &cu_index_htab_)
+    : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
+  {}
+
   struct objfile *objfile;
-  struct obstack *addr_obstack;
-  htab_t cu_index_htab;
+  data_buf &addr_vec;
+  psym_index_map &cu_index_htab;
 
   /* Non-zero if the previous_* fields are valid.
      We can't write an entry until we see the next entry (since it is only then
@@ -23621,24 +23515,21 @@ struct addrmap_index_data
   CORE_ADDR previous_cu_start;
 };
 
-/* Write an address entry to OBSTACK.  */
+/* Write an address entry to ADDR_VEC.  */
 
 static void
-add_address_entry (struct objfile *objfile, struct obstack *obstack,
+add_address_entry (struct objfile *objfile, data_buf &addr_vec,
 		   CORE_ADDR start, CORE_ADDR end, unsigned int cu_index)
 {
-  offset_type cu_index_to_write;
-  gdb_byte addr[8];
   CORE_ADDR baseaddr;
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, start - baseaddr);
-  obstack_grow (obstack, addr, 8);
-  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, end - baseaddr);
-  obstack_grow (obstack, addr, 8);
-  cu_index_to_write = MAYBE_SWAP (cu_index);
-  obstack_grow (obstack, &cu_index_to_write, sizeof (offset_type));
+  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
+			  start - baseaddr);
+  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
+			  end - baseaddr);
+  addr_vec.append_data (MAYBE_SWAP (cu_index));
 }
 
 /* Worker function for traversing an addrmap to build the address table.  */
@@ -23650,44 +23541,39 @@ add_address_entry_worker (void *datap, CORE_ADDR start_addr, void *obj)
   struct partial_symtab *pst = (struct partial_symtab *) obj;
 
   if (data->previous_valid)
-    add_address_entry (data->objfile, data->addr_obstack,
+    add_address_entry (data->objfile, data->addr_vec,
 		       data->previous_cu_start, start_addr,
 		       data->previous_cu_index);
 
   data->previous_cu_start = start_addr;
   if (pst != NULL)
     {
-      struct psymtab_cu_index_map find_map, *map;
-      find_map.psymtab = pst;
-      map = ((struct psymtab_cu_index_map *)
-	     htab_find (data->cu_index_htab, &find_map));
-      gdb_assert (map != NULL);
-      data->previous_cu_index = map->cu_index;
+      const auto it = data->cu_index_htab.find (pst);
+      gdb_assert (it != data->cu_index_htab.cend ());
+      data->previous_cu_index = it->second;
       data->previous_valid = 1;
     }
   else
-      data->previous_valid = 0;
+    data->previous_valid = 0;
 
   return 0;
 }
 
-/* Write OBJFILE's address map to OBSTACK.
+/* Write OBJFILE's address map to ADDR_VEC.
    CU_INDEX_HTAB is used to map addrmap entries to their CU indices
    in the index file.  */
 
 static void
-write_address_map (struct objfile *objfile, struct obstack *obstack,
-		   htab_t cu_index_htab)
+write_address_map (struct objfile *objfile, data_buf &addr_vec,
+		   psym_index_map &cu_index_htab)
 {
-  struct addrmap_index_data addrmap_index_data;
+  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
   /* When writing the address table, we have to cope with the fact that
      the addrmap iterator only provides the start of a region; we have to
      wait until the next invocation to get the start of the next region.  */
 
   addrmap_index_data.objfile = objfile;
-  addrmap_index_data.addr_obstack = obstack;
-  addrmap_index_data.cu_index_htab = cu_index_htab;
   addrmap_index_data.previous_valid = 0;
 
   addrmap_foreach (objfile->psymtabs_addrmap, add_address_entry_worker,
@@ -23699,7 +23585,7 @@ write_address_map (struct objfile *objfile, struct obstack *obstack,
      doesn't work here.  To cope we pass 0xff...ff, this is a rare situation
      anyway.  */
   if (addrmap_index_data.previous_valid)
-    add_address_entry (objfile, obstack,
+    add_address_entry (objfile, addr_vec,
 		       addrmap_index_data.previous_cu_start, (CORE_ADDR) -1,
 		       addrmap_index_data.previous_cu_index);
 }
@@ -23746,7 +23632,7 @@ symbol_kind (struct partial_symbol *psym)
 
 static void
 write_psymbols (struct mapped_symtab *symtab,
-		htab_t psyms_seen,
+		std::unordered_set<partial_symbol *> &psyms_seen,
 		struct partial_symbol **psymp,
 		int count,
 		offset_type cu_index,
@@ -23755,43 +23641,33 @@ write_psymbols (struct mapped_symtab *symtab,
   for (; count-- > 0; ++psymp)
     {
       struct partial_symbol *psym = *psymp;
-      void **slot;
 
       if (SYMBOL_LANGUAGE (psym) == language_ada)
 	error (_("Ada is not currently supported by the index"));
 
       /* Only add a given psymbol once.  */
-      slot = htab_find_slot (psyms_seen, psym, INSERT);
-      if (!*slot)
+      if (psyms_seen.insert (psym).second)
 	{
 	  gdb_index_symbol_kind kind = symbol_kind (psym);
 
-	  *slot = psym;
 	  add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym),
 			   is_static, kind, cu_index);
 	}
     }
 }
 
-/* Write the contents of an ("unfinished") obstack to FILE.  Throw an
-   exception if there is an error.  */
-
-static void
-write_obstack (FILE *file, struct obstack *obstack)
-{
-  if (fwrite (obstack_base (obstack), 1, obstack_object_size (obstack),
-	      file)
-      != obstack_object_size (obstack))
-    error (_("couldn't data write to file"));
-}
-
 /* A helper struct used when iterating over debug_types.  */
 struct signatured_type_index_data
 {
+  signatured_type_index_data (data_buf &types_list_,
+                              std::unordered_set<partial_symbol *> &psyms_seen_)
+    : types_list (types_list_), psyms_seen (psyms_seen_)
+  {}
+
   struct objfile *objfile;
   struct mapped_symtab *symtab;
-  struct obstack *types_list;
-  htab_t psyms_seen;
+  data_buf &types_list;
+  std::unordered_set<partial_symbol *> &psyms_seen;
   int cu_index;
 };
 
@@ -23805,7 +23681,6 @@ write_one_signatured_type (void **slot, void *d)
     = (struct signatured_type_index_data *) d;
   struct signatured_type *entry = (struct signatured_type *) *slot;
   struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
-  gdb_byte val[8];
 
   write_psymbols (info->symtab,
 		  info->psyms_seen,
@@ -23820,14 +23695,14 @@ write_one_signatured_type (void **slot, void *d)
 		  psymtab->n_static_syms, info->cu_index,
 		  1);
 
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE,
 			  to_underlying (entry->per_cu.sect_off));
-  obstack_grow (info->types_list, val, 8);
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE,
 			  to_underlying (entry->type_offset_in_tu));
-  obstack_grow (info->types_list, val, 8);
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->signature);
-  obstack_grow (info->types_list, val, 8);
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE, entry->signature);
 
   ++info->cu_index;
 
@@ -23841,7 +23716,7 @@ static void
 recursively_write_psymbols (struct objfile *objfile,
 			    struct partial_symtab *psymtab,
 			    struct mapped_symtab *symtab,
-			    htab_t psyms_seen,
+			    std::unordered_set<partial_symbol *> &psyms_seen,
 			    offset_type cu_index)
 {
   int i;
@@ -23863,22 +23738,25 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
+/* Closes FILE on scope exit.  */
+struct file_closer
+{
+  explicit file_closer (FILE *file)
+    : m_file (file)
+  {}
+
+  ~file_closer ()
+  { fclose (m_file); }
+
+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)
 {
-  struct cleanup *cleanup;
-  char *filename;
-  struct obstack contents, addr_obstack, constant_pool, symtab_obstack;
-  struct obstack cu_list, types_cu_list;
-  int i;
-  FILE *out_file;
-  struct mapped_symtab *symtab;
-  offset_type val, size_of_contents, total_len;
-  struct stat st;
-  struct psymtab_cu_index_map *psymtab_cu_index_map;
-
   if (dwarf2_per_objfile->using_index)
     error (_("Cannot use an index to create the index"));
 
@@ -23888,58 +23766,39 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
     return;
 
+  struct stat st;
   if (stat (objfile_name (objfile), &st) < 0)
     perror_with_name (objfile_name (objfile));
 
-  filename = concat (dir, SLASH_STRING, lbasename (objfile_name (objfile)),
-		     INDEX_SUFFIX, (char *) NULL);
-  cleanup = make_cleanup (xfree, filename);
+  std::string filename (std::string (dir) + SLASH_STRING
+			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
 
-  out_file = gdb_fopen_cloexec (filename, "wb");
+  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
   if (!out_file)
-    error (_("Can't open `%s' for writing"), filename);
-
-  gdb::unlinker unlink_file (filename);
-
-  symtab = create_mapped_symtab ();
-  make_cleanup (cleanup_mapped_symtab, symtab);
+    error (_("Can't open `%s' for writing"), filename.c_str ());
 
-  obstack_init (&addr_obstack);
-  make_cleanup_obstack_free (&addr_obstack);
+  file_closer close_out_file (out_file);
+  gdb::unlinker unlink_file (filename.c_str ());
 
-  obstack_init (&cu_list);
-  make_cleanup_obstack_free (&cu_list);
-
-  obstack_init (&types_cu_list);
-  make_cleanup_obstack_free (&types_cu_list);
-
-  htab_up psyms_seen (htab_create_alloc (100, htab_hash_pointer,
-					 htab_eq_pointer,
-					 NULL, xcalloc, xfree));
+  mapped_symtab symtab;
+  data_buf cu_list;
+  std::unordered_set<partial_symbol *> psyms_seen;
 
   /* 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.  */
-  htab_up cu_index_htab (htab_create_alloc (100,
-					    hash_psymtab_cu_index,
-					    eq_psymtab_cu_index,
-					    NULL, xcalloc, xfree));
-  psymtab_cu_index_map = XNEWVEC (struct psymtab_cu_index_map,
-				  dwarf2_per_objfile->n_comp_units);
-  make_cleanup (xfree, psymtab_cu_index_map);
+  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.  */
-  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
 	= dwarf2_per_objfile->all_comp_units[i];
       struct partial_symtab *psymtab = per_cu->v.psymtab;
-      gdb_byte val[8];
-      struct psymtab_cu_index_map *map;
-      void **slot;
 
       /* 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
@@ -23948,36 +23807,32 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
 	continue;
 
       if (psymtab->user == NULL)
-	recursively_write_psymbols (objfile, psymtab, symtab,
-				    psyms_seen.get (), i);
+	recursively_write_psymbols (objfile, psymtab, &symtab,
+				    psyms_seen, i);
 
-      map = &psymtab_cu_index_map[i];
-      map->psymtab = psymtab;
-      map->cu_index = i;
-      slot = htab_find_slot (cu_index_htab.get (), map, INSERT);
-      gdb_assert (slot != NULL);
-      gdb_assert (*slot == NULL);
-      *slot = map;
+      const auto insertpair = cu_index_htab.emplace (psymtab, i);
+      gdb_assert (insertpair.second);
 
-      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE,
 			      to_underlying (per_cu->sect_off));
-      obstack_grow (&cu_list, val, 8);
-      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, per_cu->length);
-      obstack_grow (&cu_list, val, 8);
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE, per_cu->length);
     }
 
   /* Dump the address map.  */
-  write_address_map (objfile, &addr_obstack, cu_index_htab.get ());
+  data_buf addr_vec;
+  write_address_map (objfile, addr_vec, cu_index_htab);
 
   /* Write out the .debug_type entries, if any.  */
+  data_buf types_cu_list;
   if (dwarf2_per_objfile->signatured_types)
     {
-      struct signatured_type_index_data sig_data;
+      signatured_type_index_data sig_data (types_cu_list,
+					   psyms_seen);
 
       sig_data.objfile = objfile;
-      sig_data.symtab = symtab;
-      sig_data.types_list = &types_cu_list;
-      sig_data.psyms_seen = psyms_seen.get ();
+      sig_data.symtab = &symtab;
       sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
       htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
 			      write_one_signatured_type, &sig_data);
@@ -23985,63 +23840,49 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
 
   /* Now that we've processed all symbols we can shrink their cu_indices
      lists.  */
-  uniquify_cu_indices (symtab);
+  uniquify_cu_indices (&symtab);
 
-  obstack_init (&constant_pool);
-  make_cleanup_obstack_free (&constant_pool);
-  obstack_init (&symtab_obstack);
-  make_cleanup_obstack_free (&symtab_obstack);
-  write_hash_table (symtab, &symtab_obstack, &constant_pool);
+  data_buf symtab_vec, constant_pool;
+  write_hash_table (&symtab, symtab_vec, constant_pool);
 
-  obstack_init (&contents);
-  make_cleanup_obstack_free (&contents);
-  size_of_contents = 6 * sizeof (offset_type);
-  total_len = size_of_contents;
+  data_buf contents;
+  const offset_type size_of_contents = 6 * sizeof (offset_type);
+  offset_type total_len = size_of_contents;
 
   /* The version number.  */
-  val = MAYBE_SWAP (8);
-  obstack_grow (&contents, &val, sizeof (val));
+  contents.append_data (MAYBE_SWAP (8));
 
   /* The offset of the CU list from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&cu_list);
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += cu_list.size ();
 
   /* The offset of the types CU list from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&types_cu_list);
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += types_cu_list.size ();
 
   /* The offset of the address table from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&addr_obstack);
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += addr_vec.size ();
 
   /* The offset of the symbol table from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&symtab_obstack);
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += symtab_vec.size ();
 
   /* The offset of the constant pool from the start of the file.  */
-  val = MAYBE_SWAP (total_len);
-  obstack_grow (&contents, &val, sizeof (val));
-  total_len += obstack_object_size (&constant_pool);
-
-  gdb_assert (obstack_object_size (&contents) == size_of_contents);
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += constant_pool.size ();
 
-  write_obstack (out_file, &contents);
-  write_obstack (out_file, &cu_list);
-  write_obstack (out_file, &types_cu_list);
-  write_obstack (out_file, &addr_obstack);
-  write_obstack (out_file, &symtab_obstack);
-  write_obstack (out_file, &constant_pool);
+  gdb_assert (contents.size () == size_of_contents);
 
-  fclose (out_file);
+  contents.file_write (out_file);
+  cu_list.file_write (out_file);
+  types_cu_list.file_write (out_file);
+  addr_vec.file_write (out_file);
+  symtab_vec.file_write (out_file);
+  constant_pool.file_write (out_file);
 
   /* We want to keep the file.  */
   unlink_file.keep ();
-
-  do_cleanups (cleanup);
 }
 
 /* Implementation of the `save gdb-index' command.
-- 
2.5.5


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

* [PATCH 4/6] .gdb_index prod perf regression: find before insert in unordered_map
  2017-06-12 16:08   ` [pushed] " Pedro Alves
  2017-06-12 16:14     ` [PATCH 6/6] .gdb_index prod perf regression: mapped_symtab now vector of values Pedro Alves
@ 2017-06-12 16:14     ` Pedro Alves
  2017-06-12 16:14     ` [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write Pedro Alves
                       ` (6 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:14 UTC (permalink / raw)
  To: gdb-patches

"perf" shows the unordered_map::emplace call in write_hash_table a bit
high up on profiles.  Fix this using the find + insert idiom instead
of going straight to insert.

I tried doing the same to the other unordered_maps::emplace calls in
the file, but saw no performance improvement, so left them be.

With a '-g3 -O2' build of gdb, and:

  $ cat save-index.cmd
  set $i = 0
  while $i < 100
    save gdb-index .
    set $i = $i + 1
  end
  $ time ./gdb -data-directory=data-directory -nx --batch -q -x save-index.cmd  ./gdb.pristine

I get an improvement of ~7%:

  ~7.0s => ~6.5s (average of 5 runs).

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

	* dwarf2read.c (write_hash_table): Check if key already exists
	before emplacing.
---
 gdb/ChangeLog    |  5 +++++
 gdb/dwarf2read.c | 21 ++++++++++++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4c8657c..01b66a1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
 2017-06-12  Pedro Alves  <palves@redhat.com>
 
+	* dwarf2read.c (write_hash_table): Check if key already exists
+	before emplacing.
+
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
 	* dwarf2read.c (data_buf::append_space): Rename to...
 	(data_buf::grow): ... this, and make private.  Adjust all callers.
 	(data_buf::append_uint): New method.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 63a591e..93fd275 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23430,11 +23430,22 @@ write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
 	if (it == NULL)
 	  continue;
 	gdb_assert (it->index_offset == 0);
-	const auto insertpair
-	  = symbol_hash_table.emplace (it->cu_indices, cpool.size ());
-	it->index_offset = insertpair.first->second;
-	if (!insertpair.second)
-	  continue;
+
+	/* Finding before inserting is faster than always trying to
+	   insert, because inserting always allocates a node, does the
+	   lookup, and then destroys the new node if another node
+	   already had the same key.  C++17 try_emplace will avoid
+	   this.  */
+	const auto found
+	  = symbol_hash_table.find (it->cu_indices);
+	if (found != symbol_hash_table.end ())
+	  {
+	    it->index_offset = found->second;
+	    continue;
+	  }
+
+	symbol_hash_table.emplace (it->cu_indices, cpool.size ());
+	it->index_offset = cpool.size ();
 	cpool.append_data (MAYBE_SWAP (it->cu_indices.size ()));
 	for (const auto iter : it->cu_indices)
 	  cpool.append_data (MAYBE_SWAP (iter));
-- 
2.5.5

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

* [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-12 16:08   ` [pushed] " Pedro Alves
  2017-06-12 16:14     ` [PATCH 6/6] .gdb_index prod perf regression: mapped_symtab now vector of values Pedro Alves
  2017-06-12 16:14     ` [PATCH 4/6] .gdb_index prod perf regression: find before insert in unordered_map Pedro Alves
@ 2017-06-12 16:14     ` Pedro Alves
  2017-06-17 17:35       ` Jan Kratochvil
  2017-06-18 18:36       ` Regression: " Jan Kratochvil
  2017-06-12 16:14     ` [PATCH 3/6] Code cleanup: dwarf2read.c: Add data_buf::append_uint Pedro Alves
                       ` (5 subsequent siblings)
  8 siblings, 2 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:14 UTC (permalink / raw)
  To: gdb-patches

There's no real need for all this indirection.

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

	* dwarf2read.c (file_write(FILE *, const void *, size_t)): Delete.
	(file_write (FILE *, const std::vector<Elem>&)): Delete.
	(data_buf::file_write): Call ::fwrite directly.
---
 gdb/ChangeLog    |  6 ++++++
 gdb/dwarf2read.c | 22 ++--------------------
 2 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 316e03a..e3e980d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
 2017-06-12  Pedro Alves  <palves@redhat.com>
 
+	* dwarf2read.c (file_write(FILE *, const void *, size_t)): Delete.
+	(file_write (FILE *, const std::vector<Elem>&)): Delete.
+	(data_buf::file_write): Call ::fwrite directly.
+
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
 	* dwarf2read.c (uniquify_cu_indices): Use std::unique and
 	std::vector::erase.
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 0c9e275..55b3033 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23195,25 +23195,6 @@ 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]));
-}
-
 /* In-memory buffer to prepare data to be written later to a file.  */
 class data_buf
 {
@@ -23252,7 +23233,8 @@ public:
   /* Write the buffer to FILE.  */
   void file_write (FILE *file) const
   {
-    ::file_write (file, m_vec);
+    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
+      error (_("couldn't write data to file"));
   }
 
 private:
-- 
2.5.5

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

* [PATCH 3/6] Code cleanup: dwarf2read.c: Add data_buf::append_uint
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (2 preceding siblings ...)
  2017-06-12 16:14     ` [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write Pedro Alves
@ 2017-06-12 16:14     ` Pedro Alves
  2017-06-12 16:14     ` [PATCH 1/6] Code cleanup: dwarf2read.c:uniquify_cu_indices: Use std::unique Pedro Alves
                       ` (4 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:14 UTC (permalink / raw)
  To: gdb-patches

This avoids having to specify the integer size twice in the same line.

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

	* dwarf2read.c (data_buf::append_space): Rename to...
	(data_buf::grow): ... this, and make private.  Adjust all callers.
	(data_buf::append_uint): New method.
	(add_address_entry, write_one_signatured_type)
	(write_psymtabs_to_index): Use it.
---
 gdb/ChangeLog    |  8 ++++++++
 gdb/dwarf2read.c | 58 ++++++++++++++++++++++++++++----------------------------
 2 files changed, 37 insertions(+), 29 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e3e980d..4c8657c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
 2017-06-12  Pedro Alves  <palves@redhat.com>
 
+	* dwarf2read.c (data_buf::append_space): Rename to...
+	(data_buf::grow): ... this, and make private.  Adjust all callers.
+	(data_buf::append_uint): New method.
+	(add_address_entry, write_one_signatured_type)
+	(write_psymtabs_to_index): Use it.
+
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
 	* dwarf2read.c (file_write(FILE *, const void *, size_t)): Delete.
 	(file_write (FILE *, const std::vector<Elem>&)): Delete.
 	(data_buf::file_write): Call ::fwrite directly.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 55b3033..63a591e 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23199,29 +23199,28 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 class data_buf
 {
 public:
-  /* Add SIZE bytes at the end of the buffer.  Returns a pointer to
-     the start of the new block.  */
-  gdb_byte *append_space (size_t size)
-  {
-    m_vec.resize (m_vec.size () + size);
-    return &*m_vec.end () - size;
-  }
-
   /* Copy DATA to the end of the buffer.  */
   template<typename T>
   void append_data (const T &data)
   {
     std::copy (reinterpret_cast<const gdb_byte *> (&data),
 	       reinterpret_cast<const gdb_byte *> (&data + 1),
-	       append_space (sizeof (data)));
+	       grow (sizeof (data)));
   }
 
-  /* Copy CSTR (a null-terminated string) to the end of the buffer.
-     The terminating null is appended too.  */
+  /* Copy CSTR (a zero-terminated string) to the end of buffer.  The
+     terminating zero is appended too.  */
   void append_cstr0 (const char *cstr)
   {
     const size_t size = strlen (cstr) + 1;
-    std::copy (cstr, cstr + size, append_space (size));
+    std::copy (cstr, cstr + size, grow (size));
+  }
+
+  /* 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)
+  {
+    ::store_unsigned_integer (grow (len), len, byte_order, val);
   }
 
   /* Return the size of the buffer.  */
@@ -23238,6 +23237,14 @@ public:
   }
 
 private:
+  /* Grow SIZE bytes at the end of the buffer.  Returns a pointer to
+     the start of the new block.  */
+  gdb_byte *grow (size_t size)
+  {
+    m_vec.resize (m_vec.size () + size);
+    return &*m_vec.end () - size;
+  }
+
   std::vector<gdb_byte> m_vec;
 };
 
@@ -23494,10 +23501,8 @@ add_address_entry (struct objfile *objfile, data_buf &addr_vec,
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
-			  start - baseaddr);
-  store_unsigned_integer (addr_vec.append_space (8), 8, BFD_ENDIAN_LITTLE,
-			  end - baseaddr);
+  addr_vec.append_uint (8, BFD_ENDIAN_LITTLE, start - baseaddr);
+  addr_vec.append_uint (8, BFD_ENDIAN_LITTLE, end - baseaddr);
   addr_vec.append_data (MAYBE_SWAP (cu_index));
 }
 
@@ -23664,14 +23669,11 @@ write_one_signatured_type (void **slot, void *d)
 		  psymtab->n_static_syms, info->cu_index,
 		  1);
 
-  store_unsigned_integer (info->types_list.append_space (8), 8,
-			  BFD_ENDIAN_LITTLE,
-			  to_underlying (entry->per_cu.sect_off));
-  store_unsigned_integer (info->types_list.append_space (8), 8,
-			  BFD_ENDIAN_LITTLE,
-			  to_underlying (entry->type_offset_in_tu));
-  store_unsigned_integer (info->types_list.append_space (8), 8,
-			  BFD_ENDIAN_LITTLE, entry->signature);
+  info->types_list.append_uint (8, BFD_ENDIAN_LITTLE,
+				to_underlying (entry->per_cu.sect_off));
+  info->types_list.append_uint (8, BFD_ENDIAN_LITTLE,
+				to_underlying (entry->type_offset_in_tu));
+  info->types_list.append_uint (8, BFD_ENDIAN_LITTLE, entry->signature);
 
   ++info->cu_index;
 
@@ -23782,11 +23784,9 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
       const auto insertpair = cu_index_htab.emplace (psymtab, i);
       gdb_assert (insertpair.second);
 
-      store_unsigned_integer (cu_list.append_space (8), 8,
-			      BFD_ENDIAN_LITTLE,
-			      to_underlying (per_cu->sect_off));
-      store_unsigned_integer (cu_list.append_space (8), 8,
-			      BFD_ENDIAN_LITTLE, per_cu->length);
+      cu_list.append_uint (8, BFD_ENDIAN_LITTLE,
+			   to_underlying (per_cu->sect_off));
+      cu_list.append_uint (8, BFD_ENDIAN_LITTLE, per_cu->length);
     }
 
   /* Dump the address map.  */
-- 
2.5.5

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

* [PATCH 6/6] .gdb_index prod perf regression: mapped_symtab now vector of values
  2017-06-12 16:08   ` [pushed] " Pedro Alves
@ 2017-06-12 16:14     ` Pedro Alves
  2017-06-12 16:14     ` [PATCH 4/6] .gdb_index prod perf regression: find before insert in unordered_map Pedro Alves
                       ` (7 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:14 UTC (permalink / raw)
  To: gdb-patches

... instead of vector of pointers

There's no real reason for having mapped_symtab::data be a vector of
heap-allocated symtab_index_entries.  symtab_index_entries is not that
large, it's movable, and it's cheap to move.  Making the vector hold
values instead improves cache locality and eliminates many roundtrips
to the heap.

Using the same test as in the previous patch, against the same gdb
inferior, timing improves ~13% further:

  ~6.0s => ~5.2s (average of 5 runs).

Note that before the .gdb_index C++ifycation patch, we were at ~5.7s.
We're now consistenly better than before.

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

	* dwarf2read.c (mapped_symtab::data): Now a vector of
	symtab_index_entry instead of vector of
	std::unique_ptr<symtab_index_entry>.  All users adjusted to check
	whether an element's name is NULL instead of checking whether the
	element itself is NULL.
	(find_slot): Change return type.  Adjust.
	(hash_expand, , add_index_entry, uniquify_cu_indices)
	(write_hash_table): Adjust.
---
 gdb/ChangeLog    | 11 +++++++++++
 gdb/dwarf2read.c | 56 ++++++++++++++++++++++++++++----------------------------
 2 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9dbc059..82f972a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,16 @@
 2017-06-12  Pedro Alves  <palves@redhat.com>
 
+	* dwarf2read.c (mapped_symtab::data): Now a vector of
+	symtab_index_entry instead of vector of
+	std::unique_ptr<symtab_index_entry>.  All users adjusted to check
+	whether an element's name is NULL instead of checking whether the
+	element itself is NULL.
+	(find_slot): Change return type.  Adjust.
+	(hash_expand, , add_index_entry, uniquify_cu_indices)
+	(write_hash_table): Adjust.
+
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
 	* dwarf2read.c (recursively_count_psymbols): New function.
 	(write_psymtabs_to_index): Call it to compute number of psyms and
 	pass estimate size of psyms_seen to unordered_set's ctor.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index bff2fcb..3f872b7 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23269,7 +23269,7 @@ struct mapped_symtab
   }
 
   offset_type n_elements = 0;
-  std::vector<std::unique_ptr<symtab_index_entry>> data;
+  std::vector<symtab_index_entry> data;
 };
 
 /* Find a slot in SYMTAB for the symbol NAME.  Returns a reference to
@@ -23278,7 +23278,7 @@ struct mapped_symtab
    Function is used only during write_hash_table so no index format backward
    compatibility is needed.  */
 
-static std::unique_ptr<symtab_index_entry> &
+static symtab_index_entry &
 find_slot (struct mapped_symtab *symtab, const char *name)
 {
   offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
@@ -23288,7 +23288,8 @@ find_slot (struct mapped_symtab *symtab, const char *name)
 
   for (;;)
     {
-      if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
+      if (symtab->data[index].name == NULL
+	  || strcmp (name, symtab->data[index].name) == 0)
 	return symtab->data[index];
       index = (index + step) & (symtab->data.size () - 1);
     }
@@ -23305,9 +23306,9 @@ hash_expand (struct mapped_symtab *symtab)
   symtab->data.resize (old_entries.size () * 2);
 
   for (auto &it : old_entries)
-    if (it != NULL)
+    if (it.name != NULL)
       {
-	auto &ref = find_slot (symtab, it->name);
+	auto &ref = find_slot (symtab, it.name);
 	ref = std::move (it);
       }
 }
@@ -23327,11 +23328,10 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
   if (4 * symtab->n_elements / 3 >= symtab->data.size ())
     hash_expand (symtab);
 
-  std::unique_ptr<symtab_index_entry> &slot = find_slot (symtab, name);
-  if (slot == NULL)
+  symtab_index_entry &slot = find_slot (symtab, name);
+  if (slot.name == NULL)
     {
-      slot.reset (new symtab_index_entry ());
-      slot->name = name;
+      slot.name = name;
       /* index_offset is set later.  */
     }
 
@@ -23347,7 +23347,7 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
      the last entry pushed), but a symbol could have multiple kinds in one CU.
      To keep things simple we don't worry about the duplication here and
      sort and uniqufy the list after we've processed all symbols.  */
-  slot->cu_indices.push_back (cu_index_and_attrs);
+  slot.cu_indices.push_back (cu_index_and_attrs);
 }
 
 /* Sort and remove duplicates of all symbols' cu_indices lists.  */
@@ -23355,11 +23355,11 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
 static void
 uniquify_cu_indices (struct mapped_symtab *symtab)
 {
-  for (const auto &entry : symtab->data)
+  for (auto &entry : symtab->data)
     {
-      if (entry && !entry->cu_indices.empty ())
+      if (entry.name != NULL && !entry.cu_indices.empty ())
 	{
-	  auto &cu_indices = entry->cu_indices;
+	  auto &cu_indices = entry.cu_indices;
 	  std::sort (cu_indices.begin (), cu_indices.end ());
 	  auto from = std::unique (cu_indices.begin (), cu_indices.end ());
 	  cu_indices.erase (from, cu_indices.end ());
@@ -23425,11 +23425,11 @@ write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
 
     /* We add all the index vectors to the constant pool first, to
        ensure alignment is ok.  */
-    for (const std::unique_ptr<symtab_index_entry> &it : symtab->data)
+    for (symtab_index_entry &entry : symtab->data)
       {
-	if (it == NULL)
+	if (entry.name == NULL)
 	  continue;
-	gdb_assert (it->index_offset == 0);
+	gdb_assert (entry.index_offset == 0);
 
 	/* Finding before inserting is faster than always trying to
 	   insert, because inserting always allocates a node, does the
@@ -23437,34 +23437,34 @@ write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
 	   already had the same key.  C++17 try_emplace will avoid
 	   this.  */
 	const auto found
-	  = symbol_hash_table.find (it->cu_indices);
+	  = symbol_hash_table.find (entry.cu_indices);
 	if (found != symbol_hash_table.end ())
 	  {
-	    it->index_offset = found->second;
+	    entry.index_offset = found->second;
 	    continue;
 	  }
 
-	symbol_hash_table.emplace (it->cu_indices, cpool.size ());
-	it->index_offset = cpool.size ();
-	cpool.append_data (MAYBE_SWAP (it->cu_indices.size ()));
-	for (const auto iter : it->cu_indices)
-	  cpool.append_data (MAYBE_SWAP (iter));
+	symbol_hash_table.emplace (entry.cu_indices, cpool.size ());
+	entry.index_offset = cpool.size ();
+	cpool.append_data (MAYBE_SWAP (entry.cu_indices.size ()));
+	for (const auto index : entry.cu_indices)
+	  cpool.append_data (MAYBE_SWAP (index));
       }
   }
 
   /* Now write out the hash table.  */
   std::unordered_map<c_str_view, offset_type, c_str_view_hasher> str_table;
-  for (const auto &it : symtab->data)
+  for (const auto &entry : symtab->data)
     {
       offset_type str_off, vec_off;
 
-      if (it != NULL)
+      if (entry.name != NULL)
 	{
-	  const auto insertpair = str_table.emplace (it->name, cpool.size ());
+	  const auto insertpair = str_table.emplace (entry.name, cpool.size ());
 	  if (insertpair.second)
-	    cpool.append_cstr0 (it->name);
+	    cpool.append_cstr0 (entry.name);
 	  str_off = insertpair.first->second;
-	  vec_off = it->index_offset;
+	  vec_off = entry.index_offset;
 	}
       else
 	{
-- 
2.5.5

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

* [PATCH 1/6] Code cleanup: dwarf2read.c:uniquify_cu_indices: Use std::unique
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (3 preceding siblings ...)
  2017-06-12 16:14     ` [PATCH 3/6] Code cleanup: dwarf2read.c: Add data_buf::append_uint Pedro Alves
@ 2017-06-12 16:14     ` Pedro Alves
  2017-06-12 16:18     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Pedro Alves
                       ` (3 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:14 UTC (permalink / raw)
  To: gdb-patches

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

	* dwarf2read.c (uniquify_cu_indices): Use std::unique and
	std::vector::erase.
---
 gdb/ChangeLog    |  5 +++++
 gdb/dwarf2read.c | 21 ++++-----------------
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 037fa0c..316e03a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
+	* dwarf2read.c (uniquify_cu_indices): Use std::unique and
+	std::vector::erase.
+
 2017-06-12  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	Code cleanup: C++ify .gdb_index producer.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index ef21092..0c9e275 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23370,23 +23370,10 @@ uniquify_cu_indices (struct mapped_symtab *symtab)
     {
       if (entry && !entry->cu_indices.empty ())
 	{
-	  unsigned int next_to_insert, next_to_check;
-	  offset_type last_value;
-
-	  std::sort (entry->cu_indices.begin (), entry->cu_indices.end ());
-
-	  last_value = entry->cu_indices[0];
-	  next_to_insert = 1;
-	  for (next_to_check = 1;
-	       next_to_check < entry->cu_indices.size ();
-	       ++next_to_check)
-	    if (entry->cu_indices[next_to_check] != last_value)
-	      {
-		last_value = entry->cu_indices[next_to_check];
-		entry->cu_indices[next_to_insert] = last_value;
-		++next_to_insert;
-	      }
-	  entry->cu_indices.resize (next_to_insert);
+	  auto &cu_indices = entry->cu_indices;
+	  std::sort (cu_indices.begin (), cu_indices.end ());
+	  auto from = std::unique (cu_indices.begin (), cu_indices.end ());
+	  cu_indices.erase (from, cu_indices.end ());
 	}
     }
 }
-- 
2.5.5

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

* Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (4 preceding siblings ...)
  2017-06-12 16:14     ` [PATCH 1/6] Code cleanup: dwarf2read.c:uniquify_cu_indices: Use std::unique Pedro Alves
@ 2017-06-12 16:18     ` Pedro Alves
  2017-06-12 16:19     ` [PATCH 5/6] .gdb_index prod perf regression: Estimate size of psyms_seen Pedro Alves
                       ` (2 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:18 UTC (permalink / raw)
  To: Jan Kratochvil, gdb-patches; +Cc: Victor Leschuk

On 06/12/2017 05:08 PM, Pedro Alves wrote:

> Thanks.  This looks generally good.
> 
> It had a number of GDB/GCC code convention issues though.
> 
> - Should use /**/ for comments.
> - CamelCase should only used in template parameters.
> - Function/ctors should be placed before data members.
> - Private data members should be prefixed with "m_".
> - Some function intro comments still referred to
>   obstacks, while the functions now take a DataBuf.
> 
> Also, the big TRY block would be better done with a RAII type.
> Tromey posted a patch to add a unique_ptr with a deleter that calls
> fclose, and makes that code use it, but that's not merged yet.
> Meanwhile we can add a little RAII class locally that does the
> same thing, still avoiding the churn.

(...)

> Anyway, in interest of forward progress:
> 
> - I fixed up the style issues mentioned above, and pushed the
>   result in, as below.  I'll post the diff as a reply to this
>   email.
> 
>   I'd much appreciate it if you'd adjust the rest of the series
>   similarly.


Thanks,
Pedro Alves


diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h
index e624c5e..439bce6 100644
--- a/gdb/common/common-defs.h
+++ b/gdb/common/common-defs.h
@@ -91,18 +91,4 @@
 /* Pull in gdb::unique_xmalloc_ptr.  */
 #include "common/gdb_unique_ptr.h"
 
-// Provide C++14 std::make_unique<> for C++11 compilation mode.
-// A copy from: gcc/libstdc++-v3/include/bits/unique_ptr.h
-#if __cplusplus <= 201103L
-namespace std {
-  template<typename _Tp>
-    struct _MakeUniq
-    { typedef unique_ptr<_Tp> __single_object; };
-  template<typename _Tp, typename... _Args>
-    inline typename _MakeUniq<_Tp>::__single_object
-    make_unique(_Args&&... __args)
-    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
-}
-#endif
-
 #endif /* COMMON_DEFS_H */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 12a194a..c5c5d55 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -69,6 +69,7 @@
 #include "filestuff.h"
 #include "build-id.h"
 #include "namespace.h"
+#include "common/gdb_unlinker.h"
 #include "common/function-view.h"
 #include "common/gdb_optional.h"
 #include "common/underlying.h"
@@ -23194,7 +23195,8 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 \f
 /* The "save gdb-index" command.  */
 
-// Write to FILE bytes starting at DATA of length SIZE with error checking.
+/* 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)
@@ -23203,66 +23205,58 @@ file_write (FILE *file, const void *data, size_t size)
     error (_("couldn't data write to file"));
 }
 
-// Write to FILE bytes of std::vector VEC with error checking.
+/* Write the contents of VEC to FILE, with error checking.  */
 
-template<class Elem> static void
+template<class Elem>
+static void
 file_write (FILE *file, const std::vector<Elem> &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 DataBuf
+/* In-memory buffer to prepare data to be written later to a file.  */
+class data_buf
 {
-private:
-  std::vector<gdb_byte> vec;
 public:
-
-  // Append space of SIZE number of bytes to the end of buffer.
-  // Return pointer to its start.
-
-  gdb_byte *
-  append_space (size_t size)
+  /* Add SIZE bytes at the end of the buffer.  Returns a pointer to
+     the start of the new block.  */
+  gdb_byte *append_space (size_t size)
   {
-    vec.resize (vec.size () + size);
-    return &*vec.end () - size;
+    m_vec.resize (m_vec.size () + size);
+    return &*m_vec.end () - size;
   }
 
-  // Copy DATA to the end of buffer.
-
-  template<typename T> void
-  append_data (const T &data)
+  /* Copy DATA to the end of the buffer.  */
+  template<typename T>
+  void append_data (const T &data)
   {
     std::copy (reinterpret_cast<const gdb_byte *> (&data),
 	       reinterpret_cast<const gdb_byte *> (&data + 1),
 	       append_space (sizeof (data)));
   }
 
-  // Copy CSTR zero-terminated string to the end of buffer including its
-  // terminating zero.
-
-  void
-  append_cstr0 (const char *cstr)
+  /* Copy CSTR (a null-terminated string) to the end of the buffer.
+     The terminating null is appended too.  */
+  void append_cstr0 (const char *cstr)
   {
-    const size_t size (strlen (cstr) + 1);
+    const size_t size = strlen (cstr) + 1;
     std::copy (cstr, cstr + size, append_space (size));
   }
 
-  // Return size of the buffer.
-
-  size_t
-  size () const
+  /* Return the size of the buffer.  */
+  size_t size () const
   {
-    return vec.size ();
+    return m_vec.size ();
   }
 
   /* Write the buffer to FILE.  */
-
-  void
-  file_write (FILE *file) const
+  void file_write (FILE *file) const
   {
-    ::file_write (file, vec);
+    ::file_write (file, m_vec);
   }
+
+private:
+  std::vector<gdb_byte> m_vec;
 };
 
 /* An entry in the symbol table.  */
@@ -23280,13 +23274,13 @@ struct symtab_index_entry
 /* The symbol table.  This is a power-of-2-sized hash table.  */
 struct mapped_symtab
 {
-public:
-  offset_type n_elements = 0;
-  std::vector<std::unique_ptr<symtab_index_entry>> data;
   mapped_symtab ()
   {
     data.resize (1024);
   }
+
+  offset_type n_elements = 0;
+  std::vector<std::unique_ptr<symtab_index_entry>> data;
 };
 
 /* Find a slot in SYMTAB for the symbol NAME.  Returns a reference to
@@ -23316,15 +23310,15 @@ find_slot (struct mapped_symtab *symtab, const char *name)
 static void
 hash_expand (struct mapped_symtab *symtab)
 {
-  auto old_entries (std::move (symtab->data));
+  auto old_entries = std::move (symtab->data);
 
   symtab->data.clear ();
   symtab->data.resize (old_entries.size () * 2);
 
-  for (auto &it:old_entries)
-    if (it)
+  for (auto &it : old_entries)
+    if (it != NULL)
       {
-	auto &ref (find_slot (symtab, it->name));
+	auto &ref = find_slot (symtab, it->name);
 	ref = std::move (it);
       }
 }
@@ -23344,10 +23338,10 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
   if (4 * symtab->n_elements / 3 >= symtab->data.size ())
     hash_expand (symtab);
 
-  std::unique_ptr<symtab_index_entry> &slot (find_slot (symtab, name));
-  if (!slot)
+  std::unique_ptr<symtab_index_entry> &slot = find_slot (symtab, name);
+  if (slot == NULL)
     {
-      slot = std::make_unique<symtab_index_entry> ();
+      slot.reset (new symtab_index_entry ());
       slot->name = name;
       /* index_offset is set later.  */
     }
@@ -23372,7 +23366,7 @@ add_index_entry (struct mapped_symtab *symtab, const char *name,
 static void
 uniquify_cu_indices (struct mapped_symtab *symtab)
 {
-  for (const auto &entry:symtab->data)
+  for (const auto &entry : symtab->data)
     {
       if (entry && !entry->cu_indices.empty ())
 	{
@@ -23397,87 +23391,89 @@ uniquify_cu_indices (struct mapped_symtab *symtab)
     }
 }
 
-// Provide form of const char * suitable for container keys.
-// Only the pointer is being stored.
-// Comparison is done for the strings themselves - not for the pointer.
-class CstrView {
-private:
-  friend class CstrViewHasher;
-  const char *const cstr;
+/* A form of 'const char *' suitable for container keys.  Only the
+   pointer is stored.  The strings themselves are compared, not the
+   pointers.  */
+class c_str_view
+{
 public:
-  CstrView (const char *cstr_) : cstr (cstr_)
-  {
-  }
-  bool
-  operator == (const CstrView &other) const
+  c_str_view (const char *cstr)
+    : m_cstr (cstr)
+  {}
+
+  bool operator== (const c_str_view &other) const
   {
-    return !strcmp (cstr, other.cstr);
+    return strcmp (m_cstr, other.m_cstr) == 0;
   }
+
+private:
+  friend class c_str_view_hasher;
+  const char *const m_cstr;
 };
 
-// Provide std::unordered_map::hasher for CstrView.
-class CstrViewHasher
+/* A std::unordered_map::hasher for c_str_view that uses the right
+   hash function for strings in a mapped index.  */
+class c_str_view_hasher
 {
 public:
-  size_t
-  operator () (const CstrView &x) const
+  size_t operator () (const c_str_view &x) const
   {
-    return mapped_index_string_hash (INT_MAX, x.cstr);
+    return mapped_index_string_hash (INT_MAX, x.m_cstr);
   }
 };
 
-// Provide std::unordered_map::hasher for std::vector<>.
-template<class T> class VectorHasher
+/* A std::unordered_map::hasher for std::vector<>.  */
+template<class T>
+class vector_hasher
 {
 public:
-  size_t
-  operator () (const std::vector<T> &key) const
+  size_t operator () (const std::vector<T> &key) const
   {
-    // return boost::hash_value<std::vector<T>> (key);
     return iterative_hash (key.data (),
 			   sizeof (key.front ()) * key.size (), 0);
   }
 };
 
-/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
-   constant pool entries going into the obstack CPOOL.  */
+/* Write the mapped hash table SYMTAB to the data buffer OUTPUT, with
+   constant pool entries going into the data buffer CPOOL.  */
 
 static void
-write_hash_table (struct mapped_symtab *symtab, DataBuf &output, DataBuf &cpool)
+write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
 {
   {
-    /* Elements are sorted vectors of the indices of all the CUs that hold
-       an object of this name.  */
+    /* Elements are sorted vectors of the indices of all the CUs that
+       hold an object of this name.  */
     std::unordered_map<std::vector<offset_type>, offset_type,
-		       VectorHasher<offset_type>> symbol_hash_table;
+		       vector_hasher<offset_type>>
+      symbol_hash_table;
 
     /* We add all the index vectors to the constant pool first, to
        ensure alignment is ok.  */
-    for (const std::unique_ptr<symtab_index_entry> &it:symtab->data)
+    for (const std::unique_ptr<symtab_index_entry> &it : symtab->data)
       {
-	if (!it)
+	if (it == NULL)
 	  continue;
 	gdb_assert (it->index_offset == 0);
-	const auto insertpair (symbol_hash_table.emplace (it->cu_indices,
-							  cpool.size ()));
+	const auto insertpair
+	  = symbol_hash_table.emplace (it->cu_indices, cpool.size ());
 	it->index_offset = insertpair.first->second;
 	if (!insertpair.second)
 	  continue;
 	cpool.append_data (MAYBE_SWAP (it->cu_indices.size ()));
-	for (const auto iter:it->cu_indices)
+	for (const auto iter : it->cu_indices)
 	  cpool.append_data (MAYBE_SWAP (iter));
       }
   }
 
   /* Now write out the hash table.  */
-  std::unordered_map<CstrView, offset_type, CstrViewHasher> str_table;
-  for (const auto &it:symtab->data)
+  std::unordered_map<c_str_view, offset_type, c_str_view_hasher> str_table;
+  for (const auto &it : symtab->data)
     {
       offset_type str_off, vec_off;
 
-      if (it)
+      if (it != NULL)
 	{
-	  const auto insertpair (str_table.emplace (it->name, cpool.size ()));
+	  const auto insertpair = str_table.emplace (it->name, cpool.size ());
 	  if (insertpair.second)
 	    cpool.append_cstr0 (it->name);
 	  str_off = insertpair.first->second;
@@ -23496,12 +23492,18 @@ write_hash_table (struct mapped_symtab *symtab, DataBuf &output, DataBuf &cpool)
     }
 }
 
+typedef std::unordered_map<partial_symtab *, unsigned int> psym_index_map;
+
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
+  addrmap_index_data (data_buf &addr_vec_, psym_index_map &cu_index_htab_)
+    : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
+  {}
+
   struct objfile *objfile;
-  DataBuf &addr_vec;
-  std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab;
+  data_buf &addr_vec;
+  psym_index_map &cu_index_htab;
 
   /* Non-zero if the previous_* fields are valid.
      We can't write an entry until we see the next entry (since it is only then
@@ -23511,17 +23513,12 @@ struct addrmap_index_data
   unsigned int previous_cu_index;
   /* Start address of the CU.  */
   CORE_ADDR previous_cu_start;
-
-  addrmap_index_data (DataBuf &addr_vec_,
-      std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab_)
-  : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
-  {}
 };
 
-/* Write an address entry to OBSTACK.  */
+/* Write an address entry to ADDR_VEC.  */
 
 static void
-add_address_entry (struct objfile *objfile, DataBuf &addr_vec,
+add_address_entry (struct objfile *objfile, data_buf &addr_vec,
 		   CORE_ADDR start, CORE_ADDR end, unsigned int cu_index)
 {
   CORE_ADDR baseaddr;
@@ -23551,24 +23548,24 @@ add_address_entry_worker (void *datap, CORE_ADDR start_addr, void *obj)
   data->previous_cu_start = start_addr;
   if (pst != NULL)
     {
-      const auto it (data->cu_index_htab.find (pst));
+      const auto it = data->cu_index_htab.find (pst);
       gdb_assert (it != data->cu_index_htab.cend ());
       data->previous_cu_index = it->second;
       data->previous_valid = 1;
     }
   else
-      data->previous_valid = 0;
+    data->previous_valid = 0;
 
   return 0;
 }
 
-/* Write OBJFILE's address map to OBSTACK.
+/* Write OBJFILE's address map to ADDR_VEC.
    CU_INDEX_HTAB is used to map addrmap entries to their CU indices
    in the index file.  */
 
 static void
-write_address_map (struct objfile *objfile, DataBuf &addr_vec,
-       std::unordered_map<struct partial_symtab *, unsigned int> &cu_index_htab)
+write_address_map (struct objfile *objfile, data_buf &addr_vec,
+		   psym_index_map &cu_index_htab)
 {
   struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
@@ -23662,16 +23659,16 @@ write_psymbols (struct mapped_symtab *symtab,
 /* A helper struct used when iterating over debug_types.  */
 struct signatured_type_index_data
 {
+  signatured_type_index_data (data_buf &types_list_,
+                              std::unordered_set<partial_symbol *> &psyms_seen_)
+    :types_list (types_list_), psyms_seen (psyms_seen_)
+  {}
+
   struct objfile *objfile;
   struct mapped_symtab *symtab;
-  DataBuf &types_list;
+  data_buf &types_list;
   std::unordered_set<partial_symbol *> &psyms_seen;
   int cu_index;
-
-  signatured_type_index_data (DataBuf &types_list_,
-                              std::unordered_set<partial_symbol *> &psyms_seen_)
-  :types_list (types_list_), psyms_seen (psyms_seen_)
-  {}
 };
 
 /* A helper function that writes a single signatured_type to an
@@ -23741,6 +23738,20 @@ recursively_write_psymbols (struct objfile *objfile,
 		  1);
 }
 
+/* Closes FILE on scope exit.  */
+struct file_closer
+{
+  explicit file_closer (FILE *file)
+    : m_file (file)
+  {}
+
+  ~file_closer ()
+  { fclose (m_file); }
+
+private:
+  FILE *m_file;
+};
+
 /* Create an index file for OBJFILE in the directory DIR.  */
 
 static void
@@ -23762,121 +23773,116 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   std::string filename (std::string (dir) + SLASH_STRING
 			+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
 
-  FILE *out_file (gdb_fopen_cloexec (filename.c_str (), "wb"));
+  FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
   if (!out_file)
     error (_("Can't open `%s' for writing"), filename.c_str ());
 
-  TRY
-    {
-      mapped_symtab symtab;
-      DataBuf cu_list;
-      std::unordered_set<partial_symbol *> psyms_seen;
-
-      /* 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.  */
-      std::unordered_map<struct partial_symtab *, unsigned int> 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.  */
-      for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
-	{
-	  struct dwarf2_per_cu_data *per_cu
-	    = dwarf2_per_objfile->all_comp_units[i];
-	  struct 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;
+  file_closer close_out_file (out_file);
+  gdb::unlinker unlink_file (filename.c_str ());
+
+  mapped_symtab symtab;
+  data_buf cu_list;
+  std::unordered_set<partial_symbol *> psyms_seen;
+
+  /* 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.  */
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *per_cu
+	= dwarf2_per_objfile->all_comp_units[i];
+      struct 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)
-	    recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
-					i);
+      if (psymtab->user == NULL)
+	recursively_write_psymbols (objfile, psymtab, &symtab,
+				    psyms_seen, i);
 
-	  const auto insertpair (cu_index_htab.emplace (psymtab, i));
-	  gdb_assert (insertpair.second);
+      const auto insertpair = cu_index_htab.emplace (psymtab, i);
+      gdb_assert (insertpair.second);
 
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE,
-				  to_underlying (per_cu->sect_off));
-	  store_unsigned_integer (cu_list.append_space (8), 8,
-				  BFD_ENDIAN_LITTLE, per_cu->length);
-	}
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE,
+			      to_underlying (per_cu->sect_off));
+      store_unsigned_integer (cu_list.append_space (8), 8,
+			      BFD_ENDIAN_LITTLE, per_cu->length);
+    }
 
-      /* Dump the address map.  */
-      DataBuf addr_vec;
-      write_address_map (objfile, addr_vec, cu_index_htab);
+  /* Dump the address map.  */
+  data_buf addr_vec;
+  write_address_map (objfile, addr_vec, cu_index_htab);
 
-      /* Write out the .debug_type entries, if any.  */
-      DataBuf types_cu_list;
-      if (dwarf2_per_objfile->signatured_types)
-	{
-	  struct signatured_type_index_data sig_data (types_cu_list,
-						      psyms_seen);
-
-	  sig_data.objfile = objfile;
-	  sig_data.symtab = &symtab;
-	  sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
-	  htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
-				  write_one_signatured_type, &sig_data);
-	}
+  /* Write out the .debug_type entries, if any.  */
+  data_buf types_cu_list;
+  if (dwarf2_per_objfile->signatured_types)
+    {
+      signatured_type_index_data sig_data (types_cu_list,
+					   psyms_seen);
 
-      /* Now that we've processed all symbols we can shrink their cu_indices
-	 lists.  */
-      uniquify_cu_indices (&symtab);
+      sig_data.objfile = objfile;
+      sig_data.symtab = &symtab;
+      sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
+      htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+			      write_one_signatured_type, &sig_data);
+    }
 
-      DataBuf symtab_vec, constant_pool;
-      write_hash_table (&symtab, symtab_vec, constant_pool);
+  /* Now that we've processed all symbols we can shrink their cu_indices
+     lists.  */
+  uniquify_cu_indices (&symtab);
 
-      DataBuf contents;
-      const offset_type size_of_contents (6 * sizeof (offset_type));
-      offset_type total_len (size_of_contents);
+  data_buf symtab_vec, constant_pool;
+  write_hash_table (&symtab, symtab_vec, constant_pool);
 
-      /* The version number.  */
-      contents.append_data (MAYBE_SWAP (8));
+  data_buf contents;
+  const offset_type size_of_contents = 6 * sizeof (offset_type);
+  offset_type total_len = size_of_contents;
 
-      /* The offset of the CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += cu_list.size ();
+  /* The version number.  */
+  contents.append_data (MAYBE_SWAP (8));
 
-      /* The offset of the types CU list from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += types_cu_list.size ();
+  /* The offset of the CU list from the start of the file.  */
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += cu_list.size ();
 
-      /* The offset of the address table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += addr_vec.size ();
+  /* The offset of the types CU list from the start of the file.  */
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += types_cu_list.size ();
 
-      /* The offset of the symbol table from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += symtab_vec.size ();
+  /* The offset of the address table from the start of the file.  */
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += addr_vec.size ();
 
-      /* The offset of the constant pool from the start of the file.  */
-      contents.append_data (MAYBE_SWAP (total_len));
-      total_len += constant_pool.size ();
+  /* The offset of the symbol table from the start of the file.  */
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += symtab_vec.size ();
 
-      gdb_assert (contents.size () == size_of_contents);
+  /* The offset of the constant pool from the start of the file.  */
+  contents.append_data (MAYBE_SWAP (total_len));
+  total_len += constant_pool.size ();
 
-      contents.file_write (out_file);
-      cu_list.file_write (out_file);
-      types_cu_list.file_write (out_file);
-      addr_vec.file_write (out_file);
-      symtab_vec.file_write (out_file);
-      constant_pool.file_write (out_file);
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      fclose (out_file);
-      unlink (filename.c_str ());
-      throw_exception (except);
-    }
-  END_CATCH
-  fclose (out_file);
+  gdb_assert (contents.size () == size_of_contents);
+
+  contents.file_write (out_file);
+  cu_list.file_write (out_file);
+  types_cu_list.file_write (out_file);
+  addr_vec.file_write (out_file);
+  symtab_vec.file_write (out_file);
+  constant_pool.file_write (out_file);
+
+  /* We want to keep the file.  */
+  unlink_file.keep ();
 }
 
 /* Implementation of the `save gdb-index' command.

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

* [PATCH 5/6] .gdb_index prod perf regression: Estimate size of psyms_seen
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (5 preceding siblings ...)
  2017-06-12 16:18     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Pedro Alves
@ 2017-06-12 16:19     ` Pedro Alves
  2017-06-18 14:25     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
  2017-06-18 16:50     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
  8 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-12 16:19 UTC (permalink / raw)
  To: gdb-patches

Using the same test as the previous patch, perf shows GDB spending
over 7% in "free".  A substantial number of those calls comes from
insertions in the psyms_seen unordered_set causing lots of rehashing
and recreating buckets.  Fix this by computing an estimate of the size
of the set upfront.

Using the same test as in the previous patch, against the same gdb
inferior, timing improves ~8% further:

  ~6.5s => ~6.0s (average of 5 runs).

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

	* dwarf2read.c (recursively_count_psymbols): New function.
	(write_psymtabs_to_index): Call it to compute number of psyms and
	pass estimate size of psyms_seen to unordered_set's ctor.
---
 gdb/ChangeLog    |  6 ++++++
 gdb/dwarf2read.c | 36 +++++++++++++++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 01b66a1..9dbc059 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
 2017-06-12  Pedro Alves  <palves@redhat.com>
 
+	* dwarf2read.c (recursively_count_psymbols): New function.
+	(write_psymtabs_to_index): Call it to compute number of psyms and
+	pass estimate size of psyms_seen to unordered_set's ctor.
+
+2017-06-12  Pedro Alves  <palves@redhat.com>
+
 	* dwarf2read.c (write_hash_table): Check if key already exists
 	before emplacing.
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 93fd275..bff2fcb 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23691,6 +23691,22 @@ write_one_signatured_type (void **slot, void *d)
   return 1;
 }
 
+/* Recurse into all "included" dependencies and count their symbols as
+   if they appeared in this psymtab.  */
+
+static void
+recursively_count_psymbols (struct partial_symtab *psymtab,
+			    size_t &psyms_seen)
+{
+  for (int i = 0; i < psymtab->number_of_dependencies; ++i)
+    if (psymtab->dependencies[i]->user != NULL)
+      recursively_count_psymbols (psymtab->dependencies[i],
+				  psyms_seen);
+
+  psyms_seen += psymtab->n_global_syms;
+  psyms_seen += psymtab->n_static_syms;
+}
+
 /* Recurse into all "included" dependencies and write their symbols as
    if they appeared in this psymtab.  */
 
@@ -23764,7 +23780,6 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
 
   mapped_symtab symtab;
   data_buf cu_list;
-  std::unordered_set<partial_symbol *> psyms_seen;
 
   /* 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
@@ -23776,6 +23791,25 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   /* 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.  */
+
+  /* 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.  */
+  size_t psyms_count = 0;
+  for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *per_cu
+	= dwarf2_per_objfile->all_comp_units[i];
+      struct partial_symtab *psymtab = per_cu->v.psymtab;
+
+      if (psymtab != NULL && psymtab->user == NULL)
+	recursively_count_psymbols (psymtab, psyms_count);
+    }
+  /* 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);
   for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
     {
       struct dwarf2_per_cu_data *per_cu
-- 
2.5.5

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

* Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-12 16:14     ` [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write Pedro Alves
@ 2017-06-17 17:35       ` Jan Kratochvil
  2017-06-19  9:26         ` Pedro Alves
  2017-06-18 18:36       ` Regression: " Jan Kratochvil
  1 sibling, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-17 17:35 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 12 Jun 2017 18:14:07 +0200, Pedro Alves wrote:
> There's no real need for all this indirection.

> -    ::file_write (file, m_vec);
> +    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
> +      error (_("couldn't write data to file"));

Aren't 28 characters with the variable mentioned once easier to write and more
bug-proof than to write each time 115 characters mentioning the same variable
3 times?


Jan

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

* Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (6 preceding siblings ...)
  2017-06-12 16:19     ` [PATCH 5/6] .gdb_index prod perf regression: Estimate size of psyms_seen Pedro Alves
@ 2017-06-18 14:25     ` Jan Kratochvil
  2017-06-18 15:12       ` Eli Zaretskii
  2017-06-18 16:50     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
  8 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-18 14:25 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Victor Leschuk

On Mon, 12 Jun 2017 18:08:07 +0200, Pedro Alves wrote:
> +  file_closer close_out_file (out_file);
> +  gdb::unlinker unlink_file (filename.c_str ());

I heard on MS-Windows one cannot delete a file which is still open.


Jan

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

* Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-06-18 14:25     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
@ 2017-06-18 15:12       ` Eli Zaretskii
  2017-06-19 11:50         ` [pushed] .gdb_index writer: close the file before unlinking it (Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.) Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Eli Zaretskii @ 2017-06-18 15:12 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: palves, gdb-patches, vleschuk

> Date: Sun, 18 Jun 2017 16:25:30 +0200
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: gdb-patches@sourceware.org, Victor Leschuk <vleschuk@accesssoftek.com>
> 
> On Mon, 12 Jun 2017 18:08:07 +0200, Pedro Alves wrote:
> > +  file_closer close_out_file (out_file);
> > +  gdb::unlinker unlink_file (filename.c_str ());
> 
> I heard on MS-Windows one cannot delete a file which is still open.

Depends on how it was open, but yeah, in general you are right.  (Most
programs, especially those which were ported from Posix systems, open
files in a way that indeed precludes their deletion, because that's
what the MS implementation of 'open' does.)

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

* Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
  2017-06-12 16:08   ` [pushed] " Pedro Alves
                       ` (7 preceding siblings ...)
  2017-06-18 14:25     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
@ 2017-06-18 16:50     ` Jan Kratochvil
  8 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-18 16:50 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Victor Leschuk

On Mon, 12 Jun 2017 18:08:07 +0200, Pedro Alves wrote:
> Note that this patch as is actually causes a ~10% performance
> drop in .gdb_index generation that can be significant when
> running gdb index on big binaries or in a a batch of binaries.

gdb-add-index is being used in Koji builds where it takes minutes to build
even a trivial package.

Otherwise I do not see why anyone would use it for C++ programs
edit-compile-debug cycles where the speed matters:

0m 5.389s -fuse-ld=gold -Wl,--gdb-index,--build-id
0m 3.564s -fuse-ld=gold             -Wl,--build-id
   1.825s = --gdb-index part of gold
0m19.401s (GNU ld)                  -Wl,--build-id
0m 4.364s gdb-add-index
  23.765s = GNU ld + gdb-add-index
23.765 / 5.389 = 4.4099090740397102

GNU ld is too slow and then gold can already produce .gdb_index along its
linking in just negligible time.

Just gold is not a default linker as discussed in:
	[PATCH] [BZ #14995] glibc fails to build if gold is the default linker, even if ld.bfd is available
	https://sourceware.org/ml/libc-alpha/2015-03/msg00410.html
and in my mail internally in Red Hat:
	Subject: [debug-list] DWARF5 .debug_names vs. .gdb_index vs. two lds
	Message-ID: <20161027162728.GA6631@host1.jankratochvil.net>

Although nobody invests time to fix gold to finally switch to it.

But then the currently missing support for DWO in .debug_names seems to be
pointless to implement into GDB as DWO is used only for better
edit-compile-debug cycle speed but then one cannot use GNU ld and so DWO
.debug_names support should be implemented rather into gold.


Jan

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

* Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-12 16:14     ` [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write Pedro Alves
  2017-06-17 17:35       ` Jan Kratochvil
@ 2017-06-18 18:36       ` Jan Kratochvil
  2017-06-19  9:27         ` Pedro Alves
  1 sibling, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-18 18:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 12 Jun 2017 18:14:07 +0200, Pedro Alves wrote:
> There's no real need for all this indirection.
...
> -/* 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]));
> -}
> -
>  /* In-memory buffer to prepare data to be written later to a file.  */
>  class data_buf
>  {
> @@ -23252,7 +23233,8 @@ public:
>    /* Write the buffer to FILE.  */
>    void file_write (FILE *file) const
>    {
> -    ::file_write (file, m_vec);
> +    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
> +      error (_("couldn't write data to file"));
>    }

It is a regression as one needs to multiply vector.size() by sizeof(vector[0]).
Which is also why I separated determining the memory block boundaries from
checking the write success.


Jan

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

* obsolete: [PATCH 0/6] DWARF-5: .debug_names index
  2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
                   ` (5 preceding siblings ...)
  2017-05-26 18:26 ` [PATCH 6/6] DWARF-5: .debug_names index consumer Jan Kratochvil
@ 2017-06-18 19:37 ` Jan Kratochvil
  6 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-18 19:37 UTC (permalink / raw)
  To: gdb-patches; +Cc: Victor Leschuk

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

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

* Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-17 17:35       ` Jan Kratochvil
@ 2017-06-19  9:26         ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-19  9:26 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 06/17/2017 06:34 PM, Jan Kratochvil wrote:
> On Mon, 12 Jun 2017 18:14:07 +0200, Pedro Alves wrote:
>> There's no real need for all this indirection.
> 
>> -    ::file_write (file, m_vec);
>> +    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
>> +      error (_("couldn't write data to file"));
> 
> Aren't 28 characters with the variable mentioned once easier to write and more
> bug-proof than to write each time 115 characters 

That's not a correct comparison, because you're not accounting for all the
characters of the wrapper functions there were removed.  If you count those,
then certainly we end up with fewer characters overall.  It might be different if
the wrapper functions were used in more than one place, but they aren't.

> mentioning the same variable 3 times?

The old code mentioned the same variable 3 times as well:

 -template<class Elem>
 -static void
 -file_write (FILE *file, const std::vector<Elem> &vec)
 -{
 -  file_write (file, vec.data (), vec.size() * sizeof (vec[0]));
                      ^^^          ^^^                  ^^^
 -}


I ran into this because with the byte_vector change, we'd have to
to modify this template's template parameter and prototype.
So the extra indirection ended up getting in the way, and it's
much simpler to just get rid of it.

Thanks,
Pedro Alves

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-18 18:36       ` Regression: " Jan Kratochvil
@ 2017-06-19  9:27         ` Pedro Alves
  2017-06-19  9:39           ` Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-06-19  9:27 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 06/18/2017 07:36 PM, Jan Kratochvil wrote:

>> @@ -23252,7 +23233,8 @@ public:
>>    /* Write the buffer to FILE.  */
>>    void file_write (FILE *file) const
>>    {
>> -    ::file_write (file, m_vec);
>> +    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
>> +      error (_("couldn't write data to file"));
>>    }
> 
> It is a regression as one needs to multiply vector.size() by sizeof(vector[0]).
> Which is also why I separated determining the memory block boundaries from
> checking the write success.

No it's not.  The fwrite call is no longer in generic code where
the element type is unknown.  Here m_vec is a vector of gdb_byte, and
gdb_byte is guaranteed to have sizeof == 1.

Thanks,
Pedro Alves

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19  9:27         ` Pedro Alves
@ 2017-06-19  9:39           ` Jan Kratochvil
  2017-06-19  9:47             ` Pedro Alves
  0 siblings, 1 reply; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19  9:39 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 19 Jun 2017 11:27:46 +0200, Pedro Alves wrote:
> On 06/18/2017 07:36 PM, Jan Kratochvil wrote:
> 
> >> @@ -23252,7 +23233,8 @@ public:
> >>    /* Write the buffer to FILE.  */
> >>    void file_write (FILE *file) const
> >>    {
> >> -    ::file_write (file, m_vec);
> >> +    if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
> >> +      error (_("couldn't write data to file"));
> >>    }
> > 
> > It is a regression as one needs to multiply vector.size() by sizeof(vector[0]).
> > Which is also why I separated determining the memory block boundaries from
> > checking the write success.
> 
> No it's not.  The fwrite call is no longer in generic code where
> the element type is unknown.  Here m_vec is a vector of gdb_byte, and
> gdb_byte is guaranteed to have sizeof == 1.

Ah, OK.  So I would like there some: static_assert (sizeof (m_vec[0]) == 1);

The file_write template+function is used also in a later patch of that series
where sizeof(element) is not 1.  I have reimplemented it with ::fwrite in this
"v2" series after this your removal but I do not agree with that, IMO it was
safer+easier with the template+function you just removed.


Jan

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19  9:39           ` Jan Kratochvil
@ 2017-06-19  9:47             ` Pedro Alves
  2017-06-19 10:03               ` Jan Kratochvil
  0 siblings, 1 reply; 31+ messages in thread
From: Pedro Alves @ 2017-06-19  9:47 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches


> The file_write template+function is used also in a later patch of that series
> where sizeof(element) is not 1.  I have reimplemented it with ::fwrite in this
> "v2" series after this your removal but I do not agree with that, IMO it was
> safer+easier with the template+function you just removed.

If there's more than one place this could be handy, then I'm fine with
adding a wrapper function.  But as I said, it can't be exactly the
same as the original one, because it simply wouldn't compile.

Thanks,
Pedro Alves

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19  9:47             ` Pedro Alves
@ 2017-06-19 10:03               ` Jan Kratochvil
  2017-06-19 10:35                 ` Pedro Alves
  2017-06-19 12:06                 ` Yao Qi
  0 siblings, 2 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 10:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 19 Jun 2017 11:47:51 +0200, Pedro Alves wrote:
> But as I said, it can't be exactly the
> same as the original one, because it simply wouldn't compile.

I haven't found a benchmark whether the gdb::byte_vector optimization was
really worth complicating the codebase.  GDB has more serious performance
problems than such microoptimizations.

One of the goals of the move to C++ was to remove all the GDB-specific
language constructs making it easier to contribute.  Now GDB is becoming
written in its own language again, just based on C++ this time.


Jan

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19 10:03               ` Jan Kratochvil
@ 2017-06-19 10:35                 ` Pedro Alves
  2017-06-19 12:06                 ` Yao Qi
  1 sibling, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-19 10:35 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 06/19/2017 11:03 AM, Jan Kratochvil wrote:
> On Mon, 19 Jun 2017 11:47:51 +0200, Pedro Alves wrote:
>> But as I said, it can't be exactly the
>> same as the original one, because it simply wouldn't compile.
> 
> I haven't found a benchmark whether the gdb::byte_vector optimization was
> really worth complicating the codebase.  GDB has more serious performance
> problems than such microoptimizations.

That's not a valid argument for justifying performance regressions.  
byte_vector avoids premature pessimization, at no real expense of 
readability, and makes it easier to actually use std::vector (because
that's what byte_vector is) in more cases without worrying about 
whether that'd cause a regression vs a dynamic array, as I've showed in
the patch that introduced it.

The C++ breakpoints series from a couple weeks back has some
performance fixes, and I'll be happy to review more patches that help
with any of those performance problems you may be alluding to.

> One of the goals of the move to C++ was to remove all the GDB-specific
> language constructs making it easier to contribute.  Now GDB is becoming
> written in its own language again, just based on C++ this time.

That's a gross exaggeration.  In any case, a byte buffer is not semantically
the same as a vector of integers.  And custom containers and other similar data
structures don't seem to have caused an issue for competing toolchains, btw.

Thanks,
Pedro Alves

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

* [pushed] .gdb_index writer: close the file before unlinking it (Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.)
  2017-06-18 15:12       ` Eli Zaretskii
@ 2017-06-19 11:50         ` Pedro Alves
  0 siblings, 0 replies; 31+ messages in thread
From: Pedro Alves @ 2017-06-19 11:50 UTC (permalink / raw)
  To: Eli Zaretskii, Jan Kratochvil; +Cc: gdb-patches, vleschuk


On 06/18/2017 04:11 PM, Eli Zaretskii wrote:
>> Date: Sun, 18 Jun 2017 16:25:30 +0200
>> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>> Cc: gdb-patches@sourceware.org, Victor Leschuk <vleschuk@accesssoftek.com>
>>
>> On Mon, 12 Jun 2017 18:08:07 +0200, Pedro Alves wrote:
>>> +  file_closer close_out_file (out_file);
>>> +  gdb::unlinker unlink_file (filename.c_str ());
>>
>> I heard on MS-Windows one cannot delete a file which is still open.
> 
> Depends on how it was open, but yeah, in general you are right.  (Most
> programs, especially those which were ported from Posix systems, open
> files in a way that indeed precludes their deletion, because that's
> what the MS implementation of 'open' does.)

Yeah, I forgot/missed that here.

I've pushed this in to fix it.

From 16b7a7199881fa26fc863279bbf08741e5674b5d Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 19 Jun 2017 12:46:47 +0100
Subject: [PATCH] .gdb_index writer: close the file before unlinking it

We should close the file before unlinking because on MS-Windows one
cannot delete a file that is still open.

I considered making 'gdb::unlinker::unlinker(const char *)'
'noexcept(true)' and then adding
  static_assert (noexcept (gdb::unlinker (filename.c_str ())), "");

but that doesn't really work because gdb::unlinker has a gdb_assert,
which can throw a QUIT if/when the assertion fails.  'noexcept(true)'
would cause GDB to abruptly terminate if/when the assertion fails.

gdb/ChangeLog:
2017-06-19  Pedro Alves  <palves@redhat.com>

	* dwarf2read.c (write_psymtabs_to_index): Construct file_closer
	after gdb::unlinker.
---
 gdb/ChangeLog    | 5 +++++
 gdb/dwarf2read.c | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index aaf4b89..c7cf410 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2017-06-19  Pedro Alves  <palves@redhat.com>
+
+	* dwarf2read.c (write_psymtabs_to_index): Construct file_closer
+	after gdb::unlinker.
+
 2017-06-19  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* mi/mi-cm-env.c (_initialize_mi_cmd_env): Use getenv instead of
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index abe14b2..2369d4b 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -23776,8 +23776,12 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
   if (!out_file)
     error (_("Can't open `%s' for writing"), filename.c_str ());
 
-  file_closer close_out_file (out_file);
+  /* 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);
 
   mapped_symtab symtab;
   data_buf cu_list;
-- 
2.5.5

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19 10:03               ` Jan Kratochvil
  2017-06-19 10:35                 ` Pedro Alves
@ 2017-06-19 12:06                 ` Yao Qi
  2017-06-19 12:26                   ` Jan Kratochvil
  1 sibling, 1 reply; 31+ messages in thread
From: Yao Qi @ 2017-06-19 12:06 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Pedro Alves, gdb-patches

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> GDB has more serious performance
> problems than such microoptimizations.

Hi Jan,
Do you have some examples or bugs?  GDB performance improvement is one
of my todo, so if you have some examples, or bugs, that would be quite
helpful.

-- 
Yao (齐尧)

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

* Re: Regression: Re: [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write
  2017-06-19 12:06                 ` Yao Qi
@ 2017-06-19 12:26                   ` Jan Kratochvil
  0 siblings, 0 replies; 31+ messages in thread
From: Jan Kratochvil @ 2017-06-19 12:26 UTC (permalink / raw)
  To: Yao Qi; +Cc: Pedro Alves, gdb-patches

On Mon, 19 Jun 2017 14:06:53 +0200, Yao Qi wrote:
> Do you have some examples or bugs?  GDB performance improvement is one
> of my todo, so if you have some examples, or bugs, that would be quite
> helpful.

Any backtraces take up to a minute.  That is because GDB expands only whole
CUs (and not specific DIEs) and one CU can be pretty huge in C++ programs,
moreover GDB has to expand tens of CUs to expand just one CU due to some
interdependencies between CUs enforced by dwarf2read.c.  Less serious but
another existing problem may be that dwz DW_TAG_imported_unit is implemented
only in DWARF reader and not in inferior symbol/type system of GDB, therefore
all DW_TAG_imported_unit units get duplicated/multiplicated inside GDB, being
expanded each time again.

Occasional print of an expression takes a minute which may be due to:
	gdb's performance is so terrible that it is unusable
	https://bugzilla.redhat.com/show_bug.cgi?id=1401091

Then conditions of breakpoints get evaluated by GDB and not in inferior which
is commonly unusable to wait for hours until the wished even happens and one
has to rather put an "if" statement into a recompiled debuggee.

Then there is the inability of execute C++ statements which should get fixed
by the 'compile' project but then it will be at least 2 times slower than
needed due to the use of gcc instead of clang.


Jan

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

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

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-26 18:25 [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil
2017-05-26 18:25 ` [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
2017-06-12 16:08   ` [pushed] " Pedro Alves
2017-06-12 16:14     ` [PATCH 6/6] .gdb_index prod perf regression: mapped_symtab now vector of values Pedro Alves
2017-06-12 16:14     ` [PATCH 4/6] .gdb_index prod perf regression: find before insert in unordered_map Pedro Alves
2017-06-12 16:14     ` [PATCH 2/6] Code cleanup: dwarf2read.c: Eliminate ::file_write Pedro Alves
2017-06-17 17:35       ` Jan Kratochvil
2017-06-19  9:26         ` Pedro Alves
2017-06-18 18:36       ` Regression: " Jan Kratochvil
2017-06-19  9:27         ` Pedro Alves
2017-06-19  9:39           ` Jan Kratochvil
2017-06-19  9:47             ` Pedro Alves
2017-06-19 10:03               ` Jan Kratochvil
2017-06-19 10:35                 ` Pedro Alves
2017-06-19 12:06                 ` Yao Qi
2017-06-19 12:26                   ` Jan Kratochvil
2017-06-12 16:14     ` [PATCH 3/6] Code cleanup: dwarf2read.c: Add data_buf::append_uint Pedro Alves
2017-06-12 16:14     ` [PATCH 1/6] Code cleanup: dwarf2read.c:uniquify_cu_indices: Use std::unique Pedro Alves
2017-06-12 16:18     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Pedro Alves
2017-06-12 16:19     ` [PATCH 5/6] .gdb_index prod perf regression: Estimate size of psyms_seen Pedro Alves
2017-06-18 14:25     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
2017-06-18 15:12       ` Eli Zaretskii
2017-06-19 11:50         ` [pushed] .gdb_index writer: close the file before unlinking it (Re: [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer.) Pedro Alves
2017-06-18 16:50     ` [pushed] Re: [PATCH 1/6] Code cleanup: C++ify .gdb_index producer Jan Kratochvil
2017-05-26 18:25 ` [PATCH 2/6] cc-with-tweaks.sh: Use gdb-add-index.sh Jan Kratochvil
2017-05-26 18:26 ` [PATCH 4/6] Code cleanup: dwarf2_initialize_objfile return value Jan Kratochvil
2017-05-26 18:26 ` [PATCH 5/6] Refactor: Move some generic code out of .gdb_index code Jan Kratochvil
2017-05-26 18:26 ` [PATCH 3/6] DWARF-5: .debug_names index producer Jan Kratochvil
2017-06-09  5:58   ` [PATCH 3.1/6] " Jan Kratochvil
2017-05-26 18:26 ` [PATCH 6/6] DWARF-5: .debug_names index consumer Jan Kratochvil
2017-06-18 19:37 ` obsolete: [PATCH 0/6] DWARF-5: .debug_names index Jan Kratochvil

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