Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.487 diff -u -p -r1.487 NEWS --- NEWS 7 Feb 2012 19:47:15 -0000 1.487 +++ NEWS 10 Feb 2012 01:51:59 -0000 @@ -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: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.651 diff -u -p -r1.651 breakpoint.c --- breakpoint.c 9 Feb 2012 08:20:03 -0000 1.651 +++ breakpoint.c 10 Feb 2012 01:51:59 -0000 @@ -83,6 +83,8 @@ static void enable_delete_command (char 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 /* 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,17 @@ print_one_breakpoint_location (struct br 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 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 +12900,8 @@ disable_command (char *args, int from_tt } 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 +12954,7 @@ enable_breakpoint_disp (struct breakpoin } bpt->disposition = disposition; + bpt->enable_count = count; update_global_location_list (1); breakpoints_changed (); @@ -12947,7 +12965,7 @@ enable_breakpoint_disp (struct breakpoin void enable_breakpoint (struct breakpoint *bpt) { - enable_breakpoint_disp (bpt, bpt->disposition); + enable_breakpoint_disp (bpt, bpt->disposition, 0); } static void @@ -12997,18 +13015,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 +13047,25 @@ enable_once_command (char *args, int fro } 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 +14334,12 @@ Enable breakpoints and delete when hit. 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 +14350,12 @@ Enable breakpoints for one hit. Give br 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: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.173 diff -u -p -r1.173 breakpoint.h --- breakpoint.h 24 Jan 2012 21:39:15 -0000 1.173 +++ breakpoint.h 10 Feb 2012 01:51:59 -0000 @@ -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: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.920 diff -u -p -r1.920 gdb.texinfo --- doc/gdb.texinfo 10 Feb 2012 01:24:58 -0000 1.920 +++ doc/gdb.texinfo 10 Feb 2012 01:52:00 -0000 @@ -3505,6 +3505,11 @@ has been hit. This is especially useful 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 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,12 @@ become effective once again in stopping 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. + @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: testsuite/gdb.base/ena-dis-br.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/ena-dis-br.exp,v retrieving revision 1.19 diff -u -p -r1.19 ena-dis-br.exp --- testsuite/gdb.base/ena-dis-br.exp 16 Jan 2012 16:21:44 -0000 1.19 +++ testsuite/gdb.base/ena-dis-br.exp 10 Feb 2012 01:52:00 -0000 @@ -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.)