From 816338b5632aeb20e01a18a1d96a59fac6459cd9 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Tue, 14 Feb 2012 23:28:15 +0000 Subject: [PATCH] 2012-02-14 Stan Shebs * 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 | 16 ++++++++ gdb/NEWS | 3 ++ gdb/breakpoint.c | 77 +++++++++++++++++++++++++++++++---- gdb/breakpoint.h | 5 +++ gdb/doc/ChangeLog | 4 ++ gdb/doc/gdb.texinfo | 20 ++++++++- gdb/testsuite/ChangeLog | 4 ++ gdb/testsuite/gdb.base/ena-dis-br.exp | 26 ++++++++++++ 8 files changed, 145 insertions(+), 10 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 279e223..a8fb900 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2012-02-14 Stan Shebs + + * 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 * rl78-tdep.c (reggroups.h): Include. diff --git a/gdb/NEWS b/gdb/NEWS index 46ef6d8..ec7863a 100644 --- 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 diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 9a878e1..4854765 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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\ diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index aa66790..07e3fc9 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -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; diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 0aac7d2..6c39494 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2012-02-14 Stan Shebs + + * gdb.texinfo (Disabling Breakpoints): Document enable count. + 2012-02-13 Pedro Alves * gdb.texinfo (MIPS boards): Refer to mips-elf instead of diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 9edc6ad..4373822 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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. diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 35b1df5..463a6ae 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2012-02-14 Stan Shebs + + * gdb.base/ena-dis-br.exp: Add enable count test. + 2012-02-13 Pedro Alves * config/mips-idt.exp: Delete. diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp index 2e5cdb1..2cf3e9a 100644 --- a/gdb/testsuite/gdb.base/ena-dis-br.exp +++ b/gdb/testsuite/gdb.base/ena-dis-br.exp @@ -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.) -- 2.7.4