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);
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);
/* 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;
}
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;
}
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;
}
bpt->disposition = disposition;
+ bpt->enable_count = count;
update_global_location_list (1);
breakpoints_changed ();
void
enable_breakpoint (struct breakpoint *bpt)
{
- enable_breakpoint_disp (bpt, bpt->disposition);
+ enable_breakpoint_disp (bpt, bpt->disposition, 0);
}
static void
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);
}
}
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);
}
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."),
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\
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
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
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.
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.
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"]
"\[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.)