2010-08-17  Pedro Alves  <pedro@codesourcery.com>

	PR breakpoints/11371

	* breakpoint.c (breakpoint_init_inferior): Decrement the
	location's reference count instead of deleting right away.
	(bpstat_free): Decrement the location's reference count.  Make
	static.
	(bpstat_copy): Increment the location's reference count.
	(bpstat_find_breakpoint): Adjust.
	(bpstat_num): Adjust.
	(print_it_typical): Adjust.  Use the breakpoint pointer in the
	bpstat instead of the location's owner.
	(bpstat_alloc): Remove const qualifier from the 'bl' parameter.
	Adjust to record the location's owner in the bpstat.
	(watchpoint_check): Use the breakpoint pointer in the bpstat
	instead of the location's owner.
	(bpstat_check_breakpoint_conditions): Don't handle
	bp_watchpoint_scope here.  Use the breakpoint pointer in the
	bpstat instead of the location's owner.
	(bpstat_stop_status): Defer inferior function calls to after
	building the bpstat list.  Handle bp_watchpoint_scope here.  Use
	the breakpoint pointer in the bpstat instead of the location's
	owner.
	(bpstat_what): Use the breakpoint pointer in the bpstat instead of
	the location's owner.
	(free_bp_location): Don't walk bpstats clearing locations.
	(incref_bp_location): New.
	(decref_bp_location): New.
	(breakpoint_auto_delete): Use the breakpoint pointer in the bpstat
	instead of the location's owner.
	(update_global_location_list): Clear the location's owner, and
	decrement the location's reference count instead of deleting it
	right away.
	(breakpoint_retire_moribund): Decrement the location's reference
	count instead of deleting it right away.
	(bpstat_remove_bp_location): Delete.
	(bpstat_remove_breakpoint): New.
	(bpstat_remove_bp_location_callback): Delete.
	(bpstat_remove_breakpoint_callback): New.
	(delete_breakpoint): Iterate over all threads' stop_bpstat's
	clearing references to the breakpoint that is being deleted.

	* breakpoint.h (struct bp_location) <refc>: New field.
	<owner>: Update comments.
	(bpstat_free): Delete declaration.
	(struct bpstats): Change the type of the breakpoint_at field to
	struct breakpoint point, from struct bp_location pointer.  Add new
	field bp_location_at.

gdb/testsuite/
2010-08-17  Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Pedro Alves  <pedro@codesourcery.com>

	PR breakpoints/11371

	* gdb.base/watch-cond-infcall.exp: New file.
	* gdb.base/watch-cond-infcall.c: New file.
This commit is contained in:
Pedro Alves 2010-08-17 20:59:04 +00:00
parent 1ab03f4b26
commit f431efe540
6 changed files with 332 additions and 108 deletions

View File

@ -1,3 +1,53 @@
2010-08-17 Pedro Alves <pedro@codesourcery.com>
PR breakpoints/11371
* breakpoint.c (breakpoint_init_inferior): Decrement the
location's reference count instead of deleting right away.
(bpstat_free): Decrement the location's reference count. Make
static.
(bpstat_copy): Increment the location's reference count.
(bpstat_find_breakpoint): Adjust.
(bpstat_num): Adjust.
(print_it_typical): Adjust. Use the breakpoint pointer in the
bpstat instead of the location's owner.
(bpstat_alloc): Remove const qualifier from the 'bl' parameter.
Adjust to record the location's owner in the bpstat.
(watchpoint_check): Use the breakpoint pointer in the bpstat
instead of the location's owner.
(bpstat_check_breakpoint_conditions): Don't handle
bp_watchpoint_scope here. Use the breakpoint pointer in the
bpstat instead of the location's owner.
(bpstat_stop_status): Defer inferior function calls to after
building the bpstat list. Handle bp_watchpoint_scope here. Use
the breakpoint pointer in the bpstat instead of the location's
owner.
(bpstat_what): Use the breakpoint pointer in the bpstat instead of
the location's owner.
(free_bp_location): Don't walk bpstats clearing locations.
(incref_bp_location): New.
(decref_bp_location): New.
(breakpoint_auto_delete): Use the breakpoint pointer in the bpstat
instead of the location's owner.
(update_global_location_list): Clear the location's owner, and
decrement the location's reference count instead of deleting it
right away.
(breakpoint_retire_moribund): Decrement the location's reference
count instead of deleting it right away.
(bpstat_remove_bp_location): Delete.
(bpstat_remove_breakpoint): New.
(bpstat_remove_bp_location_callback): Delete.
(bpstat_remove_breakpoint_callback): New.
(delete_breakpoint): Iterate over all threads' stop_bpstat's
clearing references to the breakpoint that is being deleted.
* breakpoint.h (struct bp_location) <refc>: New field.
<owner>: Update comments.
(bpstat_free): Delete declaration.
(struct bpstats): Change the type of the breakpoint_at field to
struct breakpoint point, from struct bp_location pointer. Add new
field bp_location_at.
2010-08-16 Tom Tromey <tromey@redhat.com>
* NEWS: Fix typo.

