]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Move cooked_index_shard to new files
authorTom Tromey <tom@tromey.com>
Mon, 24 Mar 2025 21:19:20 +0000 (15:19 -0600)
committerTom Tromey <tom@tromey.com>
Tue, 1 Apr 2025 13:30:10 +0000 (07:30 -0600)
This moves cooked_index_shard to a couple of new files,
dwarf2/cooked-index-shard.[ch].  The rationale is the same as the
previous patch: cooked-index.h had to be split to enable other
cleanups.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
gdb/Makefile.in
gdb/dwarf2/cooked-index-shard.c [new file with mode: 0644]
gdb/dwarf2/cooked-index-shard.h [new file with mode: 0644]
gdb/dwarf2/cooked-index.c
gdb/dwarf2/cooked-index.h

index b4e54071eedbbc3d0c7400c1454cf76d3b86ee89..0c4102d25654c5a367c14c03cf55ad53a69c8b8c 100644 (file)
@@ -1098,6 +1098,7 @@ COMMON_SFILES = \
        dwarf2/comp-unit-head.c \
        dwarf2/cooked-index.c \
        dwarf2/cooked-index-entry.c \
+       dwarf2/cooked-index-shard.c \
        dwarf2/cooked-index-worker.c \
        dwarf2/cooked-indexer.c \
        dwarf2/cu.c \
@@ -1358,6 +1359,7 @@ HFILES_NO_SRCDIR = \
        dwarf2/aranges.h \
        dwarf2/cooked-index.h \
        dwarf2/cooked-index-entry.h \
+       dwarf2/cooked-index-shard.h \
        dwarf2/cooked-index-worker.h \
        dwarf2/cooked-indexer.h \
        dwarf2/cu.h \
