2012-02-14 Stan Shebs <stan@codesourcery.com>
authorStan Shebs <shebs@codesourcery.com>
Tue, 14 Feb 2012 23:28:15 +0000 (23:28 +0000)
committerStan Shebs <shebs@codesourcery.com>
Tue, 14 Feb 2012 23:28:15 +0000 (23:28 +0000)
* NEWS: Mention enable count command.
* breakpoint.h (struct breakpoint): New field enable_count.
* breakpoint.c (enable_breakpoint_disp): Add count argument.
(enable_breakpoint): Add arg to call.
(struct disp_data): New struct.
(do_enable_breakpoint_disp): Interp arg as disp_data and unpack.
(do_map_enable_once_breakpoint): Create a struct and pass it.
(do_map_enable_delete_breakpoint): Ditto.
(do_map_enable_count_breakpoint): New function.
(enable_count_command): New function.
(bpstat_stop_status): Decrement enable_count.
(print_one_breakpoint_location): Report enable count.
(_initialize_breakpoint): Add enable count command.

* gdb.texinfo (Disabling Breakpoints): Document enable count.

* gdb.base/ena-dis-br.exp: Add enable count test.

gdb/ChangeLog
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/ena-dis-br.exp

index 279e223..a8fb900 100644 (file)
@@ -1,3 +1,19 @@
+2012-02-14  Stan Shebs  <stan@codesourcery.com>
+
+       * NEWS: Mention enable count command.
+       * breakpoint.h (struct breakpoint): New field enable_count.
+       * breakpoint.c (enable_breakpoint_disp): Add count argument.
+       (enable_breakpoint): Add arg to call.
+       (struct disp_data): New struct.
+       (do_enable_breakpoint_disp): Interp arg as disp_data and unpack.
+       (do_map_enable_once_breakpoint): Create a struct and pass it.
+       (do_map_enable_delete_breakpoint): Ditto.
+       (do_map_enable_count_breakpoint): New function.
+       (enable_count_command): New function.
+       (bpstat_stop_status): Decrement enable_count.
+       (print_one_breakpoint_location): Report enable count.
+       (_initialize_breakpoint): Add enable count command.
+
 2012-02-14  Kevin Buettner  <kevinb@redhat.com>
 
        * rl78-tdep.c (reggroups.h): Include.
index 46ef6d8..ec7863a 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -49,6 +49,9 @@
   ** "catch load" and "catch unload" can be used to stop when a shared
      library is loaded or unloaded, respectively.
 
+  ** "enable count" can be used to auto-disable a breakpoint after
+     several hits.
+
 *** Changes in GDB 7.4
 
 * GDB now handles ambiguous linespecs more consistently; the existing
index 9a878e1..4854765 100644 (file)
@@ -83,6 +83,8 @@ static void enable_delete_command (char *, int);
 
 static void enable_once_command (char *, int);
 
+static void enable_count_command (char *, int);
+
 static void disable_command (char *, int);
 
 static void enable_command (char *, int);
@@ -207,7 +209,8 @@ static void hbreak_command (char *, int);
 
 static void thbreak_command (char *, int);
 
-static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp);
+static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp,
+                                   int count);
 
 static void stop_command (char *arg, int from_tty);
 
@@ -4335,7 +4338,9 @@ bpstat_stop_status (struct address_space *aspace,
              /* We will stop here.  */
              if (b->disposition == disp_disable)
                {
-                 if (b->enable_state != bp_permanent)
+                 --(b->enable_count);
+                 if (b->enable_count <= 0
+                     && b->enable_state != bp_permanent)
                    b->enable_state = bp_disabled;
                  removed_any = 1;
                }
@@ -5039,6 +5044,23 @@ print_one_breakpoint_location (struct breakpoint *b,
       ui_out_text (uiout, " hits\n");
     }
 
+  /* Note that an enable count of 1 corresponds to "enable once"
+     behavior, which is reported by the combination of enablement and
+     disposition, so we don't need to mention it here.  */
+  if (!part_of_multiple && b->enable_count > 1)
+    {
+      annotate_field (8);
+      ui_out_text (uiout, "\tdisable after ");
+      /* Tweak the wording to clarify that ignore and enable counts
+        are distinct, and have additive effect.  */
+      if (b->ignore_count)
+       ui_out_text (uiout, "additional ");
+      else
+       ui_out_text (uiout, "next ");
+      ui_out_field_int (uiout, "enable", b->enable_count);
+      ui_out_text (uiout, " hits\n");
+    }
+
   if (!part_of_multiple && is_tracepoint (b))
     {
       struct tracepoint *tp = (struct tracepoint *) b;
@@ -12884,7 +12906,8 @@ disable_command (char *args, int from_tty)
 }
 
 static void
-enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
+enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition,
+                       int count)
 {
   int target_resources_ok;
 
@@ -12937,6 +12960,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
     }
 
   bpt->disposition = disposition;
