@@ -1244,11 +1244,10 @@ jit_breakpoint_re_set (void)
static void
jit_inferior_exit_hook (struct inferior *inf)
{
- for (objfile *objf : current_program_space->objfiles_safe ())
+ current_program_space->remove_objfiles_if ([&] (const objfile *objf)
{
- if (objf->jited_data != nullptr && objf->jited_data->addr != 0)
- objf->unlink ();
- }
+ return (objf->jited_data != nullptr) && (objf->jited_data->addr != 0);
+ });
}
void
@@ -411,6 +411,14 @@ objfile::unlink ()
this->pspace ()->remove_objfile (this);
}
+/* See objfiles.h. */
+
+qf_safe_range
+objfile::qf_safe ()
+{
+ return qf_safe_range (qf_range (qf.begin (), qf.end ()));
+}
+
/* Free all separate debug objfile of OBJFILE, but don't free OBJFILE
itself. */
@@ -723,14 +731,12 @@ have_full_symbols (program_space *pspace)
void
objfile_purge_solibs (program_space *pspace)
{
- for (objfile *objf : pspace->objfiles_safe ())
+ pspace->remove_objfiles_if ([&] (const objfile *objf)
{
/* We assume that the solib package has been purged already, or will
be soon. */
-
- if (!(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED))
- objf->unlink ();
- }
+ return !(objf->flags & OBJF_USERLOADED) && (objf->flags & OBJF_SHARED);
+ });
}
/* See objfiles.h. */
@@ -365,6 +365,12 @@ class separate_debug_iterator
typedef iterator_range<separate_debug_iterator> separate_debug_range;
+/* See objfile::qf_safe. */
+
+using qf_list = std::forward_list<quick_symbol_functions_up>;
+using qf_range = iterator_range<qf_list::iterator>;
+using qf_safe_range = basic_safe_range<qf_range>;
+
/* Sections in an objfile. The section offsets are stored in the
OBJFILE. */
@@ -770,8 +776,15 @@ struct objfile : intrusive_list_node<objfile>
const struct sym_fns *sf = nullptr;
/* The "quick" (aka partial) symbol functions for this symbol
- reader. */
- std::forward_list<quick_symbol_functions_up> qf;
+ reader. Many quick_symbol_functions methods may result
+ in the deletion of a quick_symbol_functions from this
+ qf_list. It is recommended that qf_safe be used to iterate
+ over the qf_list. */
+ qf_list qf;
+
+ /* Returns an iterable object that allows for safe deletion during
+ iteration. See gdbsupport/safe-iterator.h. */
+ qf_safe_range qf_safe ();
/* Per objfile data-pointers required by other GDB modules. */
@@ -148,14 +148,14 @@ program_space::free_all_objfiles ()
void
program_space::add_objfile (std::unique_ptr<objfile> &&objfile,
- struct objfile *before)
+ struct objfile *after)
{
- if (before == nullptr)
+ if (after == nullptr)
m_objfiles_list.push_back (std::move (objfile));
else
{
- gdb_assert (before->is_linked ());
- m_objfiles_list.insert (m_objfiles_list.iterator_to (*before),
+ gdb_assert (after->is_linked ());
+ m_objfiles_list.insert (++m_objfiles_list.iterator_to (*after),
std::move (objfile));
}
}
@@ -180,6 +180,17 @@ program_space::remove_objfile (struct objfile *objfile)
/* See progspace.h. */
+void
+program_space::remove_objfiles_if
+ (gdb::function_view<bool (const objfile *objfile)> predicate)
+{
+ for (objfile *objf : objfiles_safe ())
+ if (predicate (objf))
+ remove_objfile (objf);
+}
+
+/* See progspace.h. */
+
struct objfile *
program_space::objfile_for_address (CORE_ADDR address)
{
@@ -196,26 +196,33 @@ struct program_space
return objfiles_range (objfiles_iterator (m_objfiles_list.begin ()));
}
- using objfiles_safe_range = basic_safe_range<objfiles_range>;
+ using objfiles_safe_reverse_range
+ = basic_safe_reverse_range<objfiles_range>;
/* An iterable object that can be used to iterate over all objfiles.
The basic use is in a foreach, like:
for (objfile *objf : pspace->objfiles_safe ()) { ... }
- This variant uses a basic_safe_iterator so that objfiles can be
- deleted during iteration. */
- objfiles_safe_range objfiles_safe ()
+ This variant uses a basic_safe_reverse_iterator so that objfiles
+ can be deleted during iteration.
+
+ The use of a reverse iterator helps ensure that separate debug
+ objfiles are deleted before their parent objfile. This prevents
+ iterator invalidation due to the deletion of a parent objfile. */
+
+ objfiles_safe_reverse_range objfiles_safe ()
{
- return objfiles_safe_range
- (objfiles_range (objfiles_iterator (m_objfiles_list.begin ())));
+ return objfiles_safe_reverse_range
+ (objfiles_range (objfiles_iterator (m_objfiles_list.begin ()),
+ objfiles_iterator (m_objfiles_list.end ())));
}
- /* Add OBJFILE to the list of objfiles, putting it just before
- BEFORE. If BEFORE is nullptr, it will go at the end of the
+ /* Add OBJFILE to the list of objfiles, putting it just after
+ AFTER. If AFTER is nullptr, it will go at the end of the
list. */
void add_objfile (std::unique_ptr<objfile> &&objfile,
- struct objfile *before);
+ struct objfile *after);
/* Remove OBJFILE from the list of objfiles. */
void remove_objfile (struct objfile *objfile);
@@ -227,6 +234,11 @@ struct program_space
/* Free all the objfiles associated with this program space. */
void free_all_objfiles ();
+ /* Remove all objfiles associated with this program space for which
+ PREDICATE evaluates to true. */
+ void remove_objfiles_if
+ (gdb::function_view<bool (const objfile *objfile)> predicate);
+
/* Return the objfile containing ADDRESS, or nullptr if the address
is outside all objfiles in this progspace. */
struct objfile *objfile_for_address (CORE_ADDR address);
@@ -84,7 +84,7 @@ objfile::has_partial_symbols ()
them, then that is an indication that they are in fact available. Without
this function the symbols may have been already read in but they also may
not be present in this objfile. */
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
retval = iter->has_symbols (this);
if (retval)
@@ -107,7 +107,7 @@ objfile::has_unexpanded_symtabs ()
objfile_debug_name (this));
bool result = false;
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
if (iter->has_unexpanded_symtabs (this))
{
@@ -132,7 +132,7 @@ objfile::find_last_source_symtab ()
gdb_printf (gdb_stdlog, "qf->find_last_source_symtab (%s)\n",
objfile_debug_name (this));
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
retval = iter->find_last_source_symtab (this);
if (retval != nullptr)
@@ -156,7 +156,7 @@ objfile::forget_cached_source_info ()
for (compunit_symtab *cu : compunits ())
cu->forget_cached_source_info ();
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->forget_cached_source_info (this);
}
@@ -203,7 +203,7 @@ objfile::map_symtabs_matching_filename
return result;
};
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
if (!iter->expand_symtabs_matching (this,
match_one_filename,
@@ -266,7 +266,7 @@ objfile::lookup_symbol (block_enum kind, const lookup_name_info &name,
return true;
};
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
if (!iter->expand_symtabs_matching (this,
nullptr,
@@ -296,7 +296,7 @@ objfile::print_stats (bool print_bcache)
gdb_printf (gdb_stdlog, "qf->print_stats (%s, %d)\n",
objfile_debug_name (this), print_bcache);
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->print_stats (this, print_bcache);
}
@@ -307,7 +307,7 @@ objfile::dump ()
gdb_printf (gdb_stdlog, "qf->dump (%s)\n",
objfile_debug_name (this));
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->dump (this);
}
@@ -322,7 +322,7 @@ objfile::expand_symtabs_for_function (const char *func_name)
lookup_name_info base_lookup (func_name, symbol_name_match_type::FULL);
lookup_name_info lookup_name = base_lookup.make_ignore_params ();
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->expand_symtabs_matching (this,
nullptr,
&lookup_name,
@@ -340,7 +340,7 @@ objfile::expand_all_symtabs ()
gdb_printf (gdb_stdlog, "qf->expand_all_symtabs (%s)\n",
objfile_debug_name (this));
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->expand_all_symtabs (this);
}
@@ -358,7 +358,7 @@ objfile::expand_symtabs_with_fullname (const char *fullname)
return filename_cmp (basenames ? basename : fullname, filename) == 0;
};
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->expand_symtabs_matching (this,
file_matcher,
nullptr,
@@ -391,7 +391,7 @@ objfile::expand_symtabs_matching
host_address_to_string (&expansion_notify),
domain_name (domain).c_str ());
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
if (!iter->expand_symtabs_matching (this, file_matcher, lookup_name,
symbol_matcher, expansion_notify,
search_flags, domain,
@@ -417,7 +417,7 @@ objfile::find_pc_sect_compunit_symtab (bound_minimal_symbol msymbol,
host_address_to_string (section),
warn_if_readin);
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
retval = iter->find_pc_sect_compunit_symtab (this, msymbol, pc, section,
warn_if_readin);
@@ -445,7 +445,7 @@ objfile::map_symbol_filenames (gdb::function_view<symbol_filename_ftype> fun,
objfile_debug_name (this),
need_fullname);
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->map_symbol_filenames (this, fun, need_fullname);
}
@@ -457,7 +457,7 @@ objfile::compute_main_name ()
"qf->compute_main_name (%s)\n",
objfile_debug_name (this));
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
iter->compute_main_name (this);
}
@@ -471,7 +471,7 @@ objfile::find_compunit_symtab_by_address (CORE_ADDR address)
hex_string (address));
struct compunit_symtab *result = NULL;
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
result = iter->find_compunit_symtab_by_address (this, address);
if (result != nullptr)
@@ -496,7 +496,7 @@ objfile::lookup_global_symbol_language (const char *name,
enum language result = language_unknown;
*symbol_found_p = false;
- for (const auto &iter : qf)
+ for (const auto &iter : qf_safe ())
{
result = iter->lookup_global_symbol_language (this, name, domain,
symbol_found_p);
@@ -135,7 +135,7 @@ gdb_test "p main" "= {<text variable, no debug info>} $hex <main>" \
gdb_py_test_silent_cmd "python objfile.add_separate_debug_file(\"${binfile}\")" \
"Add separate debug file file" 1
-gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[0\]" \
+gdb_py_test_silent_cmd "python sep_objfile = gdb.objfiles()\[1\]" \
"Get separate debug info objfile" 1
gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \
@@ -136,4 +136,122 @@ class basic_safe_range
Range m_range;
};
+/* A reverse basic_safe_iterator. See basic_safe_iterator for intended use. */
+
+template<typename Iterator>
+class basic_safe_reverse_iterator
+{
+public:
+ typedef basic_safe_reverse_iterator self_type;
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::reference reference;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::iterator_category iterator_category;
+ typedef typename Iterator::difference_type difference_type;
+
+ /* Construct the iterator using ARG, and construct the end iterator
+ using ARG2. ARG and ARG2 should be forward iterators, typically
+ from begin and end methods, respectively.
+
+ For example if ARG1 is created with container.begin and ARG2 is
+ is created with container.end, then the basic_safe_reverse_iterator
+ will traverse from the last element in the container to the first
+ element in the container. */
+ template<typename Arg>
+ explicit basic_safe_reverse_iterator (Arg &&arg, Arg &&arg2)
+ : m_begin (std::forward<Arg> (arg)),
+ m_end (std::forward<Arg> (arg2)),
+ m_it (m_begin),
+ m_next (m_end)
+ {
+ /* M_IT and M_NEXT are initialized as one-past-end. Set M_IT to point
+ to the last element and set M_NEXT to point to the second last element,
+ if such elements exist. */
+ if (m_begin != m_end)
+ {
+ /* Set M_IT to the last element in the list. */
+ for (auto it = std::next (m_begin); it != m_end; ++it)
+ ++m_it;
+
+ /* Set M_NEXT to the element before M_IT, if one exists. */
+ if (m_it != m_begin)
+ {
+ m_next = m_it;
+ --m_next;
+ }
+ }
+ }
+
+ typename std::invoke_result<decltype(&Iterator::operator*), Iterator>::type
+ operator* () const
+ { return *m_it; }
+
+ self_type &operator++ ()
+ {
+ m_it = m_next;
+
+ if (m_it != m_end)
+ {
+ /* Use M_BEGIN only if we sure that it is valid. */
+ if (m_it == m_begin)
+ m_next = m_end;
+ else
+ --m_next;
+ }
+
+ return *this;
+ }
+
+ bool operator== (const self_type &other) const
+ { return m_it == other.m_it; }
+
+ bool operator!= (const self_type &other) const
+ { return m_it != other.m_it; }
+
+private:
+ /* The first element. */
+ Iterator m_begin {};
+
+ /* A one-past-end iterator. */
+ Iterator m_end {};
+
+ /* The current element. */
+ Iterator m_it {};
+
+ /* The next element. Always one element ahead of M_IT. */
+ Iterator m_next {};
+};
+
+/* A range adapter that wraps a forward range, and then returns
+ safe reverse iterators wrapping the original range's iterators. */
+
+template<typename Range>
+class basic_safe_reverse_range
+{
+public:
+
+ typedef basic_safe_reverse_iterator<typename Range::iterator> iterator;
+
+ /* RANGE must be a forward range. basic_safe_reverse_iterators
+ will be used to traverse the forward range from the last element
+ to the first. */
+ explicit basic_safe_reverse_range (Range range)
+ : m_range (range)
+ {
+ }
+
+ iterator begin ()
+ {
+ return iterator (m_range.begin (), m_range.end ());
+ }
+
+ iterator end ()
+ {
+ return iterator (m_range.end (), m_range.end ());
+ }
+
+private:
+
+ Range m_range;
+};
#endif /* COMMON_SAFE_ITERATOR_H */