the error and the condition string will be rejected.
This two-pass approach is taken to avoid setting the
state of locations in case of a reject. */
- for (bp_location *loc : b->locations ())
+ for (const bp_location *loc : b->locations ())
{
try
{
/* Condition string is invalid. If this happens to
be the last loc, abandon (if not forced) or continue
(if forced). */
- if (loc->next == nullptr && !force)
+ if (loc == &b->last_loc () && !force)
throw;
}
}
{
gdb_assert (!b->has_locations ());
- b->loc = new bp_location (b, bp_loc_other);
- b->loc->pspace = pspace;
+ bp_location *loc = new bp_location (b, bp_loc_other);
+ loc->pspace = pspace;
+ b->add_location (*loc);
}
/* Assuming that B is a watchpoint:
/* We don't free locations. They are stored in the bp_location array
and update_global_location_list will eventually delete them and
remove breakpoints if needed. */
- b->loc = NULL;
+ b->clear_locations ();
if (within_current_scope && reparse)
{
{
CORE_ADDR addr;
enum target_hw_bp_type type;
- struct bp_location *loc, **tmp;
int bitpos = 0, bitsize = 0;
if (v->bitsize () != 0)
else if (b->type == bp_access_watchpoint)
type = hw_access;
- loc = b->allocate_location ();
- for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
- ;
- *tmp = loc;
+ bp_location *loc = b->allocate_location ();
loc->gdbarch = v->type ()->arch ();
-
loc->pspace = frame_pspace;
loc->address
= gdbarch_remove_non_address_bits (loc->gdbarch, addr);
+ b->add_location (*loc);
if (bitsize != 0)
{
/* Breakpoints set through other program spaces could have locations
bound to PSPACE as well. Remove those. */
for (bp_location *loc : all_bp_locations ())
- {
- struct bp_location *tmp;
-
- if (loc->pspace == pspace)
- {
- /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
- if (loc->owner->loc == loc)
- loc->owner->loc = loc->next;
- else
- for (tmp = loc->owner->loc; tmp->next != NULL; tmp = tmp->next)
- if (tmp->next == loc)
- {
- tmp->next = loc->next;
- break;
- }
- }
- }
+ if (loc->pspace == pspace)
+ {
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
+ loc->owner->unadd_location (*loc);
+ }
/* Now update the global location list to permanently delete the
removed locations above. */
update_watchpoint, when the inferior is restarted.
The next update_global_location_list call will
garbage collect them. */
- b->loc = NULL;
+ b->clear_locations ();
if (context == inf_starting)
{
const struct breakpoint *b = bs->breakpoint_at;
const struct bp_location *bl = bs->bp_location_at.get ();
- int locno = 0;
-
if (b != nullptr && b->has_multiple_locations ())
{
- const bp_location *bl_i;
-
- for (bl_i = b->loc;
- bl_i != bl && bl_i->next != nullptr;
- bl_i = bl_i->next)
- locno++;
+ int locno = 1;
- if (bl_i == bl)
- locno++;
- else
+ for (bp_location *loc : b->locations ())
{
- warning (_("location number not found for breakpoint %d address %s."),
- b->number, paddress (bl->gdbarch, bl->address));
- locno = 0;
+ if (bl == loc)
+ return locno;
+
+ ++locno;
}
+
+ warning (_("location number not found for breakpoint %d address %s."),
+ b->number, paddress (bl->gdbarch, bl->address));
}
- return locno;
+ return 0;
}
/* See breakpoint.h. */
(new_momentary_breakpoint (orig->gdbarch, type, orig->pspace,
orig->frame_id, thread));
const bp_location &orig_loc = orig->first_loc ();
- copy->loc = copy->allocate_location ();
- set_breakpoint_location_function (copy->loc);
-
- copy->loc->gdbarch = orig_loc.gdbarch;
- copy->loc->requested_address = orig_loc.requested_address;
- copy->loc->address = orig_loc.address;
- copy->loc->section = orig_loc.section;
- copy->loc->pspace = orig_loc.pspace;
- copy->loc->probe = orig_loc.probe;
- copy->loc->line_number = orig_loc.line_number;
- copy->loc->symtab = orig_loc.symtab;
- copy->loc->enabled = loc_enabled;
+ bp_location *copy_loc = copy->allocate_location ();
+ copy->add_location (*copy_loc);
+ set_breakpoint_location_function (copy_loc);
+
+ copy_loc->gdbarch = orig_loc.gdbarch;
+ copy_loc->requested_address = orig_loc.requested_address;
+ copy_loc->address = orig_loc.address;
+ copy_loc->section = orig_loc.section;
+ copy_loc->pspace = orig_loc.pspace;
+ copy_loc->probe = orig_loc.probe;
+ copy_loc->line_number = orig_loc.line_number;
+ copy_loc->symtab = orig_loc.symtab;
+ copy_loc->enabled = loc_enabled;
breakpoint *b = add_to_breakpoint_chain (std::move (copy));
update_global_location_list_nothrow (UGLL_DONT_INSERT);
bp_location *
code_breakpoint::add_location (const symtab_and_line &sal)
{
- struct bp_location *new_loc, **tmp;
CORE_ADDR adjusted_address;
struct gdbarch *loc_gdbarch = get_sal_arch (sal);
sal.pspace);
/* Sort the locations by their ADDRESS. */
- new_loc = allocate_location ();
- for (tmp = &(loc); *tmp != NULL && (*tmp)->address <= adjusted_address;
- tmp = &((*tmp)->next))
- ;
- new_loc->next = *tmp;
- *tmp = new_loc;
+ bp_location *new_loc = this->allocate_location ();
new_loc->requested_address = sal.pc;
new_loc->address = adjusted_address;
new_loc->msymbol = sal.msymbol;
new_loc->objfile = sal.objfile;
+ breakpoint::add_location (*new_loc);
+
set_breakpoint_location_function (new_loc);
/* While by definition, permanent breakpoints are already present in the
if (this->has_multiple_locations ())
{
- struct bp_location *iter = loc;
- int n = 0;
- for (; iter; iter = iter->next)
- ++n;
+ int n = std::distance (m_locations.begin (), m_locations.end ());
gdb_printf (" (%d locations)", n);
}
}
bp_location_range breakpoint::locations () const
{
- return bp_location_range (this->loc);
+ return bp_location_range
+ (bp_location_pointer_iterator (m_locations.begin ()),
+ bp_location_pointer_iterator (m_locations.end ()));
}
struct bp_location *
return new bp_location (this);
}
+/* See breakpoint.h. */
+
+void
+breakpoint::add_location (bp_location &loc)
+{
+ gdb_assert (loc.owner == this);
+ gdb_assert (!loc.is_linked ());
+
+ auto ub = std::upper_bound (m_locations.begin (), m_locations.end (),
+ loc,
+ [] (const bp_location &left,
+ const bp_location &right)
+ { return left.address < right.address; });
+ m_locations.insert (ub, loc);
+}
+
+/* See breakpoint.h. */
+
+void
+breakpoint::unadd_location (bp_location &loc)
+{
+ gdb_assert (loc.owner == this);
+ gdb_assert (loc.is_linked ());
+
+ m_locations.erase (m_locations.iterator_to (loc));
+}
+
#define internal_error_pure_virtual_called() \
gdb_assert_not_reached ("pure virtual function called")
belong to this breakpoint. Do this before freeing the breakpoint
itself, since remove_breakpoint looks at location's owner. It
might be better design to have location completely
- self-contained, but it's not the case now. */
+ self-contained, but it's not the case now.
+
+ Clear the location linked list first, otherwise, the intrusive_list
+ destructor accesses the locations after they are freed. */
+ bpt->clear_locations ();
update_global_location_list (UGLL_DONT_INSERT);
/* On the chance that someone will soon try again to delete this
}
/* Subroutine of update_breakpoint_locations to simplify it.
- Return true if multiple fns in list LOC have the same name.
+ Return true if multiple fns in list LOCS have the same name.
Null names are ignored. */
static bool
-ambiguous_names_p (struct bp_location *loc)
+ambiguous_names_p (const bp_location_range &locs)
{
- struct bp_location *l;
htab_up htab (htab_create_alloc (13, htab_hash_string, htab_eq_string, NULL,
xcalloc, xfree));
- for (l = loc; l != NULL; l = l->next)
+ for (const bp_location *l : locs)
{
const char **slot;
const char *name = l->function_name.get ();
return sal;
}
-/* Returns true iff locations A and B are sufficiently same that
+/* Returns true iff location lists A and B are sufficiently same that
we don't need to report breakpoint as changed. */
static bool
-locations_are_equal (struct bp_location *a, struct bp_location *b)
+locations_are_equal (const bp_location_list &a, const bp_location_range &b)
{
- while (a && b)
+ auto a_iter = a.begin ();
+ auto b_iter = b.begin ();
+
+ for (; a_iter != a.end () && b_iter != b.end (); ++a_iter, ++b_iter)
{
- if (a->address != b->address)
+ if (a_iter->address != (*b_iter)->address)
return false;
- if (a->shlib_disabled != b->shlib_disabled)
+ if (a_iter->shlib_disabled != (*b_iter)->shlib_disabled)
return false;
- if (a->enabled != b->enabled)
+ if (a_iter->enabled != (*b_iter)->enabled)
return false;
- if (a->disabled_by_cond != b->disabled_by_cond)
+ if (a_iter->disabled_by_cond != (*b_iter)->disabled_by_cond)
return false;
-
- a = a->next;
- b = b->next;
}
- if ((a == NULL) != (b == NULL))
- return false;
-
- return true;
+ return (a_iter == a.end ()) == (b_iter == b.end ());
}
-/* Split all locations of B that are bound to PSPACE out of B's
- location list to a separate list and return that list's head. If
- PSPACE is NULL, hoist out all locations of B. */
+/* See breakpoint.h. */
-static struct bp_location *
-hoist_existing_locations (struct breakpoint *b, struct program_space *pspace)
+bp_location_list
+breakpoint::steal_locations (program_space *pspace)
{
- struct bp_location head;
- struct bp_location *i = b->loc;
- struct bp_location **i_link = &b->loc;
- struct bp_location *hoisted = &head;
-
if (pspace == NULL)
- {
- i = b->loc;
- b->loc = NULL;
- return i;
- }
+ return std::move (m_locations);
- head.next = NULL;
+ bp_location_list ret;
- while (i != NULL)
+ for (auto it = m_locations.begin (); it != m_locations.end (); )
{
- if (i->pspace == pspace)
+ if (it->pspace == pspace)
{
- *i_link = i->next;
- i->next = NULL;
- hoisted->next = i;
- hoisted = i;
+ bp_location &loc = *it;
+ it = m_locations.erase (it);
+ ret.push_back (loc);
}
else
- i_link = &i->next;
- i = *i_link;
+ ++it;
}
- return head.next;
+ return ret;
}
/* Create new breakpoint locations for B (a hardware or software
gdb::array_view<const symtab_and_line> sals,
gdb::array_view<const symtab_and_line> sals_end)
{
- struct bp_location *existing_locations;
-
if (!sals_end.empty () && (sals.size () != 1 || sals_end.size () != 1))
{
/* Ranged breakpoints have only one start location and one end
if (all_locations_are_pending (b, filter_pspace) && sals.empty ())
return;
- existing_locations = hoist_existing_locations (b, filter_pspace);
+ bp_location_list existing_locations = b->steal_locations (filter_pspace);
for (const auto &sal : sals)
{
/* If possible, carry over 'disable' status from existing
breakpoints. */
{
- struct bp_location *e = existing_locations;
/* If there are multiple breakpoints with the same function name,
e.g. for inline functions, comparing function names won't work.
Instead compare pc addresses; this is just a heuristic as things
may have moved, but in practice it gives the correct answer
often enough until a better solution is found. */
- int have_ambiguous_names = ambiguous_names_p (b->loc);
+ int have_ambiguous_names = ambiguous_names_p (b->locations ());
- for (; e; e = e->next)
+ for (const bp_location &e : existing_locations)
{
- if ((!e->enabled || e->disabled_by_cond) && e->function_name)
+ if ((!e.enabled || e.disabled_by_cond) && e.function_name)
{
if (have_ambiguous_names)
{
As mentioned above, this is an heuristic and in
practice should give the correct answer often
enough. */
- if (breakpoint_locations_match (e, l, true))
+ if (breakpoint_locations_match (&e, l, true))
{
- l->enabled = e->enabled;
- l->disabled_by_cond = e->disabled_by_cond;
+ l->enabled = e.enabled;
+ l->disabled_by_cond = e.disabled_by_cond;
break;
}
}
{
for (bp_location *l : b->locations ())
if (l->function_name
- && strcmp (e->function_name.get (),
+ && strcmp (e.function_name.get (),
l->function_name.get ()) == 0)
{
- l->enabled = e->enabled;
- l->disabled_by_cond = e->disabled_by_cond;
+ l->enabled = e.enabled;
+ l->disabled_by_cond = e.disabled_by_cond;
break;
}
}
}
}
- if (!locations_are_equal (existing_locations, b->loc))
+ if (!locations_are_equal (existing_locations, b->locations ()))
gdb::observers::breakpoint_modified.notify (b);
}
#include "gdbsupport/next-iterator.h"
#include "gdbsupport/iterator-range.h"
#include "gdbsupport/refcounted-object.h"
+#include "gdbsupport/reference-to-pointer-iterator.h"
#include "gdbsupport/safe-iterator.h"
#include "cli/cli-script.h"
#include "target/waitstatus.h"
bp_loc_other /* Miscellaneous... */
};
-class bp_location : public refcounted_object
+class bp_location : public refcounted_object, public intrusive_list_node<bp_location>
{
public:
- bp_location () = default;
-
/* Construct a bp_location with the type inferred from OWNER's
type. */
explicit bp_location (breakpoint *owner);
virtual ~bp_location () = default;
- /* Chain pointer to the next breakpoint location for
- the same parent breakpoint. */
- bp_location *next = NULL;
-
/* Type of this breakpoint location. */
bp_loc_type loc_type {};
extern bool target_exact_watchpoints;
-/* bp_location linked list range. */
-
-using bp_location_range = next_range<bp_location>;
+using bp_location_list = intrusive_list<bp_location>;
+using bp_location_iterator = bp_location_list::iterator;
+using bp_location_pointer_iterator
+ = reference_to_pointer_iterator<bp_location_iterator>;
+using bp_location_range = iterator_range<bp_location_pointer_iterator>;
/* Note that the ->silent field is not currently used by any commands
(though the code is in there if it was to be, and set_raw_breakpoint
/* Allocate a location for this breakpoint. */
virtual struct bp_location *allocate_location ();
+ /* Return a range of this breakpoint's locations. */
+ bp_location_range locations () const;
+
+ /* Add LOC to the location list of this breakpoint, sorted by address
+ (using LOC.ADDRESS).
+
+ LOC must have this breakpoint as its owner. LOC must not already be linked
+ in a location list. */
+ void add_location (bp_location &loc);
+
+ /* Remove LOC from this breakpoint's location list. The name is a bit funny
+ because remove_location is already taken, and means something else.
+
+ LOC must be have this breakpoints as its owner. LOC must be linked in this
+ breakpoint's location list. */
+ void unadd_location (bp_location &loc);
+
+ /* Clear the location list of this breakpoint. */
+ void clear_locations ()
+ { m_locations.clear (); }
+
+ /* Split all locations of this breakpoint that are bound to PSPACE out of its
+ location list to a separate list and return that list. If
+ PSPACE is nullptr, hoist out all locations. */
+ bp_location_list steal_locations (program_space *pspace);
+
/* Return true if this breakpoint has a least one location. */
bool has_locations () const
- { return this->loc != nullptr; }
+ { return !m_locations.empty (); }
/* Return true if this breakpoint has a single location. */
bool has_single_location () const
- { return this->loc != nullptr && this->loc->next == nullptr; }
+ {
+ if (!this->has_locations ())
+ return false;
+
+ return std::next (m_locations.begin ()) == m_locations.end ();
+ }
/* Return true if this breakpoint has multiple locations. */
bool has_multiple_locations () const
- { return this->loc != nullptr && this->loc->next != nullptr; }
+ {
+ if (!this->has_locations ())
+ return false;
+
+ return std::next (m_locations.begin ()) != m_locations.end ();
+ }
/* Return a reference to the first location of this breakpoint. */
bp_location &first_loc ()
{
gdb_assert (this->has_locations ());
- return *this->loc;
+ return m_locations.front ();
}
/* Return a reference to the first location of this breakpoint. */
const bp_location &first_loc () const
{
gdb_assert (this->has_locations ());
- return *this->loc;
+ return m_locations.front ();
+ }
+
+ /* Return a reference to the last location of this breakpoint. */
+ const bp_location &last_loc () const
+ {
+ gdb_assert (this->has_locations ());
+ return m_locations.back ();
}
/* Reevaluate a breakpoint. This is necessary after symbols change
/* Nothing to do. */
}
- /* Return a range of this breakpoint's locations. */
- bp_location_range locations () const;
-
breakpoint *next = NULL;
/* Type of breakpoint. */
bptype type = bp_none;
/* Number assigned to distinguish breakpoints. */
int number = 0;
- /* Location(s) associated with this high-level breakpoint. */
- bp_location *loc = NULL;
-
/* True means a silent breakpoint (don't print frame info if we stop
here). */
bool silent = false;
thread 1", which needs outputting before any breakpoint-type
specific extra command necessary for B's recreation. */
void print_recreate_thread (struct ui_file *fp) const;
+
+ /* Location(s) associated with this high-level breakpoint. */
+ bp_location_list m_locations;
};
/* Abstract base class representing code breakpoints. User "break"