static int breakpoint_1 (int, int, int (*) (const struct breakpoint *));
-static bpstat bpstat_alloc (const struct bp_location *, bpstat);
-
static int breakpoint_cond_eval (void *);
static void cleanup_executing_breakpoints (void *);
CORE_ADDR pc);
static void free_bp_location (struct bp_location *loc);
+static void incref_bp_location (struct bp_location *loc);
+static void decref_bp_location (struct bp_location **loc);
static struct bp_location *allocate_bp_location (struct breakpoint *bpt);
static void update_global_location_list_nothrow (int);
-static int bpstat_remove_bp_location_callback (struct thread_info *th,
- void *data);
-
static int is_hardware_watchpoint (const struct breakpoint *bpt);
static int is_watchpoint (const struct breakpoint *bpt);
if (within_current_scope && reparse)
{
char *s;
+
if (b->exp)
{
xfree (b->exp);
b->exp = NULL;
}
- s = b->exp_string;
+ s = b->exp_string_reparse ? b->exp_string_reparse : b->exp_string;
b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
/* If the meaning of expression itself changed, the old value is
no longer relevant. We don't want to report a watchpoint hit
/* Get rid of the moribund locations. */
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, bpt); ++ix)
- free_bp_location (bpt);
+ decref_bp_location (&bpt);
VEC_free (bp_location_p, moribund_locations);
}
return (ep->type == bp_catchpoint);
}
-void
+/* Frees any storage that is part of a bpstat. Does not walk the
+ 'next' chain. */
+
+static void
bpstat_free (bpstat bs)
{
if (bs->old_val != NULL)
value_free (bs->old_val);
decref_counted_command_line (&bs->commands);
+ decref_bp_location (&bs->bp_location_at);
xfree (bs);
}
tmp = (bpstat) xmalloc (sizeof (*tmp));
memcpy (tmp, bs, sizeof (*tmp));
incref_counted_command_line (tmp->commands);
+ incref_bp_location (tmp->bp_location_at);
if (bs->old_val != NULL)
{
tmp->old_val = value_copy (bs->old_val);
for (; bsp != NULL; bsp = bsp->next)
{
- if (bsp->breakpoint_at && bsp->breakpoint_at->owner == breakpoint)
+ if (bsp->breakpoint_at == breakpoint)
return bsp;
}
return NULL;
correspond to a single breakpoint -- otherwise,
this function might return the same number more
than once and this will look ugly. */
- b = (*bsp)->breakpoint_at ? (*bsp)->breakpoint_at->owner : NULL;
+ b = (*bsp)->breakpoint_at;
*bsp = (*bsp)->next;
if (b == NULL)
return -1; /* breakpoint that's been deleted since */
which has since been deleted. */
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
- bl = bs->breakpoint_at;
- /* bl->owner can be NULL if it was a momentary breakpoint
- which has since been placed into moribund_locations. */
- if (bl->owner == NULL)
- return PRINT_UNKNOWN;
- b = bl->owner;
+ gdb_assert (bs->bp_location_at != NULL);
+
+ bl = bs->bp_location_at;
+ b = bs->breakpoint_at;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
{
case bp_breakpoint:
case bp_hardware_breakpoint:
- bp_temp = bs->breakpoint_at->owner->disposition == disp_del;
+ bp_temp = b->disposition == disp_del;
if (bl->address != bl->requested_address)
breakpoint_adjustment_warning (bl->requested_address,
bl->address,
case print_it_normal:
{
- const struct bp_location *bl = bs->breakpoint_at;
- struct breakpoint *b = bl ? bl->owner : NULL;
-
+ struct breakpoint *b = bs->breakpoint_at;
+
/* Normal case. Call the breakpoint's print_it method, or
print_it_typical. */
/* FIXME: how breakpoint can ever be NULL here? */
return i;
}
-/* Allocate a new bpstat and chain it to the current one. */
+/* Allocate a new bpstat. Link it to the FIFO list by BS_LINK_POINTER. */
static bpstat
-bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
+bpstat_alloc (struct bp_location *bl, bpstat **bs_link_pointer)
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
- cbs->next = bs;
- bs->breakpoint_at = bl;
+ bs->next = NULL;
+ **bs_link_pointer = bs;
+ *bs_link_pointer = &bs->next;
+ bs->breakpoint_at = bl->owner;
+ bs->bp_location_at = bl;
+ incref_bp_location (bl);
/* If the condition is false, etc., don't do the commands. */
bs->commands = NULL;
bs->commands_left = NULL;
struct frame_info *fr;
int within_current_scope;
- /* BS is built for existing struct breakpoint. */
+ /* BS is built from an existing struct breakpoint. */
gdb_assert (bs->breakpoint_at != NULL);
- gdb_assert (bs->breakpoint_at->owner != NULL);
- b = bs->breakpoint_at->owner;
+ b = bs->breakpoint_at;
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
struct breakpoint *b;
/* BS is built for existing struct breakpoint. */
- bl = bs->breakpoint_at;
+ bl = bs->bp_location_at;
gdb_assert (bl != NULL);
- b = bl->owner;
+ b = bs->breakpoint_at;
gdb_assert (b != NULL);
if (is_watchpoint (b))
/* Check conditions (condition proper, frame, thread and ignore count)
of breakpoint referred to by BS. If we should not stop for this
breakpoint, set BS->stop to 0. */
+
static void
bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
{
struct breakpoint *b;
/* BS is built for existing struct breakpoint. */
- bl = bs->breakpoint_at;
+ bl = bs->bp_location_at;
gdb_assert (bl != NULL);
- b = bl->owner;
+ b = bs->breakpoint_at;
gdb_assert (b != NULL);
if (frame_id_p (b->frame_id)
int value_is_zero = 0;
struct expression *cond;
- /* If this is a scope breakpoint, mark the associated
- watchpoint as triggered so that we will handle the
- out-of-scope event. We'll get to the watchpoint next
- iteration. */
- if (b->type == bp_watchpoint_scope)
- b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
-
if (is_watchpoint (b))
cond = b->cond_exp;
else
cond = bl->cond;
- if (cond && bl->owner->disposition != disp_del_at_next_stop)
+ if (cond && b->disposition != disp_del_at_next_stop)
{
int within_current_scope = 1;
struct breakpoint *b = NULL;
struct bp_location *bl;
struct bp_location *loc;
- /* Root of the chain of bpstat's */
- struct bpstats root_bs[1];
+ /* First item of allocated bpstat's. */
+ bpstat bs_head = NULL, *bs_link = &bs_head;
/* Pointer to the last thing in the chain currently. */
- bpstat bs = root_bs;
+ bpstat bs;
int ix;
int need_remove_insert;
+ int removed_any;
- /* ALL_BP_LOCATIONS iteration would break across
- update_global_location_list possibly executed by
- bpstat_check_breakpoint_conditions's inferior call. */
+ /* First, build the bpstat chain with locations that explain a
+ target stop, while being careful to not set the target running,
+ as that may invalidate locations (in particular watchpoint
+ locations are recreated). Resuming will happen here with
+ breakpoint conditions or watchpoint expressions that include
+ inferior function calls. */
ALL_BREAKPOINTS (b)
{
/* Come here if it's a watchpoint, or if the break address matches */
- bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
+ bs = bpstat_alloc (bl, &bs_link); /* Alloc a bpstat to explain stop */
- /* Assume we stop. Should we find watchpoint that is not actually
- triggered, or if condition of breakpoint is false, we'll reset
- 'stop' to 0. */
+ /* Assume we stop. Should we find a watchpoint that is not
+ actually triggered, or if the condition of the breakpoint
+ evaluates as false, we'll reset 'stop' to 0. */
bs->stop = 1;
bs->print = 1;
- bpstat_check_watchpoint (bs);
- if (!bs->stop)
- continue;
+ /* If this is a scope breakpoint, mark the associated
+ watchpoint as triggered so that we will handle the
+ out-of-scope event. We'll get to the watchpoint next
+ iteration. */
+ if (b->type == bp_watchpoint_scope)
+ b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
+ }
+ }
+
+ for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
+ {
+ if (breakpoint_address_match (loc->pspace->aspace, loc->address,
+ aspace, bp_addr))
+ {
+ bs = bpstat_alloc (loc, &bs_link);
+ /* For hits of moribund locations, we should just proceed. */
+ bs->stop = 0;
+ bs->print = 0;
+ bs->print_it = print_it_noop;
+ }
+ }
+
+ /* Now go through the locations that caused the target to stop, and
+ check whether we're interested in reporting this stop to higher
+ layers, or whether we should resume the target transparently. */
+
+ removed_any = 0;
+
+ for (bs = bs_head; bs != NULL; bs = bs->next)
+ {
+ if (!bs->stop)
+ continue;
+
+ bpstat_check_watchpoint (bs);
+ if (!bs->stop)
+ continue;
+
+ b = bs->breakpoint_at;
if (b->type == bp_thread_event || b->type == bp_overlay_event
|| b->type == bp_longjmp_master
bs->stop = 0;
else
bpstat_check_breakpoint_conditions (bs, ptid);
-
+
if (bs->stop)
{
++(b->hit_count);
{
if (b->enable_state != bp_permanent)
b->enable_state = bp_disabled;
- update_global_location_list (0);
+ removed_any = 1;
}
if (b->silent)
bs->print = 0;
/* Print nothing for this entry if we dont stop or dont print. */
if (bs->stop == 0 || bs->print == 0)
bs->print_it = print_it_noop;
- }
}
- for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
- {
- if (breakpoint_address_match (loc->pspace->aspace, loc->address,
- aspace, bp_addr))
- {
- bs = bpstat_alloc (loc, bs);
- /* For hits of moribund locations, we should just proceed. */
- bs->stop = 0;
- bs->print = 0;
- bs->print_it = print_it_noop;
- }
- }
-
- bs->next = NULL; /* Terminate the chain */
-
/* If we aren't stopping, the value of some hardware watchpoint may
not have changed, but the intermediate memory locations we are
watching may have. Don't bother if we're stopping; this will get
done later. */
need_remove_insert = 0;
- if (! bpstat_causes_stop (root_bs->next))
- for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (! bpstat_causes_stop (bs_head))
+ for (bs = bs_head; bs != NULL; bs = bs->next)
if (!bs->stop
- && bs->breakpoint_at->owner
- && is_hardware_watchpoint (bs->breakpoint_at->owner))
+ && bs->breakpoint_at
+ && is_hardware_watchpoint (bs->breakpoint_at))
{
- update_watchpoint (bs->breakpoint_at->owner, 0 /* don't reparse. */);
- /* Updating watchpoints invalidates bs->breakpoint_at.
- Prevent further code from trying to use it. */
- bs->breakpoint_at = NULL;
+ update_watchpoint (bs->breakpoint_at, 0 /* don't reparse. */);
need_remove_insert = 1;
}
if (need_remove_insert)
update_global_location_list (1);
+ else if (removed_any)
+ update_global_location_list (0);
- return root_bs->next;
+ return bs_head;
}
static void
breakpoint which has since been deleted. */
bptype = bp_none;
}
- else if (bs->breakpoint_at->owner == NULL)
+ else if (bs->breakpoint_at == NULL)
bptype = bp_none;
else
- bptype = bs->breakpoint_at->owner->type;
+ bptype = bs->breakpoint_at->type;
switch (bptype)
{
internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
}
+ loc->refc = 1;
return loc;
}
-static void free_bp_location (struct bp_location *loc)
+static void
+free_bp_location (struct bp_location *loc)
{
- /* Be sure no bpstat's are pointing at it after it's been freed. */
- /* FIXME, how can we find all bpstat's?
- We just check stop_bpstat for now. Note that we cannot just
- remove bpstats pointing at bpt from the stop_bpstat list
- entirely, as breakpoint commands are associated with the bpstat;
- if we remove it here, then the later call to
- bpstat_do_actions (&stop_bpstat);
- in event-top.c won't do anything, and temporary breakpoints
- with commands won't work. */
-
- iterate_over_threads (bpstat_remove_bp_location_callback, loc);
-
if (loc->cond)
xfree (loc->cond);
if (loc->function_name)
xfree (loc->function_name);
-
+
xfree (loc);
}
+/* Increment reference count. */
+
+static void
+incref_bp_location (struct bp_location *bl)
+{
+ ++bl->refc;
+}
+
+/* Decrement reference count. If the reference count reaches 0,
+ destroy the bp_location. Sets *BLP to NULL. */
+
+static void
+decref_bp_location (struct bp_location **blp)
+{
+ gdb_assert ((*blp)->refc > 0);
+
+ if (--(*blp)->refc == 0)
+ free_bp_location (*blp);
+ *blp = NULL;
+}
+
/* Helper to set_raw_breakpoint below. Creates a breakpoint
that has type BPTYPE and has no locations as yet. */
/* This function is used in gdbtk sources and thus can not be made static. */
/* If pending breakpoint support is auto query and the user
selects no, then simply return the error code. */
if (pending_break_support == AUTO_BOOLEAN_AUTO
- && !nquery ("Make breakpoint pending on future shared library load? "))
+ && !nquery (_("Make breakpoint pending on future shared library load? ")))
return 0;
/* At this point, either the user was queried about setting
t = check_typedef (TYPE_TARGET_TYPE (check_typedef (t)));
name = type_to_string (t);
- b->exp_string = xstrprintf ("* (%s *) %s", name,
- core_addr_to_string (addr));
+ b->exp_string_reparse = xstrprintf ("* (%s *) %s", name,
+ core_addr_to_string (addr));
xfree (name);
+ b->exp_string = xstrprintf ("-location: %.*s",
+ (int) (exp_end - exp_start), exp_start);
+
/* The above expression is in C. */
b->language = language_c;
}
{
if (VALUE_LVAL (v) == lval_memory)
{
- if (value_lazy (v))
- /* A lazy memory lvalue is one that GDB never needed to fetch;
- we either just used its address (e.g., `a' in `a.b') or
- we never needed it at all (e.g., `a' in `a,b'). */
+ if (v != head && value_lazy (v))
+ /* A lazy memory lvalue in the chain is one that GDB never
+ needed to fetch; we either just used its address (e.g.,
+ `a' in `a.b') or we never needed it at all (e.g., `a'
+ in `a,b'). This doesn't apply to HEAD; if that is
+ lazy then it was not readable, but watch it anyway. */
;
else
{
struct breakpoint *b, *temp;
for (; bs; bs = bs->next)
- if (bs->breakpoint_at
- && bs->breakpoint_at->owner
- && bs->breakpoint_at->owner->disposition == disp_del
+ if (bs->breakpoint_at
+ && bs->breakpoint_at->disposition == disp_del
&& bs->stop)
- delete_breakpoint (bs->breakpoint_at->owner);
+ delete_breakpoint (bs->breakpoint_at);
ALL_BREAKPOINTS_SAFE (b, temp)
{
VEC_safe_push (bp_location_p, moribund_locations, old_loc);
}
else
- free_bp_location (old_loc);
+ {
+ old_loc->owner = NULL;
+ decref_bp_location (&old_loc);
+ }
}
}
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
if (--(loc->events_till_retirement) == 0)
{
- free_bp_location (loc);
+ decref_bp_location (&loc);
VEC_unordered_remove (bp_location_p, moribund_locations, ix);
--ix;
}
update_global_location_list (inserting);
}
-/* Clear LOC from a BPS. */
+/* Clear BKP from a BPS. */
+
static void
-bpstat_remove_bp_location (bpstat bps, struct bp_location *loc)
+bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt)
{
bpstat bs;
for (bs = bps; bs; bs = bs->next)
- if (bs->breakpoint_at == loc)
+ if (bs->breakpoint_at == bpt)
{
bs->breakpoint_at = NULL;
bs->old_val = NULL;
/* Callback for iterate_over_threads. */
static int
-bpstat_remove_bp_location_callback (struct thread_info *th, void *data)
+bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
{
- struct bp_location *loc = data;
+ struct breakpoint *bpt = data;
- bpstat_remove_bp_location (th->stop_bpstat, loc);
+ bpstat_remove_bp_location (th->stop_bpstat, bpt);
return 0;
}
/* Delete a breakpoint and clean up all traces of it in the data
- structures. */
+ structures. */
void
delete_breakpoint (struct breakpoint *bpt)
xfree (bpt->addr_string);
xfree (bpt->exp);
xfree (bpt->exp_string);
+ xfree (bpt->exp_string_reparse);
value_free (bpt->val);
xfree (bpt->source_file);
xfree (bpt->exec_pathname);
clean_up_filters (&bpt->syscalls_to_be_caught);
+
+ /* Be sure no bpstat's are pointing at the breakpoint after it's
+ been freed. */
+ /* FIXME, how can we find all bpstat's? We just check stop_bpstat
+ in all threeds for now. Note that we cannot just remove bpstats
+ pointing at bpt from the stop_bpstat list entirely, as breakpoint
+ commands are associated with the bpstat; if we remove it here,
+ then the later call to bpstat_do_actions (&stop_bpstat); in
+ event-top.c won't do anything, and temporary breakpoints with
+ commands won't work. */
+
+ iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
+
/* Now that breakpoint is removed from breakpoint
list, update the global location list. This
will remove locations that used to belong to
fprintf_unfiltered (fp, " commands\n");
ui_out_redirect (uiout, fp);
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY_CATCH (ex, RETURN_MASK_ALL)
{
print_command_lines (uiout, tp->commands->commands, 2);
}