aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorXavier Roirand <roirand@adacore.com>2017-11-07 11:00:31 +0000
committerPedro Alves <palves@redhat.com>2017-11-07 11:00:31 +0000
commitd0fe47010fc3289e081ba547a0bfcc6d07906cd2 (patch)
treecb255e0b04bb0b1e4d43bce583ca2938e08f4b7d /gdb
parent0198d5e6fc331d50dc19b7f250ac4bc510a8dbb5 (diff)
downloadgdb-d0fe47010fc3289e081ba547a0bfcc6d07906cd2.zip
gdb-d0fe47010fc3289e081ba547a0bfcc6d07906cd2.tar.gz
gdb-d0fe47010fc3289e081ba547a0bfcc6d07906cd2.tar.bz2
Allow enabling/disabling breakpoint location ranges
When a breakpoint has multiple locations, like e.g.: Num Type Disp Enb Address What 1 breakpoint keep y <MULTIPLE> 1.1 y 0x080486a2 in void foo<int>()... 1.2 y 0x080486ca in void foo<double>()... [....] 1.5 y 0x080487fa in void foo<long>()... it's possible to enable/disable the individual locations using the '<breakpoint_number>.<location_number>' syntax, like e.g.: (gdb) disable 1.2 1.3 1.4 1.5 That's inconvenient when you have a long list of locations to disable, however. This patch adds shorthand for the above, by making it possible to specify a range of locations with the following syntax (similar to thread id ranges): <breakpoint_number>.<first_location_number>-<last_location_number> For example, the command above can now be simplified to: (gdb) disable 1.2-5 gdb/ChangeLog: 2017-11-07 Xavier Roirand <roirand@adacore.com> Pedro Alves <palves@redhat.com> * breakpoint.c (map_breakpoint_number_range): New, factored out from ... (map_breakpoint_numbers): ... here. (find_location_by_number): Change parameters from string to breakpoint number and location. (extract_bp_number_and_location): New function. (enable_disable_bp_num_loc) (enable_disable_breakpoint_location_range) (enable_disable_command): New functions, factored out ... (enable_command, disable_command): ... these functions, and adjusted to support ranges. * NEWS: Document enable/disable breakpoint location range feature. gdb/doc/ChangeLog: 2017-11-07 Xavier Roirand <roirand@adacore.com> Pedro Alves <palves@redhat.com> * gdb.texinfo (Set Breaks): Document support for breakpoint location ranges in the enable/disable commands. gdb/testsuite/ChangeLog: 2017-11-07 Xavier Roirand <roirand@adacore.com> Pedro Alves <palves@redhat.com> * gdb.base/ena-dis-br.exp: Add reference to gdb.cp/ena-dis-br-range.exp. * gdb.cp/ena-dis-br-range.exp: New file. * gdb.cp/ena-dis-br-range.cc: New file.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/NEWS3
-rw-r--r--gdb/breakpoint.c340
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo18
-rw-r--r--gdb/testsuite/ChangeLog8
-rw-r--r--gdb/testsuite/gdb.base/ena-dis-br.exp3
-rw-r--r--gdb/testsuite/gdb.cp/ena-dis-br-range.cc66
-rw-r--r--gdb/testsuite/gdb.cp/ena-dis-br-range.exp132
9 files changed, 471 insertions, 121 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 077369c..1770b1f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,19 @@
+2017-11-07 Xavier Roirand <roirand@adacore.com>
+ Pedro Alves <palves@redhat.com>
+
+ * breakpoint.c (map_breakpoint_number_range): New, factored out
+ from ...
+ (map_breakpoint_numbers): ... here.
+ (find_location_by_number): Change parameters from string to
+ breakpoint number and location.
+ (extract_bp_number_and_location): New function.
+ (enable_disable_bp_num_loc)
+ (enable_disable_breakpoint_location_range)
+ (enable_disable_command): New functions, factored out ...
+ (enable_command, disable_command): ... these functions, and
+ adjusted to support ranges.
+ * NEWS: Document enable/disable breakpoint location range feature.
+
2017-11-06 Luis Machado <luis.machado@linaro.org>
* MAINTAINERS (Write After Approval): Update my e-mail address.
diff --git a/gdb/NEWS b/gdb/NEWS
index fbf5591..aadb7a3 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -75,6 +75,9 @@ QSetWorkingDir
* The "maintenance selftest" command now takes an optional argument to
filter the tests to be run.
+* The "enable", and "disable" commands now accept a range of
+ breakpoint locations, e.g. "enable 1.3-5".
+
* New commands
set|show cwd
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index adc8950..e100f43 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -14131,59 +14131,66 @@ ignore_command (char *args, int from_tty)
printf_filtered ("\n");
}
-/* Call FUNCTION on each of the breakpoints
- whose numbers are given in ARGS. */
+
+/* Call FUNCTION on each of the breakpoints with numbers in the range
+ defined by BP_NUM_RANGE (an inclusive range). */
static void
-map_breakpoint_numbers (const char *args,
- gdb::function_view<void (breakpoint *)> function)
+map_breakpoint_number_range (std::pair<int, int> bp_num_range,
+ gdb::function_view<void (breakpoint *)> function)
{
- int num;
- struct breakpoint *b, *tmp;
-
- if (args == 0 || *args == '\0')
- error_no_arg (_("one or more breakpoint numbers"));
-
- number_or_range_parser parser (args);
-
- while (!parser.finished ())
+ if (bp_num_range.first == 0)
+ {
+ warning (_("bad breakpoint number at or near '%d'"),
+ bp_num_range.first);
+ }
+ else
{
- const char *p = parser.cur_tok ();
- bool match = false;
+ struct breakpoint *b, *tmp;
- num = parser.get_number ();
- if (num == 0)
- {
- warning (_("bad breakpoint number at or near '%s'"), p);
- }
- else
+ for (int i = bp_num_range.first; i <= bp_num_range.second; i++)
{
+ bool match = false;
+
ALL_BREAKPOINTS_SAFE (b, tmp)
- if (b->number == num)
+ if (b->number == i)
{
match = true;
function (b);
break;
}
if (!match)
- printf_unfiltered (_("No breakpoint number %d.\n"), num);
+ printf_unfiltered (_("No breakpoint number %d.\n"), i);
}
}
}
+/* Call FUNCTION on each of the breakpoints whose numbers are given in
+ ARGS. */
+
+static void
+map_breakpoint_numbers (const char *args,
+ gdb::function_view<void (breakpoint *)> function)
+{
+ if (args == NULL || *args == '\0')
+ error_no_arg (_("one or more breakpoint numbers"));
+
+ number_or_range_parser parser (args);
+
+ while (!parser.finished ())
+ {
+ int num = parser.get_number ();
+ map_breakpoint_number_range (std::make_pair (num, num), function);
+ }
+}
+
+/* Return the breakpoint location structure corresponding to the
+ BP_NUM and LOC_NUM values. */
+
static struct bp_location *
-find_location_by_number (const char *number)
+find_location_by_number (int bp_num, int loc_num)
{
- const char *p1;
- int bp_num;
- int loc_num;
struct breakpoint *b;
- struct bp_location *loc;
-
- p1 = number;
- bp_num = get_number_trailer (&p1, '.');
- if (bp_num == 0 || p1[0] != '.')
- error (_("Bad breakpoint number '%s'"), number);
ALL_BREAKPOINTS (b)
if (b->number == bp_num)
@@ -14192,25 +14199,153 @@ find_location_by_number (const char *number)
}
if (!b || b->number != bp_num)
- error (_("Bad breakpoint number '%s'"), number);
+ error (_("Bad breakpoint number '%d'"), bp_num);
- /* Skip the dot. */
- ++p1;
- const char *save = p1;
- loc_num = get_number (&p1);
if (loc_num == 0)
- error (_("Bad breakpoint location number '%s'"), number);
+ error (_("Bad breakpoint location number '%d'"), loc_num);
- --loc_num;
- loc = b->loc;
- for (;loc_num && loc; --loc_num, loc = loc->next)
- ;
- if (!loc)
- error (_("Bad breakpoint location number '%s'"), save);
-
- return loc;
+ int n = 0;
+ for (bp_location *loc = b->loc; loc != NULL; loc = loc->next)
+ if (++n == loc_num)
+ return loc;
+
+ error (_("Bad breakpoint location number '%d'"), loc_num);
}
+/* Extract the breakpoint/location range specified by ARG. Returns
+ the breakpoint range in BP_NUM_RANGE, and the location range in
+ BP_LOC_RANGE.
+
+ ARG may be in any of the following forms:
+
+ x where 'x' is a breakpoint number.
+ x-y where 'x' and 'y' specify a breakpoint numbers range.
+ x.y where 'x' is a breakpoint number and 'y' a location number.
+ x.y-z where 'x' is a breakpoint number and 'y' and 'z' specify a
+ location number range.
+*/
+
+static bool
+extract_bp_number_and_location (const std::string &arg,
+ std::pair<int, int> &bp_num_range,
+ std::pair<int, int> &bp_loc_range)
+{
+ std::string::size_type dot = arg.find ('.');
+
+ if (dot != std::string::npos)
+ {
+ /* Handle 'x.y' and 'x.y-z' cases. */
+
+ if (arg.length () == dot + 1 || dot == 0)
+ error (_("bad breakpoint number at or near: '%s'"), arg.c_str ());
+
+ const char *ptb = arg.c_str ();
+ int bp_num = get_number_trailer (&ptb, '.');
+ if (bp_num == 0)
+ error (_("Bad breakpoint number '%s'"), arg.c_str ());
+
+ bp_num_range.first = bp_num;
+ bp_num_range.second = bp_num;
+
+ const char *bp_loc = &arg[dot + 1];
+ std::string::size_type dash = arg.find ('-', dot + 1);
+ if (dash != std::string::npos)
+ {
+ /* bp_loc is a range (x-z). */
+ if (arg.length () == dash + 1)
+ error (_("bad breakpoint number at or near: '%s'"), bp_loc);
+
+ const char *ptlf = bp_loc;
+ bp_loc_range.first = get_number_trailer (&ptlf, '-');
+
+ const char *ptls = &arg[dash + 1];
+ bp_loc_range.second = get_number_trailer (&ptls, '\0');
+ }
+ else
+ {
+ /* bp_loc is a single value. */
+ const char *ptls = bp_loc;
+ bp_loc_range.first = get_number_trailer (&ptls, '\0');
+ if (bp_loc_range.first == 0)
+ {
+ warning (_("bad breakpoint number at or near '%s'"), arg.c_str ());
+ return false;
+ }
+ bp_loc_range.second = bp_loc_range.first;
+ }
+ }
+ else
+ {
+ /* Handle x and x-y cases. */
+ std::string::size_type dash = arg.find ('-');
+ if (dash != std::string::npos)
+ {
+ if (arg.length () == dash + 1 || dash == 0)
+ error (_("bad breakpoint number at or near: '%s'"), arg.c_str ());
+
+ const char *ptf = arg.c_str ();
+ bp_num_range.first = get_number_trailer (&ptf, '-');
+
+ const char *pts = &arg[dash + 1];
+ bp_num_range.second = get_number_trailer (&pts, '\0');
+ }
+ else
+ {
+ const char *ptf = arg.c_str ();
+ bp_num_range.first = get_number (&ptf);
+ if (bp_num_range.first == 0)
+ {
+ warning (_("bad breakpoint number at or near '%s'"), arg.c_str ());
+ return false;
+ }
+ bp_num_range.second = bp_num_range.first;
+ }
+ bp_loc_range.first = 0;
+ bp_loc_range.second = 0;
+ }
+
+ if (bp_num_range.first == 0 || bp_num_range.second == 0)
+ error (_("bad breakpoint number at or near: '%s'"), arg.c_str ());
+
+ return true;
+}
+
+/* Enable or disable a breakpoint location BP_NUM.LOC_NUM. ENABLE
+ specifies whether to enable or disable. */
+
+static void
+enable_disable_bp_num_loc (int bp_num, int loc_num, bool enable)
+{
+ struct bp_location *loc = find_location_by_number (bp_num, loc_num);
+ if (loc != NULL)
+ {
+ if (loc->enabled != enable)
+ {
+ loc->enabled = enable;
+ mark_breakpoint_location_modified (loc);
+ }
+ if (target_supports_enable_disable_tracepoint ()
+ && current_trace_status ()->running && loc->owner
+ && is_tracepoint (loc->owner))
+ target_disable_tracepoint (loc);
+ }
+ update_global_location_list (UGLL_DONT_INSERT);
+}
+
+/* Enable or disable a range of breakpoint locations. BP_NUM is the
+ number of the breakpoint, and BP_LOC_RANGE specifies the
+ (inclusive) range of location numbers of that breakpoint to
+ enable/disable. ENABLE specifies whether to enable or disable the
+ location. */
+
+static void
+enable_disable_breakpoint_location_range (int bp_num,
+ std::pair<int, int> &bp_loc_range,
+ bool enable)
+{
+ for (int i = bp_loc_range.first; i <= bp_loc_range.second; i++)
+ enable_disable_bp_num_loc (bp_num, i, enable);
+}
/* Set ignore-count of breakpoint number BPTNUM to COUNT.
If from_tty is nonzero, it prints a message to that effect,
@@ -14244,8 +14379,13 @@ disable_breakpoint (struct breakpoint *bpt)
observer_notify_breakpoint_modified (bpt);
}
+/* Enable or disable the breakpoint(s) or breakpoint location(s)
+ specified in ARGS. ARGS may be in any of the formats handled by
+ extract_bp_number_and_location. ENABLE specifies whether to enable
+ or disable the breakpoints/locations. */
+
static void
-disable_command (const char *args, int from_tty)
+enable_disable_command (const char *args, int from_tty, bool enable)
{
if (args == 0)
{
@@ -14253,7 +14393,12 @@ disable_command (const char *args, int from_tty)
ALL_BREAKPOINTS (bpt)
if (user_breakpoint_p (bpt))
- disable_breakpoint (bpt);
+ {
+ if (enable)
+ enable_breakpoint (bpt);
+ else
+ disable_breakpoint (bpt);
+ }
}
else
{
@@ -14261,35 +14406,43 @@ disable_command (const char *args, int from_tty)
while (!num.empty ())
{
- if (num.find ('.') != std::string::npos)
- {
- struct bp_location *loc = find_location_by_number (num.c_str ());
+ std::pair<int, int> bp_num_range, bp_loc_range;
- if (loc)
+ if (extract_bp_number_and_location (num, bp_num_range, bp_loc_range))
+ {
+ if (bp_loc_range.first == bp_loc_range.second
+ && bp_loc_range.first == 0)
{
- if (loc->enabled)
- {
- loc->enabled = 0;
- mark_breakpoint_location_modified (loc);
- }
- if (target_supports_enable_disable_tracepoint ()
- && current_trace_status ()->running && loc->owner
- && is_tracepoint (loc->owner))
- target_disable_tracepoint (loc);
+ /* Handle breakpoint ids with formats 'x' or 'x-z'. */
+ map_breakpoint_number_range (bp_num_range,
+ enable
+ ? enable_breakpoint
+ : disable_breakpoint);
+ }
+ else
+ {
+ /* Handle breakpoint ids with formats 'x.y' or
+ 'x.y-z'. */
+ enable_disable_breakpoint_location_range
+ (bp_num_range.first, bp_loc_range, enable);
}
- update_global_location_list (UGLL_DONT_INSERT);
}
- else
- map_breakpoint_numbers
- (num.c_str (), [&] (breakpoint *b)
- {
- iterate_over_related_breakpoints (b, disable_breakpoint);
- });
num = extract_arg (&args);
}
}
}
+/* The disable command disables the specified breakpoints/locations
+ (or all defined breakpoints) so they're no longer effective in
+ stopping the inferior. ARGS may be in any of the forms defined in
+ extract_bp_number_and_location. */
+
+static void
+disable_command (const char *args, int from_tty)
+{
+ enable_disable_command (args, from_tty, false);
+}
+
static void
enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition,
int count)
@@ -14360,54 +14513,15 @@ enable_breakpoint (struct breakpoint *bpt)
enable_breakpoint_disp (bpt, bpt->disposition, 0);
}
-/* The enable command enables the specified breakpoints (or all defined
- breakpoints) so they once again become (or continue to be) effective
- in stopping the inferior. */
+/* The enable command enables the specified breakpoints/locations (or
+ all defined breakpoints) so they once again become (or continue to
+ be) effective in stopping the inferior. ARGS may be in any of the
+ forms defined in extract_bp_number_and_location. */
static void
enable_command (const char *args, int from_tty)
{
- if (args == 0)
- {
- struct breakpoint *bpt;
-
- ALL_BREAKPOINTS (bpt)
- if (user_breakpoint_p (bpt))
- enable_breakpoint (bpt);
- }
- else
- {
- std::string num = extract_arg (&args);
-
- while (!num.empty ())
- {
- if (num.find ('.') != std::string::npos)
- {
- struct bp_location *loc = find_location_by_number (num.c_str ());
-
- if (loc)
- {
- if (!loc->enabled)
- {
- loc->enabled = 1;
- mark_breakpoint_location_modified (loc);
- }
- if (target_supports_enable_disable_tracepoint ()
- && current_trace_status ()->running && loc->owner
- && is_tracepoint (loc->owner))
- target_enable_tracepoint (loc);
- }
- update_global_location_list (UGLL_MAY_INSERT);
- }
- else
- map_breakpoint_numbers
- (num.c_str (), [&] (breakpoint *b)
- {
- iterate_over_related_breakpoints (b, enable_breakpoint);
- });
- num = extract_arg (&args);
- }
- }
+ enable_disable_command (args, from_tty, true);
}
static void
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index e3ea4ec..98eab72 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,9 @@
+2017-11-07 Xavier Roirand <roirand@adacore.com>
+ Pedro Alves <palves@redhat.com>
+
+ * gdb.texinfo (Set Breaks): Document support for breakpoint
+ location ranges in the enable/disable commands.
+
2017-10-04 Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.texinfo (Starting your Program) <The working directory.>:
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index bfeb7a9..29d4789 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3927,15 +3927,17 @@ Num Type Disp Enb Address What
1.2 y 0x080486ca in void foo<double>() at t.cc:8
@end smallexample
-Each location can be individually enabled or disabled by passing
+You cannot delete the individual locations from a breakpoint. However,
+each location can be individually enabled or disabled by passing
@var{breakpoint-number}.@var{location-number} as argument to the
-@code{enable} and @code{disable} commands. Note that you cannot
-delete the individual locations from the list, you can only delete the
-entire list of locations that belong to their parent breakpoint (with
-the @kbd{delete @var{num}} command, where @var{num} is the number of
-the parent breakpoint, 1 in the above example). Disabling or enabling
-the parent breakpoint (@pxref{Disabling}) affects all of the locations
-that belong to that breakpoint.
+@code{enable} and @code{disable} commands. It's also possible to
+@code{enable} and @code{disable} a range of @var{location-number}
+locations using a @var{breakpoint-number} and two @var{location-number}s,
+in increasing order, separated by a hyphen, like
+@kbd{@var{breakpoint-number}.@var{location-number1}-@var{location-number2}},
+in which case @value{GDBN} acts on all the locations in the range (inclusive).
+Disabling or enabling the parent breakpoint (@pxref{Disabling}) affects
+all of the locations that belong to that breakpoint.
@cindex pending breakpoints
It's quite common to have a breakpoint inside a shared library.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 371e98b..6468e52 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2017-11-07 Xavier Roirand <roirand@adacore.com>
+ Pedro Alves <palves@redhat.com>
+
+ * gdb.base/ena-dis-br.exp: Add reference to
+ gdb.cp/ena-dis-br-range.exp.
+ * gdb.cp/ena-dis-br-range.exp: New file.
+ * gdb.cp/ena-dis-br-range.cc: New file.
+
2017-11-06 Pedro Alves <palves@redhat.com>
* gdb.base/attach-non-pgrp-leader.c: New.
diff --git a/gdb/testsuite/gdb.base/ena-dis-br.exp b/gdb/testsuite/gdb.base/ena-dis-br.exp
index d407408..9b8d251 100644
--- a/gdb/testsuite/gdb.base/ena-dis-br.exp
+++ b/gdb/testsuite/gdb.base/ena-dis-br.exp
@@ -324,6 +324,9 @@ set b4 [break_at main ""]
#
# WHAT - the command to test (disable/enable).
#
+# Note: tests involving location ranges (and more) are found in
+# gdb.cp/ena-dis-br-range.exp.
+#
proc test_ena_dis_br { what } {
global b1
global b2
diff --git a/gdb/testsuite/gdb.cp/ena-dis-br-range.cc b/gdb/testsuite/gdb.cp/ena-dis-br-range.cc
new file mode 100644
index 0000000..9469e34
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ena-dis-br-range.cc
@@ -0,0 +1,66 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2017 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* Some overloaded functions to test breakpoints with multiple
+ locations. */
+
+class foo
+{
+public:
+ static void overload (void);
+ static void overload (char);
+ static void overload (int);
+ static void overload (double);
+};
+
+void
+foo::overload ()
+{
+}
+
+void
+foo::overload (char arg)
+{
+}
+
+void
+foo::overload (int arg)
+{
+}
+
+void
+foo::overload (double arg)
+{
+}
+
+void
+marker ()
+{
+}
+
+int
+main ()
+{
+ foo::overload ();
+ foo::overload (111);
+ foo::overload ('h');
+ foo::overload (3.14);
+
+ marker ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/ena-dis-br-range.exp b/gdb/testsuite/gdb.cp/ena-dis-br-range.exp
new file mode 100644
index 0000000..8873c4a
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ena-dis-br-range.exp
@@ -0,0 +1,132 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# 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, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test the enable/disable commands with breakpoint location ranges.
+
+# Note: more tests involving involving disable/enable commands on
+# multiple locations and breakpoints are found in
+# gdb.base/ena-dis-br.exp.
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile .cc
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
+ return -1
+}
+
+if ![runto 'marker'] then {
+ fail "run to marker"
+ return -1
+}
+
+# Returns a buffer corresponding to what GDB replies when asking for
+# 'info breakpoint'. The parameters are all the existing breakpoints
+# enabled/disable value: 'n' or 'y'.
+
+proc make_info_breakpoint_reply_re {b1 b2 b21 b22 b23 b24} {
+ set ws "\[\t \]+"
+ return [multi_line \
+ "Num Type${ws}Disp Enb Address${ws}What.*" \
+ "1${ws}breakpoint keep ${b1}${ws}.* in marker\\(\\) at .*" \
+ "${ws}breakpoint already hit 1 time.*" \
+ "2${ws}breakpoint${ws}keep${ws}${b2}${ws}<MULTIPLE>.*" \
+ "2.1${ws}${b21}.*" \
+ "2.2${ws}${b22}.*" \
+ "2.3${ws}${b23}.*" \
+ "2.4${ws}${b24}.*" \
+ ]
+}
+
+gdb_test "break foo::overload" \
+ "Breakpoint \[0-9\]+ at $hex: foo::overload. .4 locations." \
+ "set breakpoint at overload"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
+ "breakpoint info"
+
+# Test the enable/disable commands, and check the enable/disable state
+# of the breakpoints/locations in the "info break" output. CMD is the
+# actual disable/enable command. The bNN parameters are the same as
+# make_info_breakpoint_reply_re's.
+proc test_enable_disable {cmd b1 b2 b21 b22 b23 b24} {
+ gdb_test_no_output $cmd
+
+ set re [make_info_breakpoint_reply_re $b1 $b2 $b21 $b22 $b23 $b24]
+ gdb_test "info break" $re "breakpoint info $cmd"
+}
+
+# Check that we can disable/enable a breakpoint with a single
+# location.
+test_enable_disable "disable 1" n y y y y y
+test_enable_disable "enable 1" y y y y y y
+
+# Check that we can disable/disable a breakpoint with multiple
+# locations.
+test_enable_disable "disable 2" y n y y y y
+test_enable_disable "enable 2" y y y y y y
+
+# Check that we can disable/enable a single location breakpoint.
+test_enable_disable "disable 2.2" y y y n y y
+test_enable_disable "enable 2.2" y y y y y y
+
+# Check that we can disable/enable a range of breakpoint locations.
+test_enable_disable "disable 2.2-3" y y y n n y
+test_enable_disable "enable 2.2-3" y y y y y y
+
+# Check that we can disable/enable a breakpoint location range with
+# START==END.
+test_enable_disable "disable 2.2-2" y y y n y y
+test_enable_disable "enable 2.2-2" y y y y y y
+
+# Check that we can disable a location breakpoint range with max >
+# existing breakpoint location.
+gdb_test "disable 2.3-5" "Bad breakpoint location number '5'" \
+ "disable location breakpoint range with max > existing"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y n n] \
+ "breakpoint info disable 2.3 to 2.5"
+
+# Check that we can enable a location breakpoint range with max >
+# existing breakpoint location.
+gdb_test "enable 2.3-5" "Bad breakpoint location number '5'" \
+ "enable location breakpoint range with max > existing"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
+ "breakpoint info enable 2.3 to 2.5"
+
+# Check that disabling an reverse location breakpoint range does not
+# work.
+gdb_test_no_output "disable 2.3-2"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
+ "breakpoint info disable 2.3-2"
+
+# Check that disabling an invalid breakpoint location range does not
+# cause unexpected behavior.
+gdb_test "disable 2.6-7" "Bad breakpoint location number '6'" \
+ "disable an unvalid location breakpoint range"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
+ "breakpoint info disable 2.6-7"
+
+# Check that disabling an invalid breakpoint location range does not
+# cause trouble.
+gdb_test_no_output "disable 2.8-6"
+
+gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
+ "breakpoint info disable 2.8-6"