diff --git a/gdb/dwarf2/cooked-index-shard.c b/gdb/dwarf2/cooked-index-shard.c
new file mode 100644 (file)
index 0000000..41844cd
--- /dev/null
@@ -0,0 +1,331 @@
+/* Shards for the cooked index
+
+   Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "dwarf2/cooked-index-shard.h"
+#include "dwarf2/tag.h"
+#include "dwarf2/index-common.h"
+#include "cp-support.h"
+#include "c-lang.h"
+#include "ada-lang.h"
+
+/* Return true if a plain "main" could be the main program for this
+   language.  Languages that are known to use some other mechanism are
+   excluded here.  */
+
+static bool
+language_may_use_plain_main (enum language lang)
+{
+  /* No need to handle "unknown" here.  */
+  return (lang == language_c
+         || lang == language_objc
+         || lang == language_cplus
+         || lang == language_m2
+         || lang == language_asm
+         || lang == language_opencl
+         || lang == language_minimal);
+}
+
+/* See cooked-index.h.  */
+
+cooked_index_entry *
+cooked_index_shard::create (sect_offset die_offset,
+                           enum dwarf_tag tag,
+                           cooked_index_flag flags,
+                           enum language lang,
+                           const char *name,
+                           cooked_index_entry_ref parent_entry,
+                           dwarf2_per_cu *per_cu)
+{
+  if (tag == DW_TAG_module || tag == DW_TAG_namespace)
+    flags &= ~IS_STATIC;
+  else if (lang == language_cplus
+          && (tag == DW_TAG_class_type
+              || tag == DW_TAG_interface_type
+              || tag == DW_TAG_structure_type
+              || tag == DW_TAG_union_type
+              || tag == DW_TAG_enumeration_type
+              || tag == DW_TAG_enumerator))
+    flags &= ~IS_STATIC;
+  else if (tag_is_type (tag))
+    flags |= IS_STATIC;
+
+  return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
+                                             lang, name, parent_entry,
+                                             per_cu);
+}
+
+/* See cooked-index.h.  */
+
+cooked_index_entry *
+cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag,
+                        cooked_index_flag flags, enum language lang,
+                        const char *name, cooked_index_entry_ref parent_entry,
+                        dwarf2_per_cu *per_cu)
+{
+  cooked_index_entry *result = create (die_offset, tag, flags, lang, name,
+                                      parent_entry, per_cu);
+  m_entries.push_back (result);
+
+  /* An explicitly-tagged main program should always override the
+     implicit "main" discovery.  */
+  if ((flags & IS_MAIN) != 0)
+    m_main = result;
+  else if ((flags & IS_PARENT_DEFERRED) == 0
+          && parent_entry.resolved == nullptr
+          && m_main == nullptr
+          && language_may_use_plain_main (lang)
+          && strcmp (name, "main") == 0)
+    m_main = result;
+
+  return result;
+}
+
+/* See cooked-index.h.  */
+
+void
+cooked_index_shard::handle_gnat_encoded_entry
+     (cooked_index_entry *entry,
+      htab_t gnat_entries,
+      std::vector<cooked_index_entry *> &new_entries)
+{
+  /* We decode Ada names in a particular way: operators and wide
+     characters are left as-is.  This is done to make name matching a
+     bit simpler; and for wide characters, it means the choice of Ada
+     source charset does not affect the indexer directly.  */
+  std::string canonical = ada_decode (entry->name, false, false, false);
+  if (canonical.empty ())
+    {
+      entry->canonical = entry->name;
+      return;
+    }
+  std::vector<std::string_view> names = split_name (canonical.c_str (),
+                                                   split_style::DOT_STYLE);
+  std::string_view tail = names.back ();
+  names.pop_back ();
+
+  const cooked_index_entry *parent = nullptr;
+  for (const auto &name : names)
+    {
+      uint32_t hashval = dwarf5_djb_hash (name);
+      void **slot = htab_find_slot_with_hash (gnat_entries, &name,
+                                             hashval, INSERT);
+      /* CUs are processed in order, so we only need to check the most
+        recent entry.  */
+      cooked_index_entry *last = (cooked_index_entry *) *slot;
+      if (last == nullptr || last->per_cu != entry->per_cu)
+       {
+         const char *new_name = m_names.insert (name);
+         last = create (entry->die_offset, DW_TAG_module,
+                        IS_SYNTHESIZED, language_ada, new_name, parent,
+                        entry->per_cu);
+         last->canonical = last->name;
+         new_entries.push_back (last);
+         *slot = last;
+       }
+
+      parent = last;
+    }
+
+  entry->set_parent (parent);
+  entry->canonical = m_names.insert (tail);
+}
+
+/* Hash a cooked index entry by name pointer value.
+
+   We can use pointer equality here because names come from .debug_str, which
+   will normally be unique-ified by the linker.  Also, duplicates are relatively
+   harmless -- they just mean a bit of extra memory is used.  */
+
+struct cooked_index_entry_name_ptr_hash
+{
+  using is_avalanching = void;
+
+  std::uint64_t operator () (const cooked_index_entry *entry) const noexcept
+  {
+    return ankerl::unordered_dense::hash<const char *> () (entry->name);
+  }
+};
+
+/* Compare cooked index entries by name pointer value.  */
+
+struct cooked_index_entry_name_ptr_eq
+{
+  bool operator () (const cooked_index_entry *a,
+                   const cooked_index_entry *b) const noexcept
+  {
+    return a->name == b->name;
+  }
+};
+
+/* See cooked-index.h.  */
+
+void
+cooked_index_shard::finalize (const parent_map_map *parent_maps)
+{
+  gdb::unordered_set<const cooked_index_entry *,
+                    cooked_index_entry_name_ptr_hash,
+                    cooked_index_entry_name_ptr_eq> seen_names;
+
+  auto hash_entry = [] (const void *e)
+    {
+      const cooked_index_entry *entry = (const cooked_index_entry *) e;
+      return dwarf5_djb_hash (entry->canonical);
+    };
+
+  auto eq_entry = [] (const void *a, const void *b) -> int
+    {
+      const cooked_index_entry *ae = (const cooked_index_entry *) a;
+      const std::string_view *sv = (const std::string_view *) b;
+      return (strlen (ae->canonical) == sv->length ()
+             && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
+    };
+
+  htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
+                                          nullptr, xcalloc, xfree));
+  std::vector<cooked_index_entry *> new_gnat_entries;
+
+  for (cooked_index_entry *entry : m_entries)
+    {
+      if ((entry->flags & IS_PARENT_DEFERRED) != 0)
+       {
+         const cooked_index_entry *new_parent
+           = parent_maps->find (entry->get_deferred_parent ());
+         entry->resolve_parent (new_parent);
+       }
+
+      /* Note that this code must be kept in sync with
+        language_requires_canonicalization.  */
+      gdb_assert (entry->canonical == nullptr);
+      if ((entry->flags & IS_LINKAGE) != 0)
+       entry->canonical = entry->name;
+      else if (entry->lang == language_ada)
+       {
+         /* Newer versions of GNAT emit DW_TAG_module and use a
+            hierarchical structure.  In this case, we don't need to
+            do any extra work.  This can be detected by looking for a
+            GNAT-encoded name.  */
+         if (strstr (entry->name, "__") == nullptr)
+           {
+             entry->canonical = entry->name;
+
+             /* If the entry does not have a parent, then there's
+                nothing extra to do here -- the entry itself is
+                sufficient.
+
+                However, if it does have a parent, we have to
+                synthesize an entry with the full name.  This is
+                unfortunate, but it's necessary due to how some of
+                the Ada name-lookup code currently works.  For
+                example, without this, ada_get_tsd_type will
+                fail.
+
+                Eventually it would be good to change the Ada lookup
+                code, and then remove these entries (and supporting
+                code in cooked_index_entry::full_name).  */
+             if (entry->get_parent () != nullptr)
+               {
+                 const char *fullname
+                   = entry->full_name (&m_storage, FOR_ADA_LINKAGE_NAME);
+                 cooked_index_entry *linkage = create (entry->die_offset,
+                                                       entry->tag,
+                                                       (entry->flags
+                                                        | IS_LINKAGE
+                                                        | IS_SYNTHESIZED),
+                                                       language_ada,
+                                                       fullname,
+                                                       nullptr,
+                                                       entry->per_cu);
+                 linkage->canonical = fullname;
+                 new_gnat_entries.push_back (linkage);
+               }
+           }
+         else
+           handle_gnat_encoded_entry (entry, gnat_entries.get (),
+                                      new_gnat_entries);
+       }
+      else if (entry->lang == language_cplus || entry->lang == language_c)
+       {
+         auto [it, inserted] = seen_names.insert (entry);
+
+         if (inserted)
+           {
+             /* No entry with that name was present, compute the canonical
+                name.  */
+             gdb::unique_xmalloc_ptr<char> canon_name
+               = (entry->lang == language_cplus
+                  ? cp_canonicalize_string (entry->name)
+                  : c_canonicalize_name (entry->name));
+             if (canon_name == nullptr)
+               entry->canonical = entry->name;
+             else
+               entry->canonical = m_names.insert (std::move (canon_name));
+           }
+         else
+           {
+             /* An entry with that name was present, re-use its canonical
+                name.  */
+             entry->canonical = (*it)->canonical;
+           }
+       }
+      else
+       entry->canonical = entry->name;
+    }
+
+  /* Make sure any new Ada entries end up in the results.  This isn't
+     done when creating these new entries to avoid invalidating the
+     m_entries iterator used in the foreach above.  */
+  m_entries.insert (m_entries.end (), new_gnat_entries.begin (),
+                   new_gnat_entries.end ());
+
+  m_entries.shrink_to_fit ();
+  std::sort (m_entries.begin (), m_entries.end (),
+            [] (const cooked_index_entry *a, const cooked_index_entry *b)
+            {
+              return *a < *b;
+            });
+}
+
+/* See cooked-index.h.  */
+
+cooked_index_shard::range
+cooked_index_shard::find (const std::string &name, bool completing) const
+{
+  struct comparator
+  {
+    cooked_index_entry::comparison_mode mode;
+
+    bool operator() (const cooked_index_entry *entry,
+                    const char *name) const noexcept
+    {
+      return cooked_index_entry::compare (entry->canonical, name, mode) < 0;
+    }
+
+    bool operator() (const char *name,
+                    const cooked_index_entry *entry) const noexcept
+    {
+      return cooked_index_entry::compare (entry->canonical, name, mode) > 0;
+    }
+  };
+
+  return std::make_from_tuple<range>
+    (std::equal_range (m_entries.cbegin (), m_entries.cend (), name.c_str (),
+                      comparator { (completing
+                                    ? cooked_index_entry::COMPLETE
+                                    : cooked_index_entry::MATCH) }));
+}
diff --git a/gdb/dwarf2/cooked-index-shard.h b/gdb/dwarf2/cooked-index-shard.h
new file mode 100644 (file)
index 0000000..eb80926
--- /dev/null
@@ -0,0 +1,134 @@
+/* Shards for the cooked index
+
+   Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_DWARF2_COOKED_INDEX_SHARD_H
+#define GDB_DWARF2_COOKED_INDEX_SHARD_H
+
+#include "dwarf2/cooked-index-entry.h"
+#include "dwarf2/types.h"
+#include "gdbsupport/gdb_obstack.h"
+#include "addrmap.h"
+#include "gdbsupport/iterator-range.h"
+#include "gdbsupport/string-set.h"
+
+/* An index of interesting DIEs.  This is "cooked", in contrast to a
+   mapped .debug_names or .gdb_index, which are "raw".  An entry in
+   the index is of type cooked_index_entry.
+
+   Operations on the index are described below.  They are chosen to
+   make it relatively simple to implement the symtab "quick"
+   methods.  */
+class cooked_index_shard
+{
+public:
+  cooked_index_shard () = default;
+  DISABLE_COPY_AND_ASSIGN (cooked_index_shard);
+
+  /* Create a new cooked_index_entry and register it with this object.
+     Entries are owned by this object.  The new item is returned.  */
+  cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+                          cooked_index_flag flags, enum language lang,
+                          const char *name,
+                          cooked_index_entry_ref parent_entry,
+                          dwarf2_per_cu *per_cu);
+
+  /* Install a new fixed addrmap from the given mutable addrmap.  */
+  void install_addrmap (addrmap_mutable *map)
+  {
+    gdb_assert (m_addrmap == nullptr);
+    m_addrmap = new (&m_storage) addrmap_fixed (&m_storage, map);
+  }
+
+  friend class cooked_index;
+
+  /* A simple range over part of m_entries.  */
+  typedef iterator_range<std::vector<cooked_index_entry *>::const_iterator>
+       range;
+
+  /* Return a range of all the entries.  */
+  range all_entries () const
+  {
+    return { m_entries.cbegin (), m_entries.cend () };
+  }
+
+  /* Look up an entry by name.  Returns a range of all matching
+     results.  If COMPLETING is true, then a larger range, suitable
+     for completion, will be returned.  */
+  range find (const std::string &name, bool completing) const;
+
+private:
+
+  /* Return the entry that is believed to represent the program's
+     "main".  This will return NULL if no such entry is available.  */
+  const cooked_index_entry *get_main () const
+  {
+    return m_main;
+  }
+
+  /* Look up ADDR in the address map, and return either the
+     corresponding CU, or nullptr if the address could not be
+     found.  */
+  dwarf2_per_cu *lookup (unrelocated_addr addr)
+  {
+    if (m_addrmap == nullptr)
+      return nullptr;
+
+    return (static_cast<dwarf2_per_cu *> (m_addrmap->find ((CORE_ADDR) addr)));
+  }
+
+  /* Create a new cooked_index_entry and register it with this object.
+     Entries are owned by this object.  The new item is returned.  */
+  cooked_index_entry *create (sect_offset die_offset,
+                             enum dwarf_tag tag,
+                             cooked_index_flag flags,
+                             enum language lang,
+                             const char *name,
+                             cooked_index_entry_ref parent_entry,
+                             dwarf2_per_cu *per_cu);
+
+  /* When GNAT emits mangled ("encoded") names in the DWARF, and does
+     not emit the module structure, we still need this structuring to
+     do lookups.  This function recreates that information for an
+     existing entry, modifying ENTRY as appropriate.  Any new entries
+     are added to NEW_ENTRIES.  */
+  void handle_gnat_encoded_entry
+       (cooked_index_entry *entry, htab_t gnat_entries,
+       std::vector<cooked_index_entry *> &new_entries);
+
+  /* Finalize the index.  This should be called a single time, when
+     the index has been fully populated.  It enters all the entries
+     into the internal table and fixes up all missing parent links.
+     This may be invoked in a worker thread.  */
+  void finalize (const parent_map_map *parent_maps);
+
+  /* Storage for the entries.  */
+  auto_obstack m_storage;
+  /* List of all entries.  */
+  std::vector<cooked_index_entry *> m_entries;
+  /* If we found an entry with 'is_main' set, store it here.  */
+  cooked_index_entry *m_main = nullptr;
+  /* The addrmap.  This maps address ranges to dwarf2_per_cu objects.  */
+  addrmap_fixed *m_addrmap = nullptr;
+  /* Storage for canonical names.  */
+  gdb::string_set m_names;
+};
+
+using cooked_index_shard_up = std::unique_ptr<cooked_index_shard>;
+
+#endif /* GDB_DWARF2_COOKED_INDEX_SHARD_H */
index 9d5f152045bd9a28b0c6278f5b4720cb55b69112..5d205a83d0917660c40c05afd5f9e058a81d053c 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "dwarf2/cooked-index.h"
-#include "dwarf2/index-common.h"
 #include "dwarf2/read.h"
 #include "dwarf2/stringify.h"
 #include "dwarf2/index-cache.h"
