diff mbox

Code cleanup: C++ify .gdb_index producer

Message ID 20170331210710.GA17527@host1.jankratochvil.net
State New
Headers show

Commit Message

Jan Kratochvil March 31, 2017, 9:07 p.m. UTC
Hi,

to understand the .gdb_index producer and with an expectation I will
adjust/extend it for DWARF-5 .debug_names producer I have C++ified it.

This is a pre-requisite for my later DWARF-5 .debug_names support
(its producer draft can be now found in archer.git branch
users/jkratoch/indexcxx-debugnames).  In the end it is not much reused for
DWARF-5.  And it is also questionable whether it makes sense to still produce
.gdb_index with GDB capable of .debug_names which I have kept there by new:
	usage: save gdb-index [-dwarf-4] DIRECTORY
	                       ^^^^^^^^

OK for check-in?

It was tested it produces byte-by-byte equal index.


Jan
gdb/ChangeLog
2017-03-31  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.

Comments

Jan Kratochvil May 26, 2017, 6:28 p.m. UTC | #1
obsoleted by:
	[PATCH 1/6] Code cleanup: C++ify .gdb_index producer.
	https://sourceware.org/ml/gdb-patches/2017-05/msg00579.html
	Message-ID: <149582313928.15869.12647134810146005233.stgit@host1.jankratochvil.net>
diff mbox

Patch

diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h
index af37111..394a00b 100644
--- a/gdb/common/common-defs.h
+++ b/gdb/common/common-defs.h
@@ -90,4 +90,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 f1a10c4..be0adde 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -69,12 +69,13 @@ 
 #include "filestuff.h"
 #include "build-id.h"
 #include "namespace.h"
-#include "common/gdb_unlinker.h"
 #include "common/function-view.h"
 
 #include <fcntl.h>
 #include <sys/types.h>
 #include <algorithm>
+#include <unordered_set>
+#include <unordered_map>
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -2100,7 +2101,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
@@ -23160,69 +23161,75 @@  dwarf2_per_objfile_free (struct objfile *objfile, void *d)
 
 /* 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
@@ -23233,107 +23240,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);
     }
 }
 
@@ -23342,24 +23282,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;
+  auto old_entries (std::move (symtab->data));
 
-  symtab->size *= 2;
-  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
-
-  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.
@@ -23371,20 +23304,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;
@@ -23399,18 +23330,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.  */
@@ -23418,112 +23338,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
 	{
@@ -23533,50 +23457,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
@@ -23586,26 +23477,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.  */
@@ -23617,19 +23510,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
@@ -23643,18 +23533,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,
@@ -23666,7 +23554,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);
 }
@@ -23713,7 +23601,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,
@@ -23722,44 +23610,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
@@ -23772,7 +23650,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,
@@ -23787,14 +23664,12 @@  write_one_signatured_type (void **slot, void *d)
 		  psymtab->n_static_syms, info->cu_index,
 		  1);
 
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
-			  entry->per_cu.offset.sect_off);
-  obstack_grow (info->types_list, val, 8);
-  store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
-			  entry->type_offset_in_tu.cu_off);
-  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->per_cu.offset.sect_off);
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE, entry->type_offset_in_tu.cu_off);
+  store_unsigned_integer (info->types_list.append_space (8), 8,
+			  BFD_ENDIAN_LITTLE, entry->signature);
 
   ++info->cu_index;
 
@@ -23808,7 +23683,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;
@@ -23835,17 +23710,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"));
 
@@ -23855,160 +23719,126 @@  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;
 
-  symtab = create_mapped_symtab ();
-  make_cleanup (cleanup_mapped_symtab, symtab);
+      /* 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);
 
-  obstack_init (&addr_obstack);
-  make_cleanup_obstack_free (&addr_obstack);
+      /* 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;
 
-  obstack_init (&cu_list);
-  make_cleanup_obstack_free (&cu_list);
+	  if (psymtab->user == NULL)
+	    recursively_write_psymbols (objfile, psymtab, &symtab, psyms_seen,
+					i);
 
-  obstack_init (&types_cu_list);
-  make_cleanup_obstack_free (&types_cu_list);
+	  const auto insertpair (cu_index_htab.emplace (psymtab, i));
+	  gdb_assert (insertpair.second);
 
-  htab_up psyms_seen (htab_create_alloc (100, htab_hash_pointer,
-					 htab_eq_pointer,
-					 NULL, xcalloc, xfree));
+	  store_unsigned_integer (cu_list.append_space (8), 8,
+				  BFD_ENDIAN_LITTLE, per_cu->offset.sect_off);
+	  store_unsigned_integer (cu_list.append_space (8), 8,
+				  BFD_ENDIAN_LITTLE, per_cu->length);
+	}
 
-  /* 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);
+      /* Dump the address map.  */
+      DataBuf addr_vec;
+      write_address_map (objfile, addr_vec, cu_index_htab);
 
-  /* 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;
+      /* 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);
+	}
 
-      /* 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;
+      /* Now that we've processed all symbols we can shrink their cu_indices
+	 lists.  */
+      uniquify_cu_indices (&symtab);
 
-      if (psymtab->user == NULL)
-	recursively_write_psymbols (objfile, psymtab, symtab,
-				    psyms_seen.get (), i);
+      DataBuf symtab_vec, constant_pool;
+      write_hash_table (&symtab, symtab_vec, constant_pool);
 
-      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,
-			      per_cu->offset.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);
+      DataBuf contents;
+      const offset_type size_of_contents (6 * sizeof (offset_type));
+      offset_type total_len (size_of_contents);
 
-  fclose (out_file);
+      /* The version number.  */
+      contents.append_data (MAYBE_SWAP (8));
 
-  /* We want to keep the file.  */
-  unlink_file.keep ();
+      /* The offset of the CU list from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += cu_list.size ();
 
-  do_cleanups (cleanup);
+      /* 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 address table from the start of the file.  */
+      contents.append_data (MAYBE_SWAP (total_len));
+      total_len += addr_vec.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 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 (...)
+    {
+      fclose (out_file);
+      unlink (filename.c_str ());
+      throw;
+    }
+  fclose (out_file);
 }
 
 /* Implementation of the `save gdb-index' command.