From e51481f96757303b0f4e7034de800b1fb5c87aa7 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 2 May 1996 18:43:28 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 14 ++++ gdb/breakpoint.c | 84 +++++++++++++++++------- gdb/breakpoint.h | 162 ++++++++++++++++++++++++++++++----------------- 3 files changed, 179 insertions(+), 81 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6d143eb3461..c643aa17273 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 * Makefile.in (rs6000-nat.o): Dependant on xcoffsolib.h. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index a92164660b2..f01e6857361 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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. */ diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 5f45ccd983b..0aa42f59d1d 100644 --- a/gdb/breakpoint.h +++ b/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 disable_display PARAMS ((int)); + +extern void clear_displays PARAMS ((void)); + +extern void disable_breakpoint PARAMS ((struct breakpoint *)); + +extern void enable_breakpoint PARAMS ((struct breakpoint *)); -extern void -do_displays PARAMS ((void)); +extern void create_solib_event_breakpoint PARAMS ((CORE_ADDR)); -extern void -disable_display PARAMS ((int)); +extern void remove_solib_event_breakpoints PARAMS ((void)); -extern void -clear_displays PARAMS ((void)); +extern void re_enable_breakpoints_in_shlibs PARAMS ((void)); #endif /* !defined (BREAKPOINT_H) */ -- 2.30.2