-#include "cp-support.h"
-#include "c-lang.h"
-#include "ada-lang.h"
-#include "dwarf2/tag.h"
 #include "event-top.h"
 #include "exceptions.h"
 #include "split-name.h"
@@ -55,312 +50,6 @@ language_requires_canonicalization (enum language lang)
          || lang == language_cplus);
 }
 
-/* Return true if a plain "main" could be the main program for this
-   language.  Languages that are known to use some other mechanism are
-   excluded here.  */
-
-static bool
-language_may_use_plain_main (enum language lang)
-{
-  /* No need to handle "unknown" here.  */
-  return (lang == language_c
-         || lang == language_objc
-         || lang == language_cplus
-         || lang == language_m2
-         || lang == language_asm
-         || lang == language_opencl
-         || lang == language_minimal);
-}
-
-/* See cooked-index.h.  */
-
-cooked_index_entry *
-cooked_index_shard::create (sect_offset die_offset,
-                           enum dwarf_tag tag,
-                           cooked_index_flag flags,
-                           enum language lang,
-                           const char *name,
-                           cooked_index_entry_ref parent_entry,
-                           dwarf2_per_cu *per_cu)
-{
-  if (tag == DW_TAG_module || tag == DW_TAG_namespace)
-    flags &= ~IS_STATIC;
-  else if (lang == language_cplus
-          && (tag == DW_TAG_class_type
-              || tag == DW_TAG_interface_type
-              || tag == DW_TAG_structure_type
-              || tag == DW_TAG_union_type
-              || tag == DW_TAG_enumeration_type
-              || tag == DW_TAG_enumerator))
-    flags &= ~IS_STATIC;
-  else if (tag_is_type (tag))
-    flags |= IS_STATIC;
-
-  return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
-                                             lang, name, parent_entry,
-                                             per_cu);
-}
-
-/* See cooked-index.h.  */
-
-cooked_index_entry *
-cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag,
-                        cooked_index_flag flags, enum language lang,
-                        const char *name, cooked_index_entry_ref parent_entry,
-                        dwarf2_per_cu *per_cu)
-{
-  cooked_index_entry *result = create (die_offset, tag, flags, lang, name,
-                                      parent_entry, per_cu);
-  m_entries.push_back (result);
-
-  /* An explicitly-tagged main program should always override the
-     implicit "main" discovery.  */
-  if ((flags & IS_MAIN) != 0)
-    m_main = result;
-  else if ((flags & IS_PARENT_DEFERRED) == 0
-          && parent_entry.resolved == nullptr
-          && m_main == nullptr
-          && language_may_use_plain_main (lang)
-          && strcmp (name, "main") == 0)
-    m_main = result;
-
-  return result;
-}
-
-/* See cooked-index.h.  */
-
-void
-cooked_index_shard::handle_gnat_encoded_entry
-     (cooked_index_entry *entry,
-      htab_t gnat_entries,
-      std::vector<cooked_index_entry *> &new_entries)
-{
-  /* We decode Ada names in a particular way: operators and wide
-     characters are left as-is.  This is done to make name matching a
-     bit simpler; and for wide characters, it means the choice of Ada
-     source charset does not affect the indexer directly.  */
-  std::string canonical = ada_decode (entry->name, false, false, false);
-  if (canonical.empty ())
-    {
-      entry->canonical = entry->name;
-      return;
-    }
-  std::vector<std::string_view> names = split_name (canonical.c_str (),
-                                                   split_style::DOT_STYLE);
-  std::string_view tail = names.back ();
-  names.pop_back ();
-
-  const cooked_index_entry *parent = nullptr;
-  for (const auto &name : names)
-    {
-      uint32_t hashval = dwarf5_djb_hash (name);
-      void **slot = htab_find_slot_with_hash (gnat_entries, &name,
-                                             hashval, INSERT);
-      /* CUs are processed in order, so we only need to check the most
-        recent entry.  */
-      cooked_index_entry *last = (cooked_index_entry *) *slot;
-      if (last == nullptr || last->per_cu != entry->per_cu)
-       {
-         const char *new_name = m_names.insert (name);
-         last = create (entry->die_offset, DW_TAG_module,
-                        IS_SYNTHESIZED, language_ada, new_name, parent,
-                        entry->per_cu);
-         last->canonical = last->name;
-         new_entries.push_back (last);
-         *slot = last;
-       }
-
-      parent = last;
-    }
-
-  entry->set_parent (parent);
-  entry->canonical = m_names.insert (tail);
-}
-
-/* Hash a cooked index entry by name pointer value.
-
-   We can use pointer equality here because names come from .debug_str, which
-   will normally be unique-ified by the linker.  Also, duplicates are relatively
-   harmless -- they just mean a bit of extra memory is used.  */
-
-struct cooked_index_entry_name_ptr_hash
-{
-  using is_avalanching = void;
-
-  std::uint64_t operator () (const cooked_index_entry *entry) const noexcept
-  {
-    return ankerl::unordered_dense::hash<const char *> () (entry->name);
-  }
-};
-
-/* Compare cooked index entries by name pointer value.  */
-
-struct cooked_index_entry_name_ptr_eq
-{
-  bool operator () (const cooked_index_entry *a,
-                   const cooked_index_entry *b) const noexcept
-  {
-    return a->name == b->name;
-  }
-};
-
-/* See cooked-index.h.  */
-
-void
-cooked_index_shard::finalize (const parent_map_map *parent_maps)
-{
-  gdb::unordered_set<const cooked_index_entry *,
-                    cooked_index_entry_name_ptr_hash,
-                    cooked_index_entry_name_ptr_eq> seen_names;
-
-  auto hash_entry = [] (const void *e)
-    {
-      const cooked_index_entry *entry = (const cooked_index_entry *) e;
-      return dwarf5_djb_hash (entry->canonical);
-    };
-
-  auto eq_entry = [] (const void *a, const void *b) -> int
-    {
-      const cooked_index_entry *ae = (const cooked_index_entry *) a;
-      const std::string_view *sv = (const std::string_view *) b;
-      return (strlen (ae->canonical) == sv->length ()
-             && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
-    };
-
-  htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
-                                          nullptr, xcalloc, xfree));
-  std::vector<cooked_index_entry *> new_gnat_entries;
-
-  for (cooked_index_entry *entry : m_entries)
-    {
-      if ((entry->flags & IS_PARENT_DEFERRED) != 0)
-       {
-         const cooked_index_entry *new_parent
-           = parent_maps->find (entry->get_deferred_parent ());
-         entry->resolve_parent (new_parent);
-       }
-
-      /* Note that this code must be kept in sync with
-        language_requires_canonicalization.  */
-      gdb_assert (entry->canonical == nullptr);
-      if ((entry->flags & IS_LINKAGE) != 0)
-       entry->canonical = entry->name;
-      else if (entry->lang == language_ada)
-       {
-         /* Newer versions of GNAT emit DW_TAG_module and use a
-            hierarchical structure.  In this case, we don't need to
-            do any extra work.  This can be detected by looking for a
-            GNAT-encoded name.  */
-         if (strstr (entry->name, "__") == nullptr)
-           {
-             entry->canonical = entry->name;
-
-             /* If the entry does not have a parent, then there's
-                nothing extra to do here -- the entry itself is
-                sufficient.
-
-                However, if it does have a parent, we have to
-                synthesize an entry with the full name.  This is
-                unfortunate, but it's necessary due to how some of
-                the Ada name-lookup code currently works.  For
-                example, without this, ada_get_tsd_type will
-                fail.
-
-                Eventually it would be good to change the Ada lookup
-                code, and then remove these entries (and supporting
-                code in cooked_index_entry::full_name).  */
-             if (entry->get_parent () != nullptr)
-               {
-                 const char *fullname
-                   = entry->full_name (&m_storage, FOR_ADA_LINKAGE_NAME);
-                 cooked_index_entry *linkage = create (entry->die_offset,
-                                                       entry->tag,
-                                                       (entry->flags
-                                                        | IS_LINKAGE
-                                                        | IS_SYNTHESIZED),
-                                                       language_ada,
-                                                       fullname,
-                                                       nullptr,
-                                                       entry->per_cu);
-                 linkage->canonical = fullname;
-                 new_gnat_entries.push_back (linkage);
-               }
-           }
-         else
-           handle_gnat_encoded_entry (entry, gnat_entries.get (),
-                                      new_gnat_entries);
-       }
-      else if (entry->lang == language_cplus || entry->lang == language_c)
-       {
-         auto [it, inserted] = seen_names.insert (entry);
-
-         if (inserted)
-           {
-             /* No entry with that name was present, compute the canonical
-                name.  */
-             gdb::unique_xmalloc_ptr<char> canon_name
-               = (entry->lang == language_cplus
-                  ? cp_canonicalize_string (entry->name)
-                  : c_canonicalize_name (entry->name));
-             if (canon_name == nullptr)
-               entry->canonical = entry->name;
-             else
-               entry->canonical = m_names.insert (std::move (canon_name));
-           }
-         else
-           {
-             /* An entry with that name was present, re-use its canonical
-                name.  */
-             entry->canonical = (*it)->canonical;
-           }
-       }
-      else
-       entry->canonical = entry->name;
-    }
-
-  /* Make sure any new Ada entries end up in the results.  This isn't
-     done when creating these new entries to avoid invalidating the
-     m_entries iterator used in the foreach above.  */
-  m_entries.insert (m_entries.end (), new_gnat_entries.begin (),
-                   new_gnat_entries.end ());
-
-  m_entries.shrink_to_fit ();
-  std::sort (m_entries.begin (), m_entries.end (),
-            [] (const cooked_index_entry *a, const cooked_index_entry *b)
-            {
-              return *a < *b;
-            });
-}
-
-/* See cooked-index.h.  */
-
-cooked_index_shard::range
-cooked_index_shard::find (const std::string &name, bool completing) const
-{
-  struct comparator
-  {
-    cooked_index_entry::comparison_mode mode;
-
-    bool operator() (const cooked_index_entry *entry,
-                    const char *name) const noexcept
-    {
-      return cooked_index_entry::compare (entry->canonical, name, mode) < 0;
-    }
-
-    bool operator() (const char *name,
-                    const cooked_index_entry *entry) const noexcept
-    {
-      return cooked_index_entry::compare (entry->canonical, name, mode) > 0;
-    }
-  };
-
-  return std::make_from_tuple<range>
-    (std::equal_range (m_entries.cbegin (), m_entries.cend (), name.c_str (),
-                      comparator { (completing
-                                    ? cooked_index_entry::COMPLETE
-                                    : cooked_index_entry::MATCH) }));
-}
-
 /* See cooked-index.h.  */
 
 void