+  bpt->enable_count = count;
   update_global_location_list (1);
   breakpoints_changed ();
   
@@ -12947,7 +12971,7 @@ enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
 void
 enable_breakpoint (struct breakpoint *bpt)
 {
-  enable_breakpoint_disp (bpt, bpt->disposition);
+  enable_breakpoint_disp (bpt, bpt->disposition, 0);
 }
 
 static void
@@ -12997,18 +13021,27 @@ enable_command (char *args, int from_tty)
     map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
 }
 
+/* This struct packages up disposition data for application to multiple
+   breakpoints.  */
+
+struct disp_data
+{
+  enum bpdisp disp;
+  int count;
+};
+
 static void
 do_enable_breakpoint_disp (struct breakpoint *bpt, void *arg)
 {
-  enum bpdisp disp = *(enum bpdisp *) arg;
+  struct disp_data disp_data = *(struct disp_data *) arg;
 
-  enable_breakpoint_disp (bpt, disp);
+  enable_breakpoint_disp (bpt, disp_data.disp, disp_data.count);
 }
 
 static void
 do_map_enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
 {
-  enum bpdisp disp = disp_disable;
+  struct disp_data disp = { disp_disable, 1 };
 
   iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
 }
@@ -13020,9 +13053,25 @@ enable_once_command (char *args, int from_tty)
 }
 
 static void
+do_map_enable_count_breakpoint (struct breakpoint *bpt, void *countptr)
+{
+  struct disp_data disp = { disp_disable, *(int *) countptr };
+
+  iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
+}
+
+static void
+enable_count_command (char *args, int from_tty)
+{
+  int count = get_number (&args);
+
+  map_breakpoint_numbers (args, do_map_enable_count_breakpoint, &count);
+}
+
+static void
 do_map_enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
 {
-  enum bpdisp disp = disp_del;
+  struct disp_data disp = { disp_del, 1 };
 
   iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
 }
@@ -14291,6 +14340,12 @@ Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
 If a breakpoint is hit while enabled in this fashion, it is deleted."),
           &enablebreaklist);
 
