return result;
}
-cooked_index_vector::cooked_index_vector (vec_type &&vec)
- : m_vector (std::move (vec)),
- m_future (gdb::thread_pool::g_thread_pool->post_task
- ([this] ()
- {
- finalize ();
- }))
-{
-}
-
/* See cooked-index.h. */
-dwarf2_per_cu_data *
-cooked_index_vector::lookup (CORE_ADDR addr)
+void
+cooked_index::finalize ()
{
- for (const auto &index : m_vector)
+ m_future = gdb::thread_pool::g_thread_pool->post_task ([this] ()
{
- dwarf2_per_cu_data *result = index->lookup (addr);
- if (result != nullptr)
- return result;
- }
- return nullptr;
-}
-
-/* See cooked-index.h. */
-
-std::vector<addrmap *>
-cooked_index_vector::get_addrmaps ()
-{
- std::vector<addrmap *> result;
- for (const auto &index : m_vector)
- result.push_back (index->m_addrmap);
- return result;
-}
-
-/* See cooked-index.h. */
-
-cooked_index_vector::range
-cooked_index_vector::find (gdb::string_view name, bool completing)
-{
- m_future.wait ();
-
- auto lower = std::lower_bound (m_entries.begin (), m_entries.end (),
- name,
- [=] (const cooked_index_entry *entry,
- const gdb::string_view &n)
- {
- int cmp = strncasecmp (entry->canonical, n.data (), n.length ());
- if (cmp != 0 || completing)
- return cmp < 0;
- return strlen (entry->canonical) < n.length ();
- });
-
- auto upper = std::upper_bound (m_entries.begin (), m_entries.end (),
- name,
- [=] (const gdb::string_view &n,
- const cooked_index_entry *entry)
- {
- int cmp = strncasecmp (n.data (), entry->canonical, n.length ());
- if (cmp != 0 || completing)
- return cmp < 0;
- return n.length () < strlen (entry->canonical);
- });
-
- return range (lower, upper);
+ do_finalize ();
+ });
}
/* See cooked-index.h. */
gdb::unique_xmalloc_ptr<char>
-cooked_index_vector::handle_gnat_encoded_entry (cooked_index_entry *entry,
- htab_t gnat_entries)
+cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
+ htab_t gnat_entries)
{
std::string canonical = ada_decode (entry->name, false, false);
if (canonical.empty ())
{
gdb::unique_xmalloc_ptr<char> new_name
= make_unique_xstrndup (name.data (), name.length ());
- /* It doesn't matter which obstack we allocate this on, so
- we pick the most convenient one. */
- last = m_vector[0]->create (entry->die_offset, DW_TAG_namespace,
- 0, new_name.get (), parent,
- entry->per_cu);
+ last = create (entry->die_offset, DW_TAG_namespace,
+ 0, new_name.get (), parent,
+ entry->per_cu);
last->canonical = last->name;
m_names.push_back (std::move (new_name));
*slot = last;
/* See cooked-index.h. */
-const cooked_index_entry *
-cooked_index_vector::get_main () const
-{
- const cooked_index_entry *result = nullptr;
-
- for (const auto &index : m_vector)
- {
- const cooked_index_entry *entry = index->get_main ();
- if (result == nullptr
- || ((result->flags & IS_MAIN) == 0
- && entry != nullptr
- && (entry->flags & IS_MAIN) != 0))
- result = entry;
- }
-
- return result;
-}
-
-/* See cooked-index.h. */
-
void
-cooked_index_vector::finalize ()
+cooked_index::do_finalize ()
{
auto hash_name_ptr = [] (const void *p)
{
htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr,
nullptr, xcalloc, xfree));
- for (auto &index : m_vector)
- {
- htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
- nullptr, xcalloc, xfree));
+ htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
+ nullptr, xcalloc, xfree));
- std::vector<cooked_index_entry *> entries
- = std::move (index->m_entries);
- for (cooked_index_entry *entry : entries)
+ for (cooked_index_entry *entry : m_entries)
+ {
+ gdb_assert (entry->canonical == nullptr);
+ if ((entry->per_cu->lang != language_cplus
+ && entry->per_cu->lang != language_ada)
+ || (entry->flags & IS_LINKAGE) != 0)
+ entry->canonical = entry->name;
+ else
{
- gdb_assert (entry->canonical == nullptr);
- if ((entry->per_cu->lang != language_cplus
- && entry->per_cu->lang != language_ada)
- || (entry->flags & IS_LINKAGE) != 0)
- entry->canonical = entry->name;
+ if (entry->per_cu->lang == language_ada)
+ {
+ gdb::unique_xmalloc_ptr<char> canon_name
+ = handle_gnat_encoded_entry (entry, gnat_entries.get ());
+ if (canon_name == nullptr)
+ entry->canonical = entry->name;
+ else
+ {
+ entry->canonical = canon_name.get ();
+ m_names.push_back (std::move (canon_name));
+ }
+ }
else
{
- if (entry->per_cu->lang == language_ada)
+ void **slot = htab_find_slot (seen_names.get (), entry,
+ INSERT);
+ if (*slot == nullptr)
{
gdb::unique_xmalloc_ptr<char> canon_name
- = handle_gnat_encoded_entry (entry, gnat_entries.get ());
+ = cp_canonicalize_string (entry->name);
if (canon_name == nullptr)
entry->canonical = entry->name;
else
}
else
{
- void **slot = htab_find_slot (seen_names.get (), entry,
- INSERT);
- if (*slot == nullptr)
- {
- gdb::unique_xmalloc_ptr<char> canon_name
- = cp_canonicalize_string (entry->name);
- if (canon_name == nullptr)
- entry->canonical = entry->name;
- else
- {
- entry->canonical = canon_name.get ();
- m_names.push_back (std::move (canon_name));
- }
- }
- else
- {
- const cooked_index_entry *other
- = (const cooked_index_entry *) *slot;
- entry->canonical = other->canonical;
- }
+ const cooked_index_entry *other
+ = (const cooked_index_entry *) *slot;
+ entry->canonical = other->canonical;
}
}
}
-
- if (m_entries.empty ())
- m_entries = std::move (entries);
- else
- {
- m_entries.reserve (m_entries.size () + entries.size ());
- m_entries.insert (m_entries.end (), entries.begin (), entries.end ());
- }
}
m_names.shrink_to_fit ();
return *a < *b;
});
}
+
+/* See cooked-index.h. */
+
+cooked_index::range
+cooked_index::find (gdb::string_view name, bool completing)
+{
+ wait ();
+
+ auto lower = std::lower_bound (m_entries.begin (), m_entries.end (),
+ name,
+ [=] (const cooked_index_entry *entry,
+ const gdb::string_view &n)
+ {
+ int cmp = strncasecmp (entry->canonical, n.data (), n.length ());
+ if (cmp != 0 || completing)
+ return cmp < 0;
+ return strlen (entry->canonical) < n.length ();
+ });
+
+ auto upper = std::upper_bound (m_entries.begin (), m_entries.end (),
+ name,
+ [=] (const gdb::string_view &n,
+ const cooked_index_entry *entry)
+ {
+ int cmp = strncasecmp (n.data (), entry->canonical, n.length ());
+ if (cmp != 0 || completing)
+ return cmp < 0;
+ return n.length () < strlen (entry->canonical);
+ });
+
+ return range (lower, upper);
+}
+
+cooked_index_vector::cooked_index_vector (vec_type &&vec)
+ : m_vector (std::move (vec))
+{
+ for (auto &idx : m_vector)
+ idx->finalize ();
+}
+
+/* See cooked-index.h. */
+
+dwarf2_per_cu_data *
+cooked_index_vector::lookup (CORE_ADDR addr)
+{
+ for (const auto &index : m_vector)
+ {
+ dwarf2_per_cu_data *result = index->lookup (addr);
+ if (result != nullptr)
+ return result;
+ }
+ return nullptr;
+}
+
+/* See cooked-index.h. */
+
+std::vector<addrmap *>
+cooked_index_vector::get_addrmaps ()
+{
+ std::vector<addrmap *> result;
+ for (const auto &index : m_vector)
+ result.push_back (index->m_addrmap);
+ return result;
+}
+
+/* See cooked-index.h. */
+
+cooked_index_vector::range
+cooked_index_vector::find (gdb::string_view name, bool completing)
+{
+ std::vector<cooked_index::range> result_range;
+ result_range.reserve (m_vector.size ());
+ for (auto &entry : m_vector)
+ result_range.push_back (entry->find (name, completing));
+ return range (std::move (result_range));
+}
+
+/* See cooked-index.h. */
+
+const cooked_index_entry *
+cooked_index_vector::get_main () const
+{
+ const cooked_index_entry *result = nullptr;
+
+ for (const auto &index : m_vector)
+ {
+ const cooked_index_entry *entry = index->get_main ();
+ if (result == nullptr
+ || ((result->flags & IS_MAIN) == 0
+ && entry != nullptr
+ && (entry->flags & IS_MAIN) != 0))
+ result = entry;
+ }
+
+ return result;
+}
#include "gdbsupport/thread-pool.h"
#include "dwarf2/mapped-index.h"
#include "dwarf2/tag.h"
+#include "gdbsupport/range-chain.h"
struct dwarf2_per_cu_data;
m_addrmap = addrmap_create_fixed (map, &m_storage);
}
+ /* 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. */
+ void finalize ();
+
+ /* Wait for this index's finalization to be complete. */
+ void wait ()
+ {
+ m_future.wait ();
+ }
+
friend class cooked_index_vector;
+ /* A simple range over part of m_entries. */
+ typedef iterator_range<std::vector<cooked_index_entry *>::iterator> range;
+
+ /* Return a range of all the entries. */
+ range all_entries ()
+ {
+ wait ();
+ return { m_entries.begin (), m_entries.end () };
+ }
+
+ /* 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 (gdb::string_view name, bool completing);
+
private:
/* Return the entry that is believed to represent the program's
per_cu);
}
+ /* GNAT only emits mangled ("encoded") names in the DWARF, and does
+ not emit the module structure. However, we need this structure
+ to do lookups. This function recreates that structure for an
+ existing entry. It returns the base name (last element) of the
+ full decoded name. */
+ gdb::unique_xmalloc_ptr<char> handle_gnat_encoded_entry
+ (cooked_index_entry *entry, htab_t gnat_entries);
+
+ /* A helper method that does the work of 'finalize'. */
+ void do_finalize ();
+
/* Storage for the entries. */
auto_obstack m_storage;
/* List of all entries. */
/* The addrmap. This maps address ranges to dwarf2_per_cu_data
objects. */
addrmap *m_addrmap = nullptr;
+ /* Storage for canonical names. */
+ std::vector<gdb::unique_xmalloc_ptr<char>> m_names;
+ /* A future that tracks when the 'finalize' method is done. Note
+ that the 'get' method is never called on this future, only
+ 'wait'. */
+ gdb::future<void> m_future;
};
/* The main index of DIEs. The parallel DIE indexers create
~cooked_index_vector ()
{
- /* The 'finalize' method may be run in a different thread. If
- this object is destroyed before this completes, then the method
- will end up writing to freed memory. Waiting for this to
+ /* The 'finalize' methods may be run in a different thread. If
+ this object is destroyed before these complete, then one will
+ end up writing to freed memory. Waiting for finalization to
complete avoids this problem; and the cost seems ignorable
because creating and immediately destroying the debug info is a
relatively rare thing to do. */
- m_future.wait ();
+ for (auto &item : m_vector)
+ item->wait ();
}
- /* A simple range over part of m_entries. */
- typedef iterator_range<std::vector<cooked_index_entry *>::iterator> range;
+ /* A range over a vector of subranges. */
+ typedef range_chain<cooked_index::range> range;
/* Look up an entry by name. Returns a range of all matching
results. If COMPLETING is true, then a larger range, suitable
/* Return a range of all the entries. */
range all_entries ()
{
- m_future.wait ();
- return { m_entries.begin (), m_entries.end () };
+ std::vector<cooked_index::range> result_range;
+ result_range.reserve (m_vector.size ());
+ for (auto &entry : m_vector)
+ result_range.push_back (entry->all_entries ());
+ return range (std::move (result_range));
}
/* Look up ADDR in the address map, and return either the
private:
- /* GNAT only emits mangled ("encoded") names in the DWARF, and does
- not emit the module structure. However, we need this structure
- to do lookups. This function recreates that structure for an
- existing entry. It returns the base name (last element) of the
- full decoded name. */
- gdb::unique_xmalloc_ptr<char> handle_gnat_encoded_entry
- (cooked_index_entry *entry, htab_t gnat_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 hash table. */
- void finalize ();
-
/* The vector of cooked_index objects. This is stored because the
entries are stored on the obstacks in those objects. */
vec_type m_vector;
-
- /* List of all entries. This is sorted during finalization. */
- std::vector<cooked_index_entry *> m_entries;
-
- /* Storage for canonical names. */
- std::vector<gdb::unique_xmalloc_ptr<char>> m_names;
-
- /* A future that tracks when the 'finalize' method is done. Note
- that the 'get' method is never called on this future, only
- 'wait'. */
- gdb::future<void> m_future;
};
#endif /* GDB_DWARF2_COOKED_INDEX_H */
--- /dev/null
+/* A range adapter that wraps multiple ranges
+ Copyright (C) 2022 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 GDBSUPPORT_RANGE_CHAIN_H
+#define GDBSUPPORT_RANGE_CHAIN_H
+
+/* A range adapter that presents a number of ranges as if it were a
+ single range. That is, iterating over a range_chain will iterate
+ over each sub-range in order. */
+template<typename Range>
+struct range_chain
+{
+ /* The type of the iterator that is created by this range. */
+ class iterator
+ {
+ public:
+
+ iterator (const std::vector<Range> &ranges, size_t idx)
+ : m_index (idx),
+ m_ranges (ranges)
+ {
+ skip_empty ();
+ }
+
+ bool operator== (const iterator &other) const
+ {
+ if (m_index != other.m_index || &m_ranges != &other.m_ranges)
+ return false;
+ if (m_current.has_value () != other.m_current.has_value ())
+ return false;
+ if (m_current.has_value ())
+ return *m_current == *other.m_current;
+ return true;
+ }
+
+ bool operator!= (const iterator &other) const
+ {
+ return !(*this == other);
+ }
+
+ iterator &operator++ ()
+ {
+ ++*m_current;
+ if (*m_current == m_ranges[m_index].end ())
+ {
+ ++m_index;
+ skip_empty ();
+ }
+ return *this;
+ }
+
+ typename Range::iterator::value_type operator* () const
+ {
+ return **m_current;
+ }
+
+ private:
+ /* Skip empty sub-ranges. If this finds a valid sub-range,
+ m_current is updated to point to its start; otherwise,
+ m_current is reset. */
+ void skip_empty ()
+ {
+ for (; m_index < m_ranges.size (); ++m_index)
+ {
+ m_current = m_ranges[m_index].begin ();
+ if (*m_current != m_ranges[m_index].end ())
+ return;
+ }
+ m_current.reset ();
+ }
+
+ /* Index into the vector indicating where the current iterator
+ comes from. */
+ size_t m_index;
+ /* The current iterator into one of the vector ranges. If no
+ value then this (outer) iterator is at the end of the overall
+ range. */
+ gdb::optional<typename Range::iterator> m_current;
+ /* Vector of ranges. */
+ const std::vector<Range> &m_ranges;
+ };
+
+ /* Create a new range_chain. */
+ template<typename T>
+ range_chain (T &&ranges)
+ : m_ranges (std::forward<T> (ranges))
+ {
+ }
+
+ iterator begin () const
+ {
+ return iterator (m_ranges, 0);
+ }
+
+ iterator end () const
+ {
+ return iterator (m_ranges, m_ranges.size ());
+ }
+
+private:
+
+ /* The sub-ranges. */
+ std::vector<Range> m_ranges;
+};
+
+#endif /* GDBSUPPORT_RANGE_CHAIN_H */