View File

@ -133,7 +133,7 @@ static void watchpoints_info (char *, int);
static int breakpoint_1 (int, int, int (*) (const struct breakpoint *));
static bpstat bpstat_alloc (const struct bp_location *, bpstat);
static bpstat bpstat_alloc (struct bp_location *, bpstat);
static int breakpoint_cond_eval (void *);
@ -194,6 +194,8 @@ static int single_step_breakpoint_inserted_here_p (struct address_space *,
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);
@ -201,9 +203,6 @@ static void update_global_location_list (int);
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);
@ -2599,7 +2598,7 @@ breakpoint_init_inferior (enum inf_context context)
/* 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);
}
@ -2847,12 +2846,16 @@ ep_is_catchpoint (struct breakpoint *ep)
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);
}
@ -2895,6 +2898,7 @@ bpstat_copy (bpstat 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);
@ -2922,7 +2926,7 @@ bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint)
for (; bsp != NULL; bsp = bsp->next)
{
if (bsp->breakpoint_at && bsp->breakpoint_at->owner == breakpoint)
if (bsp->breakpoint_at == breakpoint)
return bsp;
}
return NULL;
@ -2949,7 +2953,7 @@ bpstat_num (bpstat *bsp, int *num)
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 */
@ -3161,13 +3165,11 @@ print_it_typical (bpstat bs)
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);
@ -3176,7 +3178,7 @@ print_it_typical (bpstat bs)
{
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,
@ -3357,9 +3359,8 @@ print_bp_stop_message (bpstat bs)
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? */
@ -3438,13 +3439,15 @@ breakpoint_cond_eval (void *exp)
/* Allocate a new bpstat and chain it to the current one. */
static bpstat
bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
bpstat_alloc (struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
cbs->next = bs;
bs->breakpoint_at = bl;
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;
@ -3537,10 +3540,9 @@ watchpoint_check (void *p)
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
@ -3731,9 +3733,9 @@ bpstat_check_watchpoint (bpstat bs)
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))
@ -3882,6 +3884,7 @@ bpstat_check_watchpoint (bpstat bs)
/* 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)
{
@ -3890,9 +3893,9 @@ 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)
@ -3903,19 +3906,12 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
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;
@ -4026,10 +4022,14 @@ bpstat_stop_status (struct address_space *aspace,
bpstat bs = root_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)
{
@ -4056,15 +4056,53 @@ bpstat_stop_status (struct address_space *aspace,
bs = bpstat_alloc (bl, bs); /* 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);
/* For hits of moribund locations, we should just proceed. */
bs->stop = 0;
bs->print = 0;
bs->print_it = print_it_noop;
}
}
/* Terminate the chain. */
bs->next = NULL;
/* 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 = root_bs->next; 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
@ -4073,7 +4111,7 @@ bpstat_stop_status (struct address_space *aspace,
bs->stop = 0;
else
bpstat_check_breakpoint_conditions (bs, ptid);
if (bs->stop)
{
++(b->hit_count);
@ -4083,7 +4121,7 @@ bpstat_stop_status (struct address_space *aspace,
{
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;
@ -4104,24 +4142,8 @@ bpstat_stop_status (struct address_space *aspace,
/* 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
@ -4130,18 +4152,17 @@ bpstat_stop_status (struct address_space *aspace,
if (! bpstat_causes_stop (root_bs->next))
for (bs = root_bs->next; 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;
}
@ -4194,10 +4215,10 @@ bpstat_what (bpstat bs)
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)
{
@ -5372,32 +5393,41 @@ allocate_bp_location (struct breakpoint *bpt)
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)
{
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. */
@ -9170,11 +9200,10 @@ breakpoint_auto_delete (bpstat bs)
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)
{
@ -9485,7 +9514,10 @@ update_global_location_list (int should_insert)
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);
}
}
}
@ -9568,7 +9600,7 @@ breakpoint_retire_moribund (void)
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;
}
@ -9583,14 +9615,15 @@ update_global_location_list_nothrow (int inserting)
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;
@ -9600,16 +9633,16 @@ bpstat_remove_bp_location (bpstat bps, struct bp_location *loc)
/* 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)
@ -9668,6 +9701,19 @@ delete_breakpoint (struct breakpoint *bpt)
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

View File

@ -240,13 +240,18 @@ struct bp_location
the same parent breakpoint. */
struct bp_location *next;
/* The reference count. */
int refc;
/* Type of this breakpoint location. */
enum bp_loc_type loc_type;
/* Each breakpoint location must belong to exactly one higher-level
breakpoint. This and the DUPLICATE flag are more straightforward
than reference counting. This pointer is NULL iff this bp_location is in
(and therefore only in) moribund_locations. */
breakpoint. This pointer is NULL iff this bp_location is no
longer attached to a breakpoint. For example, when a breakpoint
is deleted, its locations may still be found in the
moribund_locations list, or if we had stopped for it, in
bpstats. */
struct breakpoint *owner;
/* Conditional. Break only if this expression's value is nonzero.
@ -563,10 +568,6 @@ DEF_VEC_P(breakpoint_p);
typedef struct bpstats *bpstat;
/* Frees any storage that is part of a bpstat.
Does not walk the 'next' chain. */
extern void bpstat_free (bpstat);
/* Clears a chain of bpstat, freeing storage
of each. */
extern void bpstat_clear (bpstat *);
@ -731,16 +732,41 @@ enum bp_print_how
struct bpstats
{
/* Linked list because there can be two breakpoints at the same
place, and a bpstat reflects the fact that both have been hit. */
/* Linked list because there can be more than one breakpoint at
the same place, and a bpstat reflects the fact that all have
been hit. */
bpstat next;
/* Breakpoint that we are at. */
const struct bp_location *breakpoint_at;
/* Location that caused the stop. Locations are refcounted, so
this will never be NULL. Note that this location may end up
detached from a breakpoint, but that does not necessary mean
that the struct breakpoint is gone. E.g., consider a
watchpoint with a condition that involves an inferior function
call. Watchpoint locations are recreated often (on resumes,
hence on infcalls too). Between creating the bpstat and after
evaluating the watchpoint condition, this location may hence
end up detached from its original owner watchpoint, even though
the watchpoint is still listed. If it's condition evaluates as
true, we still want this location to cause a stop, and we will
still need to know which watchpoint it was originally attached.
What this means is that we should not (in most cases) follow
the `bpstat->bp_location->owner' link, but instead use the
`breakpoint_at' field below. */
struct bp_location *bp_location_at;
/* Breakpoint that caused the stop. This is nullified if the
breakpoint ends up being deleted. See comments on
`bp_location_at' above for why do we need this field instead of
following the location's owner. */
struct breakpoint *breakpoint_at;
/* The associated command list. */
struct counted_command_line *commands;
/* Commands left to be done. This points somewhere in
base_command. */
struct command_line *commands_left;
/* Old value associated with a watchpoint. */
struct value *old_val;

View File

@ -1,3 +1,11 @@
2010-08-17 Jan Kratochvil <jan.kratochvil@redhat.com>
Pedro Alves <pedro@codesourcery.com>
PR breakpoints/11371
* gdb.base/watch-cond-infcall.exp: New file.
* gdb.base/watch-cond-infcall.c: New file.
2010-08-16 Tom Tromey <tromey@redhat.com>
* gdb.base/help.exp: Update.

View File

@ -0,0 +1,33 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2010 Free Software Foundation, Inc.
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/>. */
volatile int var;
int
return_1 (void)
{
return 1;
}
int
main(void)
{
var++;
var++; /* watchpoint-stop */
return 0; /* break-at-exit */
}

View File

@ -0,0 +1,61 @@
# Copyright 2010 Free Software Foundation, Inc.
# 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/>.
# Test for watchpoints with conditions that involve inferior function
# calls.
set testfile "watch-cond-infcall"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
if { [build_executable ${testfile}.exp ${testfile} ${testfile}.c {debug}] } {
untested ${testfile}.exp
return -1
}
proc test_watchpoint { hw teststr } {
global testfile
global pf_prefix
set old_pf_prefix $pf_prefix
lappend pf_prefix "$teststr:"
clean_restart ${testfile}
if { ![runto main] } then {
fail "run to main"
return
}
if { ! $hw } {
gdb_test_no_output "set can-use-hw-watchpoints 0" ""
}
gdb_test "watch var if return_1 ()" "atchpoint .*: var"
gdb_breakpoint [gdb_get_line_number "break-at-exit"]
gdb_test "continue" \
"atchpoint \[0-9\]+: var\r\n\r\nOld value = 0\r\nNew value = 1\r\n.*watchpoint-stop.*" \
"continue"
set pf_prefix $old_pf_prefix
}
if { ![target_info exists gdb,no_hardware_watchpoints] } {
test_watchpoint 1 "hw"
}
test_watchpoint 0 "sw"