* From Peter Schauer:
authorJeff Law <law@redhat.com>
Thu, 2 May 1996 18:43:28 +0000 (18:43 +0000)
committerJeff Law <law@redhat.com>
Thu, 2 May 1996 18:43:28 +0000 (18:43 +0000)
        * 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
gdb/breakpoint.c
gdb/breakpoint.h

index 6d143eb..c643aa1 100644 (file)
@@ -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.
index a921646..f01e685 100644 (file)
@@ -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);
 }
 \f
-/* 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. */
index 5f45ccd..0aa42f5 100644 (file)
@@ -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;
+
 };
 \f
 /* 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));
 \f
 /* 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) */