diff options
author | Tom Tromey <tom@tromey.com> | 2025-03-24 15:19:20 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2025-04-01 07:30:10 -0600 |
commit | 3351f741c8dabb239e411c2a05c248f7a86a9c27 (patch) | |
tree | 8938e12587027adb73cc8dcc4ffbe8a1be83221c | |
parent | 5bc2273db46b9a55c768473cc9b835f076a27c64 (diff) | |
download | binutils-3351f741c8dabb239e411c2a05c248f7a86a9c27.zip binutils-3351f741c8dabb239e411c2a05c248f7a86a9c27.tar.gz binutils-3351f741c8dabb239e411c2a05c248f7a86a9c27.tar.bz2 |
Move cooked_index_shard to new files
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>
-rw-r--r-- | gdb/Makefile.in | 2 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-shard.c | 331 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-shard.h | 134 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index.c | 311 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index.h | 107 |
5 files changed, 468 insertions, 417 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index b4e5407..0c4102d 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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 index 0000000..41844cd --- /dev/null +++ b/gdb/dwarf2/cooked-index-shard.c @@ -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 index 0000000..eb80926 --- /dev/null +++ b/gdb/dwarf2/cooked-index-shard.h @@ -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 */ diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 9d5f152..5d205a8 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -18,14 +18,9 @@ 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 diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h index d50d1c9..beef8ff 100644 --- a/gdb/dwarf2/cooked-index.h +++ b/gdb/dwarf2/cooked-index.h @@ -28,13 +28,12 @@ #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 |