+  add_cmd ("count", no_class, enable_count_command, _("\
+Enable breakpoints for COUNT hits.  Give count and then breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion,\n\
+the count is decremented; when it reaches zero, the breakpoint is disabled."),
+          &enablebreaklist);
+
   add_cmd ("delete", no_class, enable_delete_command, _("\
 Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
 If a breakpoint is hit while enabled in this fashion, it is deleted."),
@@ -14301,6 +14356,12 @@ Enable breakpoints for one hit.  Give breakpoint numbers.\n\
 If a breakpoint is hit while enabled in this fashion, it becomes disabled."),
           &enablelist);
 
+  add_cmd ("count", no_class, enable_count_command, _("\
+Enable breakpoints for COUNT hits.  Give count and then breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion,\n\
+the count is decremented; when it reaches zero, the breakpoint is disabled."),
+          &enablelist);
+
   add_prefix_cmd ("disable", class_breakpoint, disable_command, _("\
 Disable some breakpoints.\n\
 Arguments are breakpoint numbers with spaces in between.\n\
index aa66790..07e3fc9 100644 (file)
@@ -596,6 +596,11 @@ struct breakpoint
     /* Number of stops at this breakpoint that should
        be continued automatically before really stopping.  */
     int ignore_count;
+
+    /* Number of stops at this breakpoint before it will be
+       disabled.  */
+    int enable_count;
+
     /* Chain of command lines to execute when this breakpoint is
        hit.  */
     struct counted_command_line *commands;
index 0aac7d2..6c39494 100644 (file)
@@ -1,3 +1,7 @@
+2012-02-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Disabling Breakpoints): Document enable count.
+
 2012-02-13  Pedro Alves  <palves@redhat.com>
 
        * gdb.texinfo (MIPS boards): Refer to mips-elf instead of
index 9edc6ad..4373822 100644 (file)
@@ -3505,6 +3505,11 @@ has been hit.  This is especially useful in conjunction with the
 hits, look at the breakpoint info to see how many times the breakpoint
 was hit, and then run again, ignoring one less than that number.  This
 will get you quickly to the last hit of that breakpoint.
+
+@noindent
+For a breakpoints with an enable count (xref) greater than 1,
+@code{info break} also displays that count.
+
 @end table
 
 @value{GDBN} allows you to set any number of breakpoints at the same place in
@@ -4252,8 +4257,8 @@ do not know which numbers to use.
 Disabling and enabling a breakpoint that has multiple locations
 affects all of its locations.
 
-A breakpoint, watchpoint, or catchpoint can have any of four different
-states of enablement:
+A breakpoint, watchpoint, or catchpoint can have any of several
+different states of enablement:
 
 @itemize @bullet
 @item
@@ -4265,6 +4270,9 @@ Disabled.  The breakpoint has no effect on your program.
 Enabled once.  The breakpoint stops your program, but then becomes
 disabled.
 @item
+Enabled for a count.  The breakpoint stops your program for the next
+N times, then becomes disabled.
+@item
 Enabled for deletion.  The breakpoint stops your program, but
 immediately after it does so it is deleted permanently.  A breakpoint
 set with the @code{tbreak} command starts out in this state.
@@ -4292,6 +4300,14 @@ become effective once again in stopping your program.
 Enable the specified breakpoints temporarily.  @value{GDBN} disables any
 of these breakpoints immediately after stopping your program.
 
+@item enable @r{[}breakpoints@r{]} count @var{count} @var{range}@dots{}
+Enable the specified breakpoints temporarily.  @value{GDBN} records
+@var{count} with each of the specified breakpoints, and decrements a
+breakpoint's count when it is hit.  When any count reaches 0,
+@value{GDBN} disables that breakpoint.  If a breakpoint has an ignore
+count (@pxref{Conditions, ,Break Conditions}), that will be
+decremented to 0 before @var{count} is affected.
+
 @item enable @r{[}breakpoints@r{]} delete @var{range}@dots{}
 Enable the specified breakpoints to work once, then die.  @value{GDBN}
 deletes any of these breakpoints as soon as your program stops there.
index 35b1df5..463a6ae 100644 (file)
@@ -1,3 +1,7 @@
+2012-02-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.base/ena-dis-br.exp: Add enable count test.
+
 2012-02-13  Pedro Alves  <palves@redhat.com>
 
        * config/mips-idt.exp: Delete.
index 2e5cdb1..2cf3e9a 100644 (file)
@@ -46,6 +46,7 @@ gdb_reinitialize_dir $srcdir/$subdir
 gdb_load ${binfile}
 
 set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location7 [gdb_get_line_number "set breakpoint 7 here"]
 set bp_location8 [gdb_get_line_number "set breakpoint 8 here" $srcfile1]
 set bp_location9 [gdb_get_line_number "set breakpoint 9 here" $srcfile1]
 set bp_location11 [gdb_get_line_number "set breakpoint 11 here"]
@@ -162,6 +163,31 @@ gdb_test "info break $bp" \
     "\[0-9\]*\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+n.*" \
     "info break marker4"
 
+if ![runto_main] then {
+    fail "enable/disable break tests suppressed"
+}
+
+# Test enable count by stopping at a location until it is disabled
+# and passes through.
+
+set bp [break_at $bp_location7 "line $bp_location7"]
+
+set bp2 [break_at marker1 " line ($bp_location15|$bp_location16)"]
+
+gdb_test_no_output "enable count 2 $bp" "disable break with count"
+
+gdb_test "continue" \
+    ".*factorial .*:$bp_location7.*" \
+    "continue from enable count, first time"
+
+gdb_test "continue" \
+    ".*factorial .*:$bp_location7.*" \
+    "continue from enable count, second time"
+
+gdb_test "continue" \
+    ".*marker1 .*:($bp_location15|$bp_location16).*" \
+    "continue through enable count, now disabled"
+
 # Verify that we can set a breakpoint with an ignore count N, which
 # should cause the next N triggers of the bp to be ignored.  (This is
 # a flavor of enablement/disablement, after all.)