* From Peter Schauer:
* breakpoint.h (enum bpdisp): Add del_at_next_stop. * breakpoint.c (insert_breakpoints, watchpoint_check, bpstat_stop_status): Avoid bad references to memory freed via delete_breakpoint on watchpoints going out of scope. Do not delete these watchpoints, disable them and change their disposition to del_at_next_stop instead. (breakpoint_auto_delete): Delete all breakpoints whose disposition is del_at_next_stop. (breakpoint_init_inferior): Use switch to avoid reference to already deleted breakpoint. Fixes dangling pointer problems with watchpoints.
This commit is contained in:
parent
d124785e82
commit
e51481f967
3 changed files with 179 additions and 81 deletions
|
@ -1,3 +1,17 @@
|
|||
Thu May 2 12:46:14 1996 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* From Peter Schauer:
|
||||
* breakpoint.h (enum bpdisp): Add del_at_next_stop.
|
||||
* breakpoint.c (insert_breakpoints, watchpoint_check,
|
||||
bpstat_stop_status): Avoid bad references to memory freed via
|
||||
delete_breakpoint on watchpoints going out of scope.
|
||||
Do not delete these watchpoints, disable them and change their
|
||||
disposition to del_at_next_stop instead.
|
||||
(breakpoint_auto_delete): Delete all breakpoints whose disposition
|
||||
is del_at_next_stop.
|
||||
(breakpoint_init_inferior): Use switch to avoid reference to
|
||||
already deleted breakpoint.
|
||||
|
||||
Wed May 1 17:29:18 1996 Fred Fish <fnf@cygnus.com>
|
||||
|
||||
* Makefile.in (rs6000-nat.o): Dependant on xcoffsolib.h.
|
||||
|
|
|
@ -574,8 +574,12 @@ insert_breakpoints ()
|
|||
Hardware watchpoint %d deleted because the program has left the block in\n\
|
||||
which its expression is valid.\n", b->number);
|
||||
if (b->related_breakpoint)
|
||||
delete_breakpoint (b->related_breakpoint);
|
||||
delete_breakpoint (b);
|
||||
{
|
||||
b->related_breakpoint->enable = disable;
|
||||
b->related_breakpoint->disposition = del_at_next_stop;
|
||||
}
|
||||
b->enable = disable;
|
||||
b->disposition = del_at_next_stop;
|
||||
}
|
||||
|
||||
/* Restore the frame and level. */
|
||||
|
@ -691,21 +695,32 @@ breakpoint_init_inferior ()
|
|||
{
|
||||
b->inserted = 0;
|
||||
|
||||
/* If the call dummy breakpoint is at the entry point it will
|
||||
cause problems when the inferior is rerun, so we better
|
||||
get rid of it. */
|
||||
if (b->type == bp_call_dummy)
|
||||
delete_breakpoint (b);
|
||||
switch (b->type)
|
||||
{
|
||||
case bp_call_dummy:
|
||||
case bp_watchpoint_scope:
|
||||
|
||||
/* Likewise for scope breakpoints. */
|
||||
if (b->type == bp_watchpoint_scope)
|
||||
delete_breakpoint (b);
|
||||
/* If the call dummy breakpoint is at the entry point it will
|
||||
cause problems when the inferior is rerun, so we better
|
||||
get rid of it.
|
||||
|
||||
/* Likewise for watchpoints on local expressions. */
|
||||
if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint ||
|
||||
b->type == bp_read_watchpoint || b->type == bp_access_watchpoint)
|
||||
&& b->exp_valid_block != NULL)
|
||||
delete_breakpoint (b);
|
||||
Also get rid of scope breakpoints. */
|
||||
delete_breakpoint (b);
|
||||
break;
|
||||
|
||||
case bp_watchpoint:
|
||||
case bp_hardware_watchpoint:
|
||||
case bp_read_watchpoint:
|
||||
case bp_access_watchpoint:
|
||||
|
||||
/* Likewise for watchpoints on local expressions. */
|
||||
if (b->exp_valid_block != NULL)
|
||||
delete_breakpoint (b);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1151,8 +1166,12 @@ watchpoint_check (p)
|
|||
Watchpoint %d deleted because the program has left the block in\n\
|
||||
which its expression is valid.\n", bs->breakpoint_at->number);
|
||||
if (b->related_breakpoint)
|
||||
delete_breakpoint (b->related_breakpoint);
|
||||
delete_breakpoint (b);
|
||||
{
|
||||
b->related_breakpoint->enable = disable;
|
||||
b->related_breakpoint->disposition = del_at_next_stop;
|
||||
}
|
||||
b->enable = disable;
|
||||
b->disposition = del_at_next_stop;
|
||||
|
||||
return WP_DELETED;
|
||||
}
|
||||
|
@ -1280,8 +1299,12 @@ bpstat_stop_status (pc, not_a_breakpoint)
|
|||
/* Error from catch_errors. */
|
||||
printf_filtered ("Watchpoint %d deleted.\n", b->number);
|
||||
if (b->related_breakpoint)
|
||||
delete_breakpoint (b->related_breakpoint);
|
||||
delete_breakpoint (b);
|
||||
{
|
||||
b->related_breakpoint->enable = disable;
|
||||
b->related_breakpoint->disposition = del_at_next_stop;
|
||||
}
|
||||
b->enable = disable;
|
||||
b->disposition = del_at_next_stop;
|
||||
/* We've already printed what needs to be printed. */
|
||||
bs->print_it = print_it_done;
|
||||
|
||||
|
@ -1326,9 +1349,13 @@ bpstat_stop_status (pc, not_a_breakpoint)
|
|||
case 0:
|
||||
/* Error from catch_errors. */
|
||||
printf_filtered ("Watchpoint %d deleted.\n", b->number);
|
||||
if (b->related_breakpoint)
|
||||
delete_breakpoint (b->related_breakpoint);
|
||||
delete_breakpoint (b);
|
||||
if (b->related_breakpoint)
|
||||
{
|
||||
b->related_breakpoint->enable = disable;
|
||||
b->related_breakpoint->disposition = del_at_next_stop;
|
||||
}
|
||||
b->enable = disable;
|
||||
b->disposition = del_at_next_stop;
|
||||
/* We've already printed what needs to be printed. */
|
||||
bs->print_it = print_it_done;
|
||||
break;
|
||||
|
@ -1638,7 +1665,7 @@ breakpoint_1 (bnum, allflag)
|
|||
"sigtramp",
|
||||
"watchpoint scope", "call dummy",
|
||||
"shlib events" };
|
||||
static char *bpdisps[] = {"del", "dis", "keep"};
|
||||
static char *bpdisps[] = {"del", "dstp", "dis", "keep"};
|
||||
static char bpenables[] = "ny";
|
||||
char wrap_indent[80];
|
||||
|
||||
|
@ -3231,17 +3258,26 @@ clear_command (arg, from_tty)
|
|||
free ((PTR)sals.sals);
|
||||
}
|
||||
|
||||
/* Delete breakpoint in BS if they are `delete' breakpoints.
|
||||
/* Delete breakpoint in BS if they are `delete' breakpoints and
|
||||
all breakpoints that are marked for deletion, whether hit or not.
|
||||
This is called after any breakpoint is hit, or after errors. */
|
||||
|
||||
void
|
||||
breakpoint_auto_delete (bs)
|
||||
bpstat bs;
|
||||
{
|
||||
struct breakpoint *b, *temp;
|
||||
|
||||
for (; bs; bs = bs->next)
|
||||
if (bs->breakpoint_at && bs->breakpoint_at->disposition == del
|
||||
&& bs->stop)
|
||||
delete_breakpoint (bs->breakpoint_at);
|
||||
|
||||
ALL_BREAKPOINTS_SAFE (b, temp)
|
||||
{
|
||||
if (b->disposition == del_at_next_stop)
|
||||
delete_breakpoint (b);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete a breakpoint and clean up all traces of it in the data structures. */
|
||||
|
|
162
gdb/breakpoint.h
162
gdb/breakpoint.h
|
@ -1,5 +1,5 @@
|
|||
/* Data structures associated with breakpoints in GDB.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
|
@ -15,7 +15,7 @@ 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#if !defined (BREAKPOINT_H)
|
||||
#define BREAKPOINT_H 1
|
||||
|
@ -39,9 +39,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
||||
enum bptype {
|
||||
bp_breakpoint, /* Normal breakpoint */
|
||||
bp_hardware_breakpoint, /* Hardware assisted breakpoint */
|
||||
bp_until, /* used by until command */
|
||||
bp_finish, /* used by finish command */
|
||||
bp_watchpoint, /* Watchpoint */
|
||||
bp_hardware_watchpoint, /* Hardware assisted watchpoint */
|
||||
bp_read_watchpoint, /* read watchpoint, (hardware assisted) */
|
||||
bp_access_watchpoint, /* access watchpoint, (hardware assisted) */
|
||||
bp_longjmp, /* secret breakpoint to find longjmp() */
|
||||
bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
|
||||
|
||||
|
@ -52,6 +56,20 @@ enum bptype {
|
|||
/* Used by wait_for_inferior for stepping over signal handlers. */
|
||||
bp_through_sigtramp,
|
||||
|
||||
/* Used to detect when a watchpoint expression has gone out of
|
||||
scope. These breakpoints are usually not visible to the user.
|
||||
|
||||
This breakpoint has some interesting properties:
|
||||
|
||||
1) There's always a 1:1 mapping between watchpoints
|
||||
on local variables and watchpoint_scope breakpoints.
|
||||
|
||||
2) It automatically deletes itself and the watchpoint it's
|
||||
associated with when hit.
|
||||
|
||||
3) It can never be disabled. */
|
||||
bp_watchpoint_scope,
|
||||
|
||||
/* The breakpoint at the end of a call dummy. */
|
||||
/* FIXME: What if the function we are calling longjmp()s out of the
|
||||
call, or the user gets out with the "return" command? We currently
|
||||
|
@ -59,17 +77,28 @@ enum bptype {
|
|||
(Probably can solve this by noticing longjmp, "return", etc., it's
|
||||
similar to noticing when a watchpoint on a local variable goes out
|
||||
of scope (with hardware support for watchpoints)). */
|
||||
bp_call_dummy
|
||||
bp_call_dummy,
|
||||
|
||||
/* Some dynamic linkers (HP, maybe Solaris) can arrange for special
|
||||
code in the inferior to run when significant events occur in the
|
||||
dynamic linker (for example a library is loaded or unloaded).
|
||||
|
||||
By placing a breakpoint in this magic code GDB will get control
|
||||
when these significant events occur. GDB can then re-examine
|
||||
the dynamic linker's data structures to discover any newly loaded
|
||||
dynamic libraries. */
|
||||
bp_shlib_event
|
||||
};
|
||||
|
||||
/* States of enablement of breakpoint. */
|
||||
|
||||
enum enable { disabled, enabled};
|
||||
enum enable { disabled, enabled, shlib_disabled};
|
||||
|
||||
/* Disposition of breakpoint. Ie: what to do after hitting it. */
|
||||
|
||||
enum bpdisp {
|
||||
delete, /* Delete it */
|
||||
del, /* Delete it */
|
||||
del_at_next_stop, /* Delete at next stop, whether hit or not */
|
||||
disable, /* Disable it */
|
||||
donttouch /* Leave it alone */
|
||||
};
|
||||
|
@ -128,13 +157,17 @@ struct breakpoint
|
|||
struct command_line *commands;
|
||||
/* Stack depth (address of frame). If nonzero, break only if fp
|
||||
equals this. */
|
||||
FRAME_ADDR frame;
|
||||
CORE_ADDR frame;
|
||||
/* Conditional. Break only if this expression's value is nonzero. */
|
||||
struct expression *cond;
|
||||
|
||||
/* String we used to set the breakpoint (malloc'd). Only matters if
|
||||
address is non-NULL. */
|
||||
char *addr_string;
|
||||
/* Language we used to set the breakpoint. */
|
||||
enum language language;
|
||||
/* Input radix we used to set the breakpoint. */
|
||||
int input_radix;
|
||||
/* String form of the breakpoint condition (malloc'd), or NULL if there
|
||||
is no condition. */
|
||||
char *cond_string;
|
||||
|
@ -147,16 +180,38 @@ struct breakpoint
|
|||
valid anywhere (e.g. consists just of global symbols). */
|
||||
struct block *exp_valid_block;
|
||||
/* Value of the watchpoint the last time we checked it. */
|
||||
value val;
|
||||
value_ptr val;
|
||||
|
||||
/* Holds the value chain for a hardware watchpoint expression. */
|
||||
value_ptr val_chain;
|
||||
|
||||
/* Holds the address of the related watchpoint_scope breakpoint
|
||||
when using watchpoints on local variables (might the concept
|
||||
of a related breakpoint be useful elsewhere, if not just call
|
||||
it the watchpoint_scope breakpoint or something like that. FIXME). */
|
||||
struct breakpoint *related_breakpoint;
|
||||
|
||||
/* Holds the frame address which identifies the frame this watchpoint
|
||||
should be evaluated in, or NULL if the watchpoint should be evaluated
|
||||
on the outermost frame. */
|
||||
CORE_ADDR watchpoint_frame;
|
||||
|
||||
/* Thread number for thread-specific breakpoint, or -1 if don't care */
|
||||
int thread;
|
||||
|
||||
/* Count of the number of times this breakpoint was taken, dumped
|
||||
with the info, but not used for anything else. Useful for
|
||||
seeing how many times you hit a break prior to the program
|
||||
aborting, so you can back up to just before the abort. */
|
||||
int hit_count;
|
||||
|
||||
};
|
||||
|
||||
/* The following stuff is an abstract data type "bpstat" ("breakpoint status").
|
||||
This provides the ability to determine whether we have stopped at a
|
||||
breakpoint, and what we should do about it. */
|
||||
|
||||
typedef struct bpstat *bpstat;
|
||||
typedef struct bpstats *bpstat;
|
||||
|
||||
/* Interface: */
|
||||
/* Clear a bpstat so that it says we are not at any breakpoint.
|
||||
|
@ -167,8 +222,7 @@ extern void bpstat_clear PARAMS ((bpstat *));
|
|||
is part of the bpstat is copied as well. */
|
||||
extern bpstat bpstat_copy PARAMS ((bpstat));
|
||||
|
||||
/* FIXME: prototypes uses equivalence between FRAME_ADDR and CORE_ADDR */
|
||||
extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, CORE_ADDR, int));
|
||||
extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, int));
|
||||
|
||||
/* This bpstat_what stuff tells wait_for_inferior what to do with a
|
||||
breakpoint (a challenging task). */
|
||||
|
@ -217,6 +271,10 @@ enum bpstat_what_main_action {
|
|||
checking. */
|
||||
BPSTAT_WHAT_THROUGH_SIGTRAMP,
|
||||
|
||||
/* Check the dynamic linker's data structures for new libraries, then
|
||||
keep checking. */
|
||||
BPSTAT_WHAT_CHECK_SHLIBS,
|
||||
|
||||
/* This is just used to keep track of how many enums there are. */
|
||||
BPSTAT_WHAT_LAST
|
||||
};
|
||||
|
@ -269,7 +327,7 @@ extern void bpstat_do_actions PARAMS ((bpstat *));
|
|||
extern void bpstat_clear_actions PARAMS ((bpstat));
|
||||
|
||||
/* Implementation: */
|
||||
struct bpstat
|
||||
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. */
|
||||
|
@ -279,7 +337,7 @@ struct bpstat
|
|||
/* Commands left to be done. */
|
||||
struct command_line *commands;
|
||||
/* Old value associated with a watchpoint. */
|
||||
value old_val;
|
||||
value_ptr old_val;
|
||||
|
||||
/* Nonzero if this breakpoint tells us to print the frame. */
|
||||
char print;
|
||||
|
@ -305,73 +363,63 @@ extern int frame_in_dummy PARAMS ((struct frame_info *));
|
|||
|
||||
extern int breakpoint_thread_match PARAMS ((CORE_ADDR, int));
|
||||
|
||||
extern void
|
||||
until_break_command PARAMS ((char *, int));
|
||||
extern void until_break_command PARAMS ((char *, int));
|
||||
|
||||
extern void
|
||||
breakpoint_re_set PARAMS ((void));
|
||||
extern void breakpoint_re_set PARAMS ((void));
|
||||
|
||||
extern void
|
||||
clear_momentary_breakpoints PARAMS ((void));
|
||||
extern void clear_momentary_breakpoints PARAMS ((void));
|
||||
|
||||
/* FIXME: Prototype uses equivalence of "struct frame_info *" and FRAME */
|
||||
extern struct breakpoint *
|
||||
set_momentary_breakpoint PARAMS ((struct symtab_and_line,
|
||||
struct frame_info *,
|
||||
enum bptype));
|
||||
extern struct breakpoint *set_momentary_breakpoint
|
||||
PARAMS ((struct symtab_and_line, struct frame_info *, enum bptype));
|
||||
|
||||
extern void
|
||||
set_ignore_count PARAMS ((int, int, int));
|
||||
extern void set_ignore_count PARAMS ((int, int, int));
|
||||
|
||||
extern void
|
||||
set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int));
|
||||
extern void set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int));
|
||||
|
||||
extern void
|
||||
mark_breakpoints_out PARAMS ((void));
|
||||
extern void mark_breakpoints_out PARAMS ((void));
|
||||
|
||||
extern void
|
||||
breakpoint_init_inferior PARAMS ((void));
|
||||
extern void breakpoint_init_inferior PARAMS ((void));
|
||||
|
||||
extern void
|
||||
delete_breakpoint PARAMS ((struct breakpoint *));
|
||||
extern void delete_breakpoint PARAMS ((struct breakpoint *));
|
||||
|
||||
extern void
|
||||
breakpoint_auto_delete PARAMS ((bpstat));
|
||||
extern void breakpoint_auto_delete PARAMS ((bpstat));
|
||||
|
||||
extern void
|
||||
breakpoint_clear_ignore_counts PARAMS ((void));
|
||||
extern void breakpoint_clear_ignore_counts PARAMS ((void));
|
||||
|
||||
extern void
|
||||
break_command PARAMS ((char *, int));
|
||||
extern void break_command PARAMS ((char *, int));
|
||||
|
||||
extern int
|
||||
insert_breakpoints PARAMS ((void));
|
||||
extern int insert_breakpoints PARAMS ((void));
|
||||
|
||||
extern int
|
||||
remove_breakpoints PARAMS ((void));
|
||||
extern int remove_breakpoints PARAMS ((void));
|
||||
|
||||
extern void
|
||||
enable_longjmp_breakpoint PARAMS ((void));
|
||||
extern void enable_longjmp_breakpoint PARAMS ((void));
|
||||
|
||||
extern void
|
||||
disable_longjmp_breakpoint PARAMS ((void));
|
||||
extern void disable_longjmp_breakpoint PARAMS ((void));
|
||||
|
||||
extern void
|
||||
set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR, FRAME));
|
||||
extern void set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR,
|
||||
struct frame_info *));
|
||||
|
||||
extern void clear_breakpoint_hit_counts PARAMS ((void));
|
||||
|
||||
/* The following are for displays, which aren't really breakpoints, but
|
||||
here is as good a place as any for them. */
|
||||
|
||||
extern void
|
||||
disable_current_display PARAMS ((void));
|
||||
extern void disable_current_display PARAMS ((void));
|
||||
|
||||
extern void
|
||||
do_displays PARAMS ((void));
|
||||
extern void do_displays PARAMS ((void));
|
||||
|
||||
extern void
|
||||
disable_display PARAMS ((int));
|
||||
extern void disable_display PARAMS ((int));
|
||||
|
||||
extern void
|
||||
clear_displays PARAMS ((void));
|
||||
extern void clear_displays PARAMS ((void));
|
||||
|
||||
extern void disable_breakpoint PARAMS ((struct breakpoint *));
|
||||
|
||||
extern void enable_breakpoint PARAMS ((struct breakpoint *));
|
||||
|
||||
extern void create_solib_event_breakpoint PARAMS ((CORE_ADDR));
|
||||
|
||||
extern void remove_solib_event_breakpoints PARAMS ((void));
|
||||
|
||||
extern void re_enable_breakpoints_in_shlibs PARAMS ((void));
|
||||
|
||||
#endif /* !defined (BREAKPOINT_H) */
|
||||
|
|
Loading…
Reference in a new issue