index d50d1c9aa72fdf4716edc334f69092eba54ee9a0..beef8ff588f0895cf08323ded02da47df74c7c96 100644 (file)
 #include "quick-symbol.h"
 #include "gdbsupport/gdb_obstack.h"
 #include "addrmap.h"
-#include "gdbsupport/iterator-range.h"
 #include "dwarf2/mapped-index.h"
 #include "dwarf2/read.h"
 #include "dwarf2/parent-map.h"
 #include "gdbsupport/range-chain.h"
-#include "gdbsupport/string-set.h"
 #include "complaints.h"
+#include "dwarf2/cooked-index-shard.h"
 
 #if CXX_STD_THREAD
 #include <mutex>
@@ -48,110 +47,6 @@ struct cooked_index_entry;
 
 class cooked_index;
 
-/* An index of interesting DIEs.  This is "cooked", in contrast to a
-   mapped .debug_names or .gdb_index, which are "raw".  An entry in
-   the index is of type cooked_index_entry.
-
-   Operations on the index are described below.  They are chosen to
-   make it relatively simple to implement the symtab "quick"
-   methods.  */
-class cooked_index_shard
-{
-public:
-  cooked_index_shard () = default;
-  DISABLE_COPY_AND_ASSIGN (cooked_index_shard);
-
-  /* Create a new cooked_index_entry and register it with this object.
-     Entries are owned by this object.  The new item is returned.  */
-  cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
-                          cooked_index_flag flags, enum language lang,
-                          const char *name,
-                          cooked_index_entry_ref parent_entry,
-                          dwarf2_per_cu *per_cu);
-
-  /* Install a new fixed addrmap from the given mutable addrmap.  */
-  void install_addrmap (addrmap_mutable *map)
-  {
-    gdb_assert (m_addrmap == nullptr);
-    m_addrmap = new (&m_storage) addrmap_fixed (&m_storage, map);
-  }
-
-  friend class cooked_index;
-
-  /* A simple range over part of m_entries.  */
-  typedef iterator_range<std::vector<cooked_index_entry *>::const_iterator>
-       range;
-
-  /* Return a range of all the entries.  */
-  range all_entries () const
-  {
-    return { m_entries.cbegin (), m_entries.cend () };
-  }
-
-  /* Look up an entry by name.  Returns a range of all matching
-     results.  If COMPLETING is true, then a larger range, suitable
-     for completion, will be returned.  */
-  range find (const std::string &name, bool completing) const;
-
-private:
-
-  /* Return the entry that is believed to represent the program's
-     "main".  This will return NULL if no such entry is available.  */
-  const cooked_index_entry *get_main () const
-  {
-    return m_main;
-  }
-
-  /* Look up ADDR in the address map, and return either the
-     corresponding CU, or nullptr if the address could not be
-     found.  */
-  dwarf2_per_cu *lookup (unrelocated_addr addr)
-  {
-    if (m_addrmap == nullptr)
-      return nullptr;
-
-    return (static_cast<dwarf2_per_cu *> (m_addrmap->find ((CORE_ADDR) addr)));
-  }
-
-  /* Create a new cooked_index_entry and register it with this object.
-     Entries are owned by this object.  The new item is returned.  */
-  cooked_index_entry *create (sect_offset die_offset,
-                             enum dwarf_tag tag,
-                             cooked_index_flag flags,
-                             enum language lang,
-                             const char *name,
-                             cooked_index_entry_ref parent_entry,
-                             dwarf2_per_cu *per_cu);
-
-  /* When GNAT emits mangled ("encoded") names in the DWARF, and does
-     not emit the module structure, we still need this structuring to
-     do lookups.  This function recreates that information for an
-     existing entry, modifying ENTRY as appropriate.  Any new entries
-     are added to NEW_ENTRIES.  */
-  void handle_gnat_encoded_entry
-       (cooked_index_entry *entry, htab_t gnat_entries,
-       std::vector<cooked_index_entry *> &new_entries);
-
-  /* Finalize the index.  This should be called a single time, when
-     the index has been fully populated.  It enters all the entries
-     into the internal table and fixes up all missing parent links.
-     This may be invoked in a worker thread.  */
-  void finalize (const parent_map_map *parent_maps);
-
-  /* Storage for the entries.  */
-  auto_obstack m_storage;
-  /* List of all entries.  */
-  std::vector<cooked_index_entry *> m_entries;
-  /* If we found an entry with 'is_main' set, store it here.  */
-  cooked_index_entry *m_main = nullptr;
-  /* The addrmap.  This maps address ranges to dwarf2_per_cu objects.  */
-  addrmap_fixed *m_addrmap = nullptr;
-  /* Storage for canonical names.  */
-  gdb::string_set m_names;
-};
-
-using cooked_index_shard_up = std::unique_ptr<cooked_index_shard>;
-
 /* The possible states of the index.  See the explanatory comment
    before cooked_index for more details.  */
 enum class cooked_state