Blame SOURCES/gdb-rhbz1560010-fix-assertion-symbol-language-dict-language-1of5.patch

689258
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
689258
From: Sergio Durigan Junior <sergiodj@redhat.com>
689258
Date: Fri, 11 Jan 2019 10:52:17 -0500
689258
Subject: 
689258
 gdb-rhbz1560010-fix-assertion-symbol-language-dict-language-1of5.patch
689258
689258
;; Fix 'Assertion `SYMBOL_LANGUAGE (sym) == DICT_LANGUAGE (dict)->la_language' failed.'
689258
;; Keith Seitz, RHBZ#1560010.
689258
689258
gdb/23712: Introduce multidictionary's
689258
689258
gdb/23712 is a new manifestation of the now-infamous (at least to me)
689258
symtab/23010 assertion failure (DICT_LANGUAGE == SYMBOL_LANGAUGE).
689258
689258
An example of the problem (using test case from symtab/23010):
689258
689258
Reading symbols from /home/rdiez/rdiez/arduino/JtagDue/BuildOutput/JtagDue-obj-release/firmware.elf...done.
689258
(gdb) p SysTick_Handler
689258
dwarf2read.c:9715: internal-error: void dw2_add_symbol_to_list(symbol*, pending**): Assertion `(*listhead) == NULL || (SYMBOL_LANGUAGE ((*listhead)->symbol[0]) == SYMBOL_LANGUAGE (symbol))' failed.
689258
A problem internal to GDB has been detected,
689258
further debugging may prove unreliable.
689258
Quit this debugging session? (y or n)
689258
689258
This assertion was added specifically to catch this condition (of adding
689258
symbols of different languages to a single pending list).
689258
689258
The problems we're now seeing on systems utilizing DWARF debugging seem to
689258
be caused by the use of LTO, which adds a CU with an artificial DIE of
689258
language C99 which references DIEs in other CUs of language C++.
689258
689258
Thus, we create a dictionary containing symbols of C99 but end up
689258
stuffing C++ symbols into it, and the dw2_add_symbol_to_list triggers.
689258
689258
The approach taken here to fix this is to introduce multi-language
689258
dictionaries to "replace" the standard, single-language dictionaries
689258
used today.
689258
689258
Note to reviewers: This patch introduces some temporary functions to
689258
aide with review.  This and other artifacts (such as "See dictionary.h"
689258
which appear incorrect) will all be valid at the end of the series.
689258
689258
This first patch introduces the new multidictionary and its API (which
689258
is, by design, identical to the old dictionary interface).  It also
689258
mutates dict_create_hashed and dict_create_linear so that they take
689258
a std::vector instead of the usual struct pending linked list.  This will
689258
be needed later on.
689258
689258
This patch does /not/ actually enable multidictionary's.  That is left
689258
for a subsequent patch in the series.
689258
689258
I've done exhaustive performance testing with this approach, and I've
689258
attempted to minimize the overhead for the (overwhelmingly) most common
689258
one-language scenario.
689258
689258
On average, a -g3 -O0 GDB (the one we developers use) will see
689258
approximately a 4% slowdown when initially reading symbols. [I've
689258
tested only GDB and firefox with -readnow.]  When using -O2, this
689258
difference shrinks to ~0.5%.  Since a number of runs with these
689258
patches actually run /faster/ than unpatched GDB, I conclude that
689258
these tests have at least a 0.5% error margin.
689258
689258
On our own gdb.perf test suite, again, results appear to be pretty
689258
negligible.  Differences to unpatched GDB range from -7.8% (yes,
689258
patched version is again faster than unpatched) to 27%.  All tests
689258
lying outside "negligible," such as the 27% slowdown, involve a total
689258
run time of 0.0007 (or less) with smaller numbers of CUs/DSOs (usually 10
689258
or 100).  In all cases, the follow-up tests with more CUs/DSOs is never
689258
more than 3% difference to the baseline, unpatched GDB.
689258
689258
In my opinion, these results are satisfactory.
689258
689258
gdb/ChangeLog:
689258
689258
	PR gdb/23712
689258
	PR symtab/23010
689258
	* dictionary.c: Include unordered_map.
689258
	(pending_to_vector): New function.
689258
	(dict_create_hashed_1, dict_create_linear_1, dict_add_pending_1):
689258
	Rewrite the non-"_1" functions to take vector instead
689258
	of linked list.
689258
	(dict_create_hashed, dict_create_linear, dict_add_pending): Use the
689258
	"new" _1 versions of the same name.
689258
	(multidictionary): Define.
689258
	(std::hash
689258
	(collate_pending_symbols_by_language, mdict_create_hashed)
689258
	(mdict_create_hashed_expandable, mdict_create_linear)
689258
	(mdict_create_linear_expandable, mdict_free)
689258
	(find_language_dictionary, create_new_language_dictionary)
689258
	(mdict_add_symbol, mdict_add_pending, mdict_iterator_first)
689258
	(mdict_iterator_next, mdict_iter_match_first, mdict_iter_match_next)
689258
	(mdict_size, mdict_empty): New functions.
689258
	* dictionary.h (mdict_iterator): Define.
689258
689258
diff --git a/gdb/dictionary.c b/gdb/dictionary.c
689258
--- a/gdb/dictionary.c
689258
+++ b/gdb/dictionary.c
689258
@@ -27,6 +27,7 @@
689258
 #include "buildsym.h"
689258
 #include "dictionary.h"
689258
 #include "safe-ctype.h"
689258
+#include <unordered_map>
689258
 
689258
 /* This file implements dictionaries, which are tables that associate
689258
    symbols to names.  They are represented by an opaque type 'struct
689258
@@ -341,53 +342,66 @@ static void insert_symbol_hashed (struct dictionary *dict,
689258
 
689258
 static void expand_hashtable (struct dictionary *dict);
689258
 
689258
+/* A function to convert a linked list into a vector.  */
689258
+
689258
+static std::vector<symbol *>
689258
+pending_to_vector (const struct pending *symbol_list)
689258
+{
689258
+  std::vector<symbol *> symlist;
689258
+
689258
+  for (const struct pending *list_counter = symbol_list;
689258
+       list_counter != nullptr; list_counter = list_counter->next)
689258
+    {
689258
+      for (int i = list_counter->nsyms - 1; i >= 0; --i)
689258
+	symlist.push_back (list_counter->symbol[i]);
689258
+    }
689258
+
689258
+  return symlist;
689258
+}
689258
+
689258
 /* The creation functions.  */
689258
 
689258
-/* See dictionary.h.  */
689258
+/* A function to transition dict_create_hashed to new API.  */
689258
 
689258
-struct dictionary *
689258
-dict_create_hashed (struct obstack *obstack,
689258
-		    enum language language,
689258
-		    const struct pending *symbol_list)
689258
+static struct dictionary *
689258
+dict_create_hashed_1 (struct obstack *obstack,
689258
+		      enum language language,
689258
+		      const std::vector<symbol *> &symbol_list)
689258
 {
689258
-  struct dictionary *retval;
689258
-  int nsyms = 0, nbuckets, i;
689258
-  struct symbol **buckets;
689258
-  const struct pending *list_counter;
689258
-
689258
-  retval = XOBNEW (obstack, struct dictionary);
689258
+  /* Allocate the dictionary.  */
689258
+  struct dictionary *retval = XOBNEW (obstack, struct dictionary);
689258
   DICT_VECTOR (retval) = &dict_hashed_vector;
689258
   DICT_LANGUAGE (retval) = language_def (language);
689258
 
689258
-  /* Calculate the number of symbols, and allocate space for them.  */
689258
-  for (list_counter = symbol_list;
689258
-       list_counter != NULL;
689258
-       list_counter = list_counter->next)
689258
-    {
689258
-      nsyms += list_counter->nsyms;
689258
-    }
689258
-  nbuckets = DICT_HASHTABLE_SIZE (nsyms);
689258
+  /* Allocate space for symbols.  */
689258
+  int nsyms = symbol_list.size ();
689258
+  int nbuckets = DICT_HASHTABLE_SIZE (nsyms);
689258
   DICT_HASHED_NBUCKETS (retval) = nbuckets;
689258
-  buckets = XOBNEWVEC (obstack, struct symbol *, nbuckets);
689258
+  struct symbol **buckets = XOBNEWVEC (obstack, struct symbol *, nbuckets);
689258
   memset (buckets, 0, nbuckets * sizeof (struct symbol *));
689258
   DICT_HASHED_BUCKETS (retval) = buckets;
689258
 
689258
   /* Now fill the buckets.  */
689258
-  for (list_counter = symbol_list;
689258
-       list_counter != NULL;
689258
-       list_counter = list_counter->next)
689258
-    {
689258
-      for (i = list_counter->nsyms - 1; i >= 0; --i)
689258
-	{
689258
-	  insert_symbol_hashed (retval, list_counter->symbol[i]);
689258
-	}
689258
-    }
689258
+  for (const auto &sym : symbol_list)
689258
+    insert_symbol_hashed (retval, sym);
689258
 
689258
   return retval;
689258
 }
689258
 
689258
 /* See dictionary.h.  */
689258
 
689258
+struct dictionary *
689258
+dict_create_hashed (struct obstack *obstack,
689258
+		    enum language language,
689258
+		    const struct pending *symbol_list)
689258
+{
689258
+  std::vector<symbol *> symlist = pending_to_vector (symbol_list);
689258
+
689258
+  return dict_create_hashed_1 (obstack, language, symlist);
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
 extern struct dictionary *
689258
 dict_create_hashed_expandable (enum language language)
689258
 {
689258
@@ -403,52 +417,45 @@ dict_create_hashed_expandable (enum language language)
689258
   return retval;
689258
 }
689258
 
689258
-/* See dictionary.h.  */
689258
+/* A function to transition dict_create_linear to new API.  */
689258
 
689258
-struct dictionary *
689258
-dict_create_linear (struct obstack *obstack,
689258
-		    enum language language,
689258
-		    const struct pending *symbol_list)
689258
+static struct dictionary *
689258
+dict_create_linear_1 (struct obstack *obstack,
689258
+		      enum language language,
689258
+		      const std::vector<symbol *> &symbol_list)
689258
 {
689258
-  struct dictionary *retval;
689258
-  int nsyms = 0, i, j;
689258
-  struct symbol **syms;
689258
-  const struct pending *list_counter;
689258
-
689258
-  retval = XOBNEW (obstack, struct dictionary);
689258
+  struct dictionary *retval = XOBNEW (obstack, struct dictionary);
689258
   DICT_VECTOR (retval) = &dict_linear_vector;
689258
   DICT_LANGUAGE (retval) = language_def (language);
689258
 
689258
-  /* Calculate the number of symbols, and allocate space for them.  */
689258
-  for (list_counter = symbol_list;
689258
-       list_counter != NULL;
689258
-       list_counter = list_counter->next)
689258
-    {
689258
-      nsyms += list_counter->nsyms;
689258
-    }
689258
+  /* Allocate space for symbols.  */
689258
+  int nsyms = symbol_list.size ();
689258
   DICT_LINEAR_NSYMS (retval) = nsyms;
689258
-  syms = XOBNEWVEC (obstack, struct symbol *, nsyms );
689258
+  struct symbol **syms = XOBNEWVEC (obstack, struct symbol *, nsyms);
689258
   DICT_LINEAR_SYMS (retval) = syms;
689258
 
689258
-  /* Now fill in the symbols.  Start filling in from the back, so as
689258
-     to preserve the original order of the symbols.  */
689258
-  for (list_counter = symbol_list, j = nsyms - 1;
689258
-       list_counter != NULL;
689258
-       list_counter = list_counter->next)
689258
-    {
689258
-      for (i = list_counter->nsyms - 1;
689258
-	   i >= 0;
689258
-	   --i, --j)
689258
-	{
689258
-	  syms[j] = list_counter->symbol[i];
689258
-	}
689258
-    }
689258
+  /* Now fill in the symbols.  */
689258
+  int idx = nsyms - 1;
689258
+  for (const auto &sym : symbol_list)
689258
+    syms[idx--] = sym;
689258
 
689258
   return retval;
689258
 }
689258
 
689258
 /* See dictionary.h.  */
689258
 
689258
+struct dictionary *
689258
+dict_create_linear (struct obstack *obstack,
689258
+		    enum language language,
689258
+		    const struct pending *symbol_list)
689258
+{
689258
+  std::vector<symbol *> symlist = pending_to_vector (symbol_list);
689258
+
689258
+  return dict_create_linear_1 (obstack, language, symlist);
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
 struct dictionary *
689258
 dict_create_linear_expandable (enum language language)
689258
 {
689258
@@ -483,20 +490,26 @@ dict_add_symbol (struct dictionary *dict, struct symbol *sym)
689258
   (DICT_VECTOR (dict))->add_symbol (dict, sym);
689258
 }
689258
 
689258
+/* A function to transition dict_add_pending to new API.  */
689258
+
689258
+static void
689258
+dict_add_pending_1 (struct dictionary *dict,
689258
+		    const std::vector<symbol *> &symbol_list)
689258
+{
689258
+  /* Preserve ordering by reversing the list.  */
689258
+  for (auto sym = symbol_list.rbegin (); sym != symbol_list.rend (); ++sym)
689258
+    dict_add_symbol (dict, *sym);
689258
+}
689258
+
689258
 /* Utility to add a list of symbols to a dictionary.
689258
    DICT must be an expandable dictionary.  */
689258
 
689258
 void
689258
 dict_add_pending (struct dictionary *dict, const struct pending *symbol_list)
689258
 {
689258
-  const struct pending *list;
689258
-  int i;
689258
+  std::vector<symbol *> symlist = pending_to_vector (symbol_list);
689258
 
689258
-  for (list = symbol_list; list != NULL; list = list->next)
689258
-    {
689258
-      for (i = 0; i < list->nsyms; ++i)
689258
-	dict_add_symbol (dict, list->symbol[i]);
689258
-    }
689258
+  dict_add_pending_1 (dict, symlist);
689258
 }
689258
 
689258
 /* Initialize ITERATOR to point at the first symbol in DICT, and
689258
@@ -929,3 +942,408 @@ add_symbol_linear_expandable (struct dictionary *dict,
689258
 
689258
   DICT_LINEAR_SYM (dict, nsyms - 1) = sym;
689258
 }
689258
+
689258
+/* Multi-language dictionary support.  */
689258
+
689258
+/* The structure describing a multi-language dictionary.  */
689258
+
689258
+struct multidictionary
689258
+{
689258
+  /* An array of dictionaries, one per language.  All dictionaries
689258
+     must be of the same type.  This should be free'd for expandable
689258
+     dictionary types.  */
689258
+  struct dictionary **dictionaries;
689258
+
689258
+  /* The number of language dictionaries currently allocated.
689258
+     Only used for expandable dictionaries.  */
689258
+  unsigned short n_allocated_dictionaries;
689258
+};
689258
+
689258
+/* A hasher for enum language.  Injecting this into std is a convenience
689258
+   when using unordered_map with C++11.  */
689258
+
689258
+namespace std
689258
+{
689258
+  template<> struct hash<enum language>
689258
+  {
689258
+    typedef enum language argument_type;
689258
+    typedef std::size_t result_type;
689258
+
689258
+    result_type operator() (const argument_type &l) const noexcept
689258
+    {
689258
+      return static_cast<result_type> (l);
689258
+    }
689258
+  };
689258
+} /* namespace std */
689258
+
689258
+/* A helper function to collate symbols on the pending list by language.  */
689258
+
689258
+static std::unordered_map<enum language, std::vector<symbol *>>
689258
+collate_pending_symbols_by_language (const struct pending *symbol_list)
689258
+{
689258
+  std::unordered_map<enum language, std::vector<symbol *>> nsyms;
689258
+
689258
+  for (const struct pending *list_counter = symbol_list;
689258
+       list_counter != nullptr; list_counter = list_counter->next)
689258
+    {
689258
+      for (int i = list_counter->nsyms - 1; i >= 0; --i)
689258
+	{
689258
+	  enum language language = SYMBOL_LANGUAGE (list_counter->symbol[i]);
689258
+	  nsyms[language].push_back (list_counter->symbol[i]);
689258
+	}
689258
+    }
689258
+
689258
+  return nsyms;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct multidictionary *
689258
+mdict_create_hashed (struct obstack *obstack,
689258
+		     const struct pending *symbol_list)
689258
+{
689258
+  struct multidictionary *retval
689258
+    = XOBNEW (obstack, struct multidictionary);
689258
+  std::unordered_map<enum language, std::vector<symbol *>> nsyms
689258
+    = collate_pending_symbols_by_language (symbol_list);
689258
+
689258
+  /* Loop over all languages and create/populate dictionaries.  */
689258
+  retval->dictionaries
689258
+    = XOBNEWVEC (obstack, struct dictionary *, nsyms.size ());
689258
+  retval->n_allocated_dictionaries = nsyms.size ();
689258
+
689258
+  int idx = 0;
689258
+  for (const auto &pair : nsyms)
689258
+    {
689258
+      enum language language = pair.first;
689258
+      std::vector<symbol *> symlist = pair.second;
689258
+
689258
+      retval->dictionaries[idx++]
689258
+	= dict_create_hashed_1 (obstack, language, symlist);
689258
+    }
689258
+
689258
+  return retval;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct multidictionary *
689258
+mdict_create_hashed_expandable (enum language language)
689258
+{
689258
+  struct multidictionary *retval = XNEW (struct multidictionary);
689258
+
689258
+  /* We have no symbol list to populate, but we create an empty
689258
+     dictionary of the requested language to populate later.  */
689258
+  retval->n_allocated_dictionaries = 1;
689258
+  retval->dictionaries = XNEW (struct dictionary *);
689258
+  retval->dictionaries[0] = dict_create_hashed_expandable (language);
689258
+
689258
+  return retval;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct multidictionary *
689258
+mdict_create_linear (struct obstack *obstack,
689258
+		     const struct pending *symbol_list)
689258
+{
689258
+  struct multidictionary *retval
689258
+    = XOBNEW (obstack, struct multidictionary);
689258
+  std::unordered_map<enum language, std::vector<symbol *>> nsyms
689258
+    = collate_pending_symbols_by_language (symbol_list);
689258
+
689258
+  /* Loop over all languages and create/populate dictionaries.  */
689258
+  retval->dictionaries
689258
+    = XOBNEWVEC (obstack, struct dictionary *, nsyms.size ());
689258
+  retval->n_allocated_dictionaries = nsyms.size ();
689258
+
689258
+  int idx = 0;
689258
+  for (const auto &pair : nsyms)
689258
+    {
689258
+      enum language language = pair.first;
689258
+      std::vector<symbol *> symlist = pair.second;
689258
+
689258
+      retval->dictionaries[idx++]
689258
+	= dict_create_linear_1 (obstack, language, symlist);
689258
+    }
689258
+
689258
+  return retval;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct multidictionary *
689258
+mdict_create_linear_expandable (enum language language)
689258
+{
689258
+  struct multidictionary *retval = XNEW (struct multidictionary);
689258
+
689258
+  /* We have no symbol list to populate, but we create an empty
689258
+     dictionary to populate later.  */
689258
+  retval->n_allocated_dictionaries = 1;
689258
+  retval->dictionaries = XNEW (struct dictionary *);
689258
+  retval->dictionaries[0] = dict_create_linear_expandable (language);
689258
+
689258
+  return retval;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+void
689258
+mdict_free (struct multidictionary *mdict)
689258
+{
689258
+  /* Grab the type of dictionary being used.  */
689258
+  enum dict_type type = mdict->dictionaries[0]->vector->type;
689258
+
689258
+  /* Loop over all dictionaries and free them.  */
689258
+  for (unsigned short idx = 0; idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    dict_free (mdict->dictionaries[idx]);
689258
+
689258
+  /* Free the dictionary list, if needed.  */
689258
+  switch (type)
689258
+    {
689258
+    case DICT_HASHED:
689258
+    case DICT_LINEAR:
689258
+      /* Memory was allocated on an obstack when created.  */
689258
+      break;
689258
+
689258
+    case DICT_HASHED_EXPANDABLE:
689258
+    case DICT_LINEAR_EXPANDABLE:
689258
+      xfree (mdict->dictionaries);
689258
+      break;
689258
+    }
689258
+}
689258
+
689258
+/* Helper function to find the dictionary associated with LANGUAGE
689258
+   or NULL if there is no dictionary of that language.  */
689258
+
689258
+static struct dictionary *
689258
+find_language_dictionary (const struct multidictionary *mdict,
689258
+			  enum language language)
689258
+{
689258
+  for (unsigned short idx = 0; idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      if (DICT_LANGUAGE (mdict->dictionaries[idx])->la_language == language)
689258
+	return mdict->dictionaries[idx];
689258
+    }
689258
+
689258
+  return nullptr;
689258
+}
689258
+
689258
+/* Create a new language dictionary for LANGUAGE and add it to the
689258
+   multidictionary MDICT's list of dictionaries.  If MDICT is not
689258
+   based on expandable dictionaries, this function throws an
689258
+   internal error.  */
689258
+
689258
+static struct dictionary *
689258
+create_new_language_dictionary (struct multidictionary *mdict,
689258
+				enum language language)
689258
+{
689258
+  struct dictionary *retval = nullptr;
689258
+
689258
+  /* We use the first dictionary entry to decide what create function
689258
+     to call.  Not optimal but sufficient.  */
689258
+  gdb_assert (mdict->dictionaries[0] != nullptr);
689258
+  switch (mdict->dictionaries[0]->vector->type)
689258
+    {
689258
+    case DICT_HASHED:
689258
+    case DICT_LINEAR:
689258
+      internal_error (__FILE__, __LINE__,
689258
+		      _("create_new_language_dictionary: attempted to expand "
689258
+			"non-expandable multidictionary"));
689258
+
689258
+    case DICT_HASHED_EXPANDABLE:
689258
+      retval = dict_create_hashed_expandable (language);
689258
+      break;
689258
+
689258
+    case DICT_LINEAR_EXPANDABLE:
689258
+      retval = dict_create_linear_expandable (language);
689258
+      break;
689258
+    }
689258
+
689258
+  /* Grow the dictionary vector and save the new dictionary.  */
689258
+  mdict->dictionaries
689258
+    = (struct dictionary **) xrealloc (mdict->dictionaries,
689258
+				       (++mdict->n_allocated_dictionaries
689258
+					* sizeof (struct dictionary *)));
689258
+  mdict->dictionaries[mdict->n_allocated_dictionaries - 1] = retval;
689258
+
689258
+  return retval;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+void
689258
+mdict_add_symbol (struct multidictionary *mdict, struct symbol *sym)
689258
+{
689258
+  struct dictionary *dict
689258
+    = find_language_dictionary (mdict, SYMBOL_LANGUAGE (sym));
689258
+
689258
+  if (dict == nullptr)
689258
+    {
689258
+      /* SYM is of a new language that we haven't previously seen.
689258
+	 Create a new dictionary for it.  */
689258
+      dict = create_new_language_dictionary (mdict, SYMBOL_LANGUAGE (sym));
689258
+    }
689258
+
689258
+  dict_add_symbol (dict, sym);
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+void
689258
+mdict_add_pending (struct multidictionary *mdict,
689258
+		   const struct pending *symbol_list)
689258
+{
689258
+  std::unordered_map<enum language, std::vector<symbol *>> nsyms
689258
+    = collate_pending_symbols_by_language (symbol_list);
689258
+
689258
+  for (const auto &pair : nsyms)
689258
+    {
689258
+      enum language language = pair.first;
689258
+      std::vector<symbol *> symlist = pair.second;
689258
+      struct dictionary *dict = find_language_dictionary (mdict, language);
689258
+
689258
+      if (dict == nullptr)
689258
+	{
689258
+	  /* The language was not previously seen.  Create a new dictionary
689258
+	     for it.  */
689258
+	  dict = create_new_language_dictionary (mdict, language);
689258
+	}
689258
+
689258
+      dict_add_pending_1 (dict, symlist);
689258
+    }
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct symbol *
689258
+mdict_iterator_first (const multidictionary *mdict,
689258
+		      struct mdict_iterator *miterator)
689258
+{
689258
+  miterator->mdict = mdict;
689258
+  miterator->current_idx = 0;
689258
+
689258
+  for (unsigned short idx = miterator->current_idx;
689258
+       idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      struct symbol *result
689258
+	= dict_iterator_first (mdict->dictionaries[idx], &miterator->iterator);
689258
+
689258
+      if (result != nullptr)
689258
+	{
689258
+	  miterator->current_idx = idx;
689258
+	  return result;
689258
+	}
689258
+    }
689258
+
689258
+  return nullptr;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct symbol *
689258
+mdict_iterator_next (struct mdict_iterator *miterator)
689258
+{
689258
+  struct symbol *result = dict_iterator_next (&miterator->iterator);
689258
+
689258
+  if (result != nullptr)
689258
+    return result;
689258
+
689258
+  /* The current dictionary had no matches -- move to the next
689258
+     dictionary, if any.  */
689258
+  for (unsigned short idx = ++miterator->current_idx;
689258
+       idx < miterator->mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      result
689258
+	= dict_iterator_first (miterator->mdict->dictionaries[idx],
689258
+			       &miterator->iterator);
689258
+      if (result != nullptr)
689258
+	{
689258
+	  miterator->current_idx = idx;
689258
+	  return result;
689258
+	}
689258
+    }
689258
+
689258
+  return nullptr;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct symbol *
689258
+mdict_iter_match_first (const struct multidictionary *mdict,
689258
+			const lookup_name_info &name,
689258
+			struct mdict_iterator *miterator)
689258
+{
689258
+  miterator->mdict = mdict;
689258
+  miterator->current_idx = 0;
689258
+
689258
+  for (unsigned short idx = miterator->current_idx;
689258
+       idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      struct symbol *result
689258
+	= dict_iter_match_first (mdict->dictionaries[idx], name,
689258
+				 &miterator->iterator);
689258
+
689258
+      if (result != nullptr)
689258
+	return result;
689258
+    }
689258
+
689258
+  return nullptr;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+struct symbol *
689258
+mdict_iter_match_next (const lookup_name_info &name,
689258
+		       struct mdict_iterator *miterator)
689258
+{
689258
+  /* Search the current dictionary.  */
689258
+  struct symbol *result = dict_iter_match_next (name, &miterator->iterator);
689258
+
689258
+  if (result != nullptr)
689258
+    return result;
689258
+
689258
+  /* The current dictionary had no matches -- move to the next
689258
+     dictionary, if any.  */
689258
+  for (unsigned short idx = ++miterator->current_idx;
689258
+       idx < miterator->mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      result
689258
+	= dict_iter_match_first (miterator->mdict->dictionaries[idx],
689258
+				 name, &miterator->iterator);
689258
+      if (result != nullptr)
689258
+	{
689258
+	  miterator->current_idx = idx;
689258
+	  return result;
689258
+	}
689258
+    }
689258
+
689258
+  return nullptr;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+int
689258
+mdict_size (const struct multidictionary *mdict)
689258
+{
689258
+  int size = 0;
689258
+
689258
+  for (unsigned short idx = 0; idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    size += dict_size (mdict->dictionaries[idx]);
689258
+
689258
+  return size;
689258
+}
689258
+
689258
+/* See dictionary.h.  */
689258
+
689258
+bool
689258
+mdict_empty (const struct multidictionary *mdict)
689258
+{
689258
+  for (unsigned short idx = 0; idx < mdict->n_allocated_dictionaries; ++idx)
689258
+    {
689258
+      if (!dict_empty (mdict->dictionaries[idx]))
689258
+	return false;
689258
+    }
689258
+
689258
+  return true;
689258
+}
689258
diff --git a/gdb/dictionary.h b/gdb/dictionary.h
689258
--- a/gdb/dictionary.h
689258
+++ b/gdb/dictionary.h
689258
@@ -113,6 +113,21 @@ struct dict_iterator
689258
   struct symbol *current;
689258
 };
689258
 
689258
+/* The multi-language dictionary iterator.  Like dict_iterator above,
689258
+   these contents should be considered private.  */
689258
+
689258
+struct mdict_iterator
689258
+{
689258
+  /* The multidictionary with whcih this iterator is associated.  */
689258
+  const struct multidictionary *mdict;
689258
+
689258
+  /* The iterator used to iterate through individual dictionaries.  */
689258
+  struct dict_iterator iterator;
689258
+
689258
+  /* The current index of the dictionary being iterated over.  */
689258
+  unsigned short current_idx;
689258
+};
689258
+
689258
 /* Initialize ITERATOR to point at the first symbol in DICT, and
689258
    return that first symbol, or NULL if DICT is empty.  */
689258