[v6,1/2] gdb: extend gdb_breakpoint for multiple locations

Message ID 20240930060102.752079-2-klaus.gerlicher@intel.com
State New
Headers
Series gdb: setting BP with multiple locations only displays one location |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Gerlicher, Klaus Sept. 30, 2024, 6:01 a.m. UTC
  From: "Gerlicher, Klaus" <klaus.gerlicher@intel.com>

Many tests have gdb_test "break..." style testing which
could be more generically handled by gdb_breakpoint.

This, for example

gdb_test "break func2" \
    "Breakpoint.*at.*func2.*\\(2 locations\\)"

becomes

gdb_breakpoint "func2" -locs 2

where -locs specifies that gdb_breakpoint should try to match
to 2 locations in the "break" output.

Extend gdb_breakpoint with options for matching multiple
breakpoint locations.

Also remove one historical stale comment and trailing space
and indent issues.
---
 gdb/testsuite/gdb.ada/bp_inlined_func.exp     |  4 +-
 gdb/testsuite/gdb.ada/homonym.exp             |  8 +-
 gdb/testsuite/gdb.ada/operator_bp.exp         | 18 +---
 .../gdb.base/condbreak-multi-context.exp      | 22 ++---
 gdb/testsuite/gdb.base/dtrace-probe.exp       |  4 +-
 gdb/testsuite/gdb.base/foll-fork.exp          |  7 +-
 gdb/testsuite/gdb.base/msym-bp-shl.exp        |  4 +-
 gdb/testsuite/gdb.base/msym-bp.exp            |  2 +-
 gdb/testsuite/gdb.base/solib-symbol.exp       |  4 +-
 gdb/testsuite/gdb.base/stap-probe.exp         |  8 +-
 gdb/testsuite/gdb.base/step-over-exit.exp     |  2 +-
 gdb/testsuite/gdb.cp/breakpoint-locs.exp      |  2 +-
 gdb/testsuite/gdb.cp/ena-dis-br-range.exp     |  4 +-
 gdb/testsuite/gdb.cp/mb-ctor.exp              |  8 +-
 gdb/testsuite/gdb.cp/mb-inline.exp            |  8 +-
 gdb/testsuite/gdb.cp/mb-templates.exp         | 12 +--
 gdb/testsuite/gdb.cp/meth-typedefs.exp        |  2 +-
 gdb/testsuite/gdb.cp/ovldbreak.exp            |  4 +-
 gdb/testsuite/gdb.cp/paramless.exp            |  4 +-
 gdb/testsuite/gdb.cp/templates.exp            | 20 ++--
 gdb/testsuite/gdb.dwarf2/dw2-inline-break.exp | 20 ++--
 .../gdb.dwarf2/dw2-skip-prologue.exp          |  2 +-
 gdb/testsuite/gdb.linespec/break-asm-file.exp |  4 +-
 gdb/testsuite/gdb.linespec/linespec.exp       | 20 +---
 .../gdb.multi/bp-thread-specific.exp          |  6 +-
 .../gdb.multi/inferior-specific-bp.exp        |  3 +-
 gdb/testsuite/gdb.opt/inline-break.exp        | 23 ++---
 gdb/testsuite/gdb.python/py-bp-locations.exp  |  2 +-
 gdb/testsuite/lib/gdb.exp                     | 92 ++++++++++++++++---
 29 files changed, 154 insertions(+), 165 deletions(-)
  

Patch

diff --git a/gdb/testsuite/gdb.ada/bp_inlined_func.exp b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
index db56a11d12a..028863af3fc 100644
--- a/gdb/testsuite/gdb.ada/bp_inlined_func.exp
+++ b/gdb/testsuite/gdb.ada/bp_inlined_func.exp
@@ -32,9 +32,7 @@  if {![runto_main]} {
 # Check that inserting breakpoint on read_small inlined function inserts
 # 4 breakpoints (or possibly 5, including the read_small function itself).
 
-gdb_test "break read_small" \
-         "Breakpoint $decimal at $hex: read_small\\. \\(\[45\] locations\\)" \
-         "set breakpoint at read_small"
+gdb_breakpoint "read_small" -locs "\[45\]"
 
 # We do not verify each breakpoint info, but use continue commands instead
 # to verify that we properly stop on each expected breakpoint.
diff --git a/gdb/testsuite/gdb.ada/homonym.exp b/gdb/testsuite/gdb.ada/homonym.exp
index 91a4e62e61f..dac20ad1cc4 100644
--- a/gdb/testsuite/gdb.ada/homonym.exp
+++ b/gdb/testsuite/gdb.ada/homonym.exp
@@ -29,13 +29,9 @@  clean_restart ${testfile}
 # Do these tests before running, so we are operating in a known
 # environment.
 
-gdb_test "break Get_Value" \
-    "Breakpoint \[0-9\]+ at $hex: Get_Value. .2 locations." \
-    "set breakpoint at Get_Value"
+gdb_breakpoint "Get_Value" -locs 2
 
-gdb_test "break homonym.adb:Get_Value" \
-    "Breakpoint \[0-9\]+ at $hex: homonym.adb:Get_Value. .2 locations." \
-    "set breakpoint at homonym.adb:Get_Value"
+gdb_breakpoint "homonym.adb:Get_Value" -locs 2
 
 gdb_test "break <homonym__get_value>" \
     "Breakpoint \[0-9\]+ at $hex: file .*homonym\\.adb, line $decimal\\." \
diff --git a/gdb/testsuite/gdb.ada/operator_bp.exp b/gdb/testsuite/gdb.ada/operator_bp.exp
index 2335d492798..d3f78ee6fe6 100644
--- a/gdb/testsuite/gdb.ada/operator_bp.exp
+++ b/gdb/testsuite/gdb.ada/operator_bp.exp
@@ -33,22 +33,12 @@  runto "ops_test.adb:$bp_location"
 
 # Set breakpoints for all operators, using just the operator name in quotes.
 
-set bp_re "Breakpoint $decimal at $hex"
 foreach op { "+" "-" } {
-    set op_re [string_to_regexp $op]
-    gdb_test "break \"$op\"" "$bp_re: \"$op_re\"\\. \\($decimal locations\\).*"
+    gdb_breakpoint "\"$op\"" -locs $::decimal
 }
 
 foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
-    set op_re [string_to_regexp $op]
-    gdb_test_multiple "break \"$op\"" "" {
-	-re -wrap "$bp_re: file .*ops.adb, line $decimal." {
-	    pass $gdb_test_name
-	}
-	-re -wrap "$bp_re: \"$op_re\"\\. \\($decimal locations\\).*" {
-	    pass $gdb_test_name
-	}
-    }
+    gdb_breakpoint "\"$op\""
 }
 
 # Make sure we stop correctly in each operator function.
@@ -70,9 +60,7 @@  runto "ops_test.adb:$bp_location"
 # Set breakpoints for all operators, using just the operator name in quotes.
 
 foreach op { "+" "-" } {
-    set op_re [string_to_regexp $op]
-    gdb_test "break ops.\"$op\"" \
-             "Breakpoint $decimal at $hex: ops\\.\"$op_re\"\\. \\(2 locations\\)"
+    gdb_breakpoint "ops.\"$op\"" -locs 2
 }
 
 foreach op { "*" "/" "mod" "rem" "**" "<" "<=" ">" ">=" "=" "and" "or" "xor" "&" "abs" "not"} {
diff --git a/gdb/testsuite/gdb.base/condbreak-multi-context.exp b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
index 3af37081e44..b7114e9cdf5 100644
--- a/gdb/testsuite/gdb.base/condbreak-multi-context.exp
+++ b/gdb/testsuite/gdb.base/condbreak-multi-context.exp
@@ -109,24 +109,22 @@  with_test_prefix "scenario 1" {
     # and C::func) should be disabled.  We do not test location
     # indices strictly at this moment, because we don't know them,
     # yet.  We have strict location index tests below.
-    gdb_test "break func if a == 10" \
-	[multi_line \
+    set extra [multi_line \
 	     "${warning} at location $decimal, disabling:" \
 	     "  No symbol \"a\" in current context." \
 	     "${warning} at location $decimal, disabling:" \
-	     "  No symbol \"a\" in current context." \
-	     "Breakpoint $decimal at $fill .3 locations."] \
-	"define bp with condition a == 10"
+	     "  No symbol \"a\" in current context."]
+    gdb_breakpoint "func if a == 10" -locs 3 -extra $extra
+
     set bpnum1 [get_integer_valueof "\$bpnum" 0 "get bpnum1"]
 
-    gdb_test "break func if c == 30" \
-	[multi_line \
-	     ".*${warning} at location $decimal, disabling:" \
-	     "  No symbol \"c\" in current context." \
-	     ".*${warning} at location $decimal, disabling:" \
+    set extra [multi_line \
+	     "${warning} at location $decimal, disabling:" \
 	     "  No symbol \"c\" in current context." \
-	     ".*Breakpoint $decimal at $fill .3 locations."] \
-	"define bp with condition c == 30"
+	     "${warning} at location $decimal, disabling:" \
+	     "  No symbol \"c\" in current context."]
+    gdb_breakpoint "func if c == 30" -locs 3 -extra $extra
+
     set bpnum2 [get_integer_valueof "\$bpnum" 0 "get bpnum2"]
 
     find_location_contexts
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.exp b/gdb/testsuite/gdb.base/dtrace-probe.exp
index a8c38f91fb6..2824b6ad27c 100644
--- a/gdb/testsuite/gdb.base/dtrace-probe.exp
+++ b/gdb/testsuite/gdb.base/dtrace-probe.exp
@@ -92,9 +92,7 @@  proc dtrace_test {} {
         "print \$_probe_arg1 for probe progress-counter"
 
     # Set a breakpoint with multiple probe locations.
-    gdb_test "break -pdtrace test:two-locations" \
-        "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
-        "set multi-location probe breakpoint (probe two-locations)"
+    gdb_breakpoint "-pdtrace test:two-locations" -locs 2
 
     return 0
 }
diff --git a/gdb/testsuite/gdb.base/foll-fork.exp b/gdb/testsuite/gdb.base/foll-fork.exp
index 0d801f004e4..177bc71f9bc 100644
--- a/gdb/testsuite/gdb.base/foll-fork.exp
+++ b/gdb/testsuite/gdb.base/foll-fork.exp
@@ -183,11 +183,8 @@  proc_with_prefix test_follow_fork { follow-fork-mode detach-on-fork cmd } {
     # locations it means there are two program spaces.
     if {${detach-on-fork} == "off" || ${follow-fork-mode} == "child"} {
 	set bpnum "<unset>"
-	gdb_test_multiple "break callee" "break callee" {
-	    -re -wrap "Breakpoint ($::decimal) at $::hex: callee\\. \\(2 locations\\)" {
-		set bpnum $expect_out(1,string)
-		pass $gdb_test_name
-	    }
+	if { [gdb_breakpoint "callee" -locs 2] } {
+	    set bpnum [get_integer_valueof "\$bpnum" 0 "get bpnum"]
 	}
 
 	set any {[^\r\n]+}
diff --git a/gdb/testsuite/gdb.base/msym-bp-shl.exp b/gdb/testsuite/gdb.base/msym-bp-shl.exp
index 31af1f90f31..f7e14c44f51 100644
--- a/gdb/testsuite/gdb.base/msym-bp-shl.exp
+++ b/gdb/testsuite/gdb.base/msym-bp-shl.exp
@@ -61,7 +61,7 @@  proc test {debug} {
     # Should find two locations: the static foo in the
     # msym-bp-shl-main-2 file, and <foo@plt>, both in the main binary.
     with_test_prefix "before run" {
-	gdb_test "break foo" "\\(2 locations\\)"
+	gdb_breakpoint "foo" -locs 2
 
 	if {$debug} {
 	    test_info_break_2 \
@@ -85,7 +85,7 @@  proc test {debug} {
     # foo in the msym-bp-shl-main-2 file, and the extern foo in the
     # shared library.
     with_test_prefix "at main" {
-	gdb_test "break foo" "\\(2 locations\\)"
+	gdb_breakpoint "foo" -locs 2
 
 	if {$debug} {
 	    test_info_break_2 \
diff --git a/gdb/testsuite/gdb.base/msym-bp.exp b/gdb/testsuite/gdb.base/msym-bp.exp
index 84d29020900..bf9621ad706 100644
--- a/gdb/testsuite/gdb.base/msym-bp.exp
+++ b/gdb/testsuite/gdb.base/msym-bp.exp
@@ -52,7 +52,7 @@  proc test {debug} {
 	upvar debug debug
 
 	with_test_prefix $prefix {
-	    gdb_test "break foo" "\\(2 locations\\)"
+	    gdb_breakpoint "foo" -locs 2
 
 	    if {$debug} {
 		test_info_break_2 \
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index 1ec386703cf..6759156ef83 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -57,8 +57,6 @@  gdb_test "continue" \
 	 "Continuing.*"
 
 # This symbol is now looked up in the ELF library and the binary.
-gdb_test "br foo2" \
-	 "Breakpoint.*: foo2. .2 locations..*" \
-	 "foo2 in mdlib"
+gdb_breakpoint "foo2" -locs 2
 
 gdb_exit
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
index 40e8c5e06f3..42b91cfe971 100644
--- a/gdb/testsuite/gdb.base/stap-probe.exp
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -181,9 +181,7 @@  proc stap_test {exec_name {args ""}} {
     	"check \$_probe_arg1 for probe user"
 
     # Set a breakpoint with multiple probe locations.
-    gdb_test "break -pstap test:two" \
-	"Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
-	"set multi-location probe breakpoint (probe two)"
+    gdb_breakpoint "-pstap test:two" -locs 2
 
     # Reinit GDB, set a breakpoint on probe m4.
     delete_breakpoints
@@ -273,9 +271,7 @@  proc stap_test_no_debuginfo {exec_name {args ""}} {
     # Set a breakpoint with multiple probe locations.
     # In this scenario, we may expect more than 2 locations because of
     # the optimizations (inlining, loop unrolling, etc).
-    gdb_test "break -pstap test:two" \
-	"Breakpoint .* at $hex.*\[0-9\]+ locations.*" \
-	"set multi-location probe breakpoint (probe two)"
+    gdb_breakpoint "-pstap test:two"  -locs "\[0-9\]+"
 
     # Reinit GDB, set a breakpoint on probe m4.
     delete_breakpoints
diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp
index d373b1a28ad..7c657c7f0f8 100644
--- a/gdb/testsuite/gdb.base/step-over-exit.exp
+++ b/gdb/testsuite/gdb.base/step-over-exit.exp
@@ -44,7 +44,7 @@  gdb_test "set detach-on-fork off"
 
 # Step 1, find the syscall instruction address.
 
-gdb_test "break _exit" "Breakpoint $decimal at .*"
+gdb_breakpoint "_exit"
 
 # Hit the breakpoint on _exit.  The address of syscall insn is recorded.
 
diff --git a/gdb/testsuite/gdb.cp/breakpoint-locs.exp b/gdb/testsuite/gdb.cp/breakpoint-locs.exp
index 088a7660276..e873a97356e 100644
--- a/gdb/testsuite/gdb.cp/breakpoint-locs.exp
+++ b/gdb/testsuite/gdb.cp/breakpoint-locs.exp
@@ -26,4 +26,4 @@  if { [prepare_for_testing "failed to prepare" $testfile "$srcfile $srcfile2"\
     return -1
 }
 
-gdb_test "break N1::C1::baz" "\\(2 locations\\)"
+gdb_breakpoint "N1::C1::baz" -locs 2
diff --git a/gdb/testsuite/gdb.cp/ena-dis-br-range.exp b/gdb/testsuite/gdb.cp/ena-dis-br-range.exp
index 103d38baa2f..0bd1d2e1c0d 100644
--- a/gdb/testsuite/gdb.cp/ena-dis-br-range.exp
+++ b/gdb/testsuite/gdb.cp/ena-dis-br-range.exp
@@ -51,9 +51,7 @@  proc make_info_breakpoint_reply_re {b1 b2 b21 b22 b23 b24} {
 	       ]
 }
 
-gdb_test "break foo::overload" \
-    "Breakpoint \[0-9\]+ at $hex: foo::overload. .4 locations." \
-    "set breakpoint at overload"
+gdb_breakpoint "foo::overload" -locs 4
 
 gdb_test "info break" [make_info_breakpoint_reply_re y y y y y y] \
     "breakpoint info"
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 1a84b7990f4..0367e5399f8 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -38,15 +38,11 @@  if {![runto_main]} {
 # Set a breakpoint with multiple locations
 # and a condition.
 
-gdb_test "break 'Derived::Derived(int)'" \
-    "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
-    "set-breakpoint at ctor"
+gdb_breakpoint "'Derived::Derived(int)'" -locs 2
 
 gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
 
-gdb_test "break 'Derived::~Derived()'" \
-    "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
-    "set-breakpoint at dtor"
+gdb_breakpoint "'Derived::~Derived()'" -locs 2
 
 gdb_test "continue" \
     ".*Breakpoint.*Derived.*i=7.*" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index db80bb48e40..f34a12e4953 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -33,9 +33,7 @@  set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
 
 # Set a breakpoint with multiple locations.
 
-gdb_test "break $hdrfile:$bp_location" \
-    "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
-    "set breakpoint"
+gdb_breakpoint "$hdrfile:$bp_location" -locs 2
 
 # Do "info break" now so we can easily compare it with the later "info break"
 # if problems arise.
@@ -83,9 +81,7 @@  if { ![runto_main] } {
     return 0
 }
 
-gdb_test "break $hdrfile:$bp_location" \
-    "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
-    "set multi_line_foo breakpoint"
+gdb_breakpoint "$hdrfile:$bp_location" -locs 2
 gdb_test "continue" \
     ".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
     "run to multi_line_foo breakpoint 4 afn"
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 2df88a322bb..0ab5d7cba7d 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -30,9 +30,7 @@  set bp_location [gdb_get_line_number "set breakpoint here"]
 # Set a breakpoint with multiple locations
 # and a condition.
 
-gdb_test "break $srcfile:$bp_location if i==1" \
-    "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
-    "initial condition: set breakpoint"
+gdb_breakpoint "$srcfile:$bp_location if i==1" -locs 2
 
 gdb_run_cmd
 
@@ -55,9 +53,7 @@  delete_breakpoints
 gdb_test "kill" "" "kill" \
          {Kill the program being debugged\? \(y or n\) } "y"
 
-gdb_test "break $srcfile:$bp_location" \
-    "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
-    "separate condition: set breakpoint"
+gdb_breakpoint "$srcfile:$bp_location" -locs 2
 
 gdb_test_no_output {condition $bpnum i==1} \
     "separate condition: set condition"
@@ -111,9 +107,7 @@  if { ![runto_main] } {
     return 0
 }
 
-gdb_test "break $srcfile:$bp_location" \
-    "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
-    "set multi_line_foo breakpoint"
+gdb_breakpoint "break $srcfile:$bp_location" -locs 2
 gdb_test "continue" \
     ".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
     "run to multi_line_foo breakpoint 2 <int>"
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.exp b/gdb/testsuite/gdb.cp/meth-typedefs.exp
index 149f44c6c17..e544074402c 100644
--- a/gdb/testsuite/gdb.cp/meth-typedefs.exp
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -181,7 +181,7 @@  foreach f [list "$func" "'$func'"] {
 	     "$line3${any}// test${any}"]
 
     delete_breakpoints
-    gdb_test "break $f" "\\(3 locations\\)"
+    gdb_breakpoint "$f" -locs 3
 }
 
 gdb_exit
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index 99d0a388adb..84efb37b8db 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -443,9 +443,7 @@  gdb_test "break foo::foofunc" \
 # Test breaking on an overloaded function when multiple-symbols
 # is set to "all"
 gdb_test_no_output "set multiple-symbols all"
-gdb_test "break foo::foofunc" \
-    "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*" \
-    "break on ambiguous symbol when multiple-symbols is set to all"
+gdb_breakpoint "foo::foofunc" -locs 2
 
 # That's all, folks.
 
diff --git a/gdb/testsuite/gdb.cp/paramless.exp b/gdb/testsuite/gdb.cp/paramless.exp
index fe7c0b38748..d44c4f13073 100644
--- a/gdb/testsuite/gdb.cp/paramless.exp
+++ b/gdb/testsuite/gdb.cp/paramless.exp
@@ -36,10 +36,10 @@  delete_breakpoints
 gdb_breakpoint "outer<char>::fn<short>" message
 delete_breakpoints
 
-gdb_test "break outer::fn" "Breakpoint $decimal at .*2 locations."
+gdb_breakpoint "outer::fn" -locs 2
 delete_breakpoints
 
-gdb_test "break toplev" "Breakpoint $decimal at .*2 locations."
+gdb_breakpoint "toplev" -locs 2
 delete_breakpoints
 
 gdb_breakpoint "toplev<char>" message
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 8dd0cdc70ef..8cbc5547fce 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -620,25 +620,25 @@  gdb_test_no_output "set multiple-symbols all"
 
 # Test setting breakpoints in a method of all class template instantiations,
 # including overloads.
-gdb_test "break Foo::foo"  "Breakpoint.*at.* \\(3 locations\\)"
+gdb_breakpoint "Foo::foo" -locs 3
 foreach t [list "int" "char" "volatile char *"] {
     gdb_breakpoint "Foo<$t>::foo (int, $t)"
     gdb_breakpoint "Foo::foo (int, $t)"
 }
 
-gdb_test "break Bar::bar" "Breakpoint.*at.* \\(2 locations\\)"
-gdb_test "break Bar::bar (int, int)" "Breakpoint.*at.* \\(2 locations\\)"
+gdb_breakpoint "Bar::bar" -locs 2
+gdb_breakpoint "Bar::bar (int, int)" -locs 2
 foreach val [list 1 33] {
     gdb_breakpoint "Bar<int, $val>::bar (int, int)"
 }
 
 # Test setting breakpoints in a member function template of a class template,
 # including overloads.
-gdb_test "break Foozle::fogey" "Breakpoint.*at.* \\(9 locations\\)" \
-    "break at template method fogey"
+gdb_breakpoint "Foozle::fogey" -locs 9
+
 foreach t [list "int" "char" "Empty<int>"] {
-    gdb_test "break Foozle::fogey ($t)" "Breakpoint.*at.* \\(3 locations\\)"
-    gdb_test "break Foozle::fogey<$t>" "Breakpoint.*at.* \\(3 locations\\)"
+    gdb_breakpoint "Foozle::fogey ($t)" -locs 3
+    gdb_breakpoint "Foozle::fogey<$t>" -locs 3
     foreach u [list "int" "char" "Empty<int>"] {
 	gdb_breakpoint "Foozle<$t>::fogey<$u>" message
 	gdb_assert { [gdb_breakpoint "Foozle<$t>::fogey<$u> ($u)" no-message] } \
@@ -657,10 +657,8 @@  foreach t [list "int" "char" "Empty<int>"] {
 # operator<<:
 #   1. operator<< <Empty<int>>
 #   2. operator<< <Foozle<int>>
-gdb_test "break -source $srcfile -func operator<" \
-    "Breakpoint.*at.* \\(4 locations\\)"
-gdb_test "break -source $srcfile -func operator<<" \
-    "Breakpoint.*at.* \\(2 locations\\)"
+gdb_breakpoint "-source $srcfile -func operator<" -locs 4
+gdb_breakpoint "-source $srcfile -func operator<<" -locs 2
 foreach t [list "Empty" "Foozle"] {
     set tt "$t<int>"
     gdb_breakpoint "operator< <$tt>" message
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-inline-break.exp b/gdb/testsuite/gdb.dwarf2/dw2-inline-break.exp
index 2e6f7114c33..6371b629d9b 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-inline-break.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-inline-break.exp
@@ -44,8 +44,8 @@  gdb_test "break func1" \
 # The result should be a breakpoint with two locations: the
 # out-of-line function and the single inlined instance.
 #
-gdb_test "break func2" \
-    "Breakpoint.*at.*func2.*\\(2 locations\\)"
+gdb_breakpoint "func2" -locs 2
+
 
 #
 # func3b is a static inlined function that is called once from
@@ -62,8 +62,7 @@  gdb_test "break func3b" \
 # the inlined call to func4a in main, and the inlined instance
 # within the out-of-line func4a.
 #
-gdb_test "break func4b" \
-    "Breakpoint.*at.*func4b.*\\(2 locations\\)"
+gdb_breakpoint "func4b" -locs 2
 
 #
 # func5b is a non-static inlined function that is called once
@@ -71,8 +70,8 @@  gdb_test "break func4b" \
 # breakpoint with two locations: the out-of-line function and the
 # inlined instance within the inlined call to func5a in main.
 #
-gdb_test "break func5b" \
-    "Breakpoint.*at.*func5b.*\\(2 locations\\)"
+gdb_breakpoint "func5b" -locs 2
+
 #
 # func6b is a non-static inlined function that is called once from
 # within another non-static inlined function.  The result should be
@@ -80,8 +79,7 @@  gdb_test "break func5b" \
 # inlined instance within the out-of-line func6a, and the inlined
 # instance within the inlined call to func6a in main,
 #
-gdb_test "break func6b" \
-    "Breakpoint.*at.*func6b.*\\(3 locations\\)"
+gdb_breakpoint "func6b" -locs 3
 
 #
 # func7b is a static inlined function that is called twice: once from
@@ -89,8 +87,7 @@  gdb_test "break func6b" \
 # two locations: the inlined instance within the inlined instance of
 # func7a, and the inlined instance within main.
 #
-gdb_test "break func7b" \
-    "Breakpoint.*at.*func7b.*\\(2 locations\\)"
+gdb_breakpoint "func7b" -locs 2
 
 #
 # func8b is a non-static inlined function that is called twice: once
@@ -99,8 +96,7 @@  gdb_test "break func7b" \
 # within the inlined instance of func7a, and the inlined instance
 # within main.
 #
-gdb_test "break func8b" \
-    "Breakpoint.*at.*func8b.*\\(3 locations\\)"
+gdb_breakpoint "func8b" -locs 3
 
 #
 # func1 is a static inlined function.  The result should be that no
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.exp b/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.exp
index 78ac57439f3..f155245c000 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.exp
@@ -71,7 +71,7 @@  if ![runto_main] {
     return -1
 }
 
-gdb_breakpoint "func"
+gdb_breakpoint "func" -locs 2
 gdb_continue_to_breakpoint "func"
 
 # Sanity check GDB has really found 2 locations
diff --git a/gdb/testsuite/gdb.linespec/break-asm-file.exp b/gdb/testsuite/gdb.linespec/break-asm-file.exp
index 1044fc79a26..3977e6aac85 100644
--- a/gdb/testsuite/gdb.linespec/break-asm-file.exp
+++ b/gdb/testsuite/gdb.linespec/break-asm-file.exp
@@ -60,7 +60,5 @@  gdb_test "break b/$asm_file0:func" \
 
 gdb_test "delete 2"
 
-gdb_test "break $asm_file0:func" \
-    "Breakpoint 3 at 0x\[0-9a-fA-F\]+: .*$asm_file0.*(2 locations).*" \
-    "set a break-point at function in all instances for a selected ASM file."
+gdb_breakpoint "$asm_file0:func" -locs 2
 
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
index 576d788cae0..981cd4155c0 100644
--- a/gdb/testsuite/gdb.linespec/linespec.exp
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -144,17 +144,11 @@  if { [is_remote host] } {
     }
 }
 
-gdb_test "break thefile.cc:$l1" \
-    "Breakpoint $decimal at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
-    "multi-location break using file:line"
+gdb_breakpoint "thefile.cc:$l1" -locs 2
 
-gdb_test "break dupname" \
-    "Breakpoint $decimal at $hex: dupname. \[(\]2 locations\[)\]" \
-    "multi-location break using duplicate function name"
+gdb_breakpoint "dupname" -locs 2
 
-gdb_test "break dupname:label" \
-    "Breakpoint $decimal at $hex: dupname:label. \[(\]2 locations\[)\]" \
-    "multi-location break using duplicate function name and label"
+gdb_breakpoint "dupname:label" -locs 2
 
 # Testing if the "condition" command completes only the breakpoints,
 # not the locations.
@@ -165,9 +159,7 @@  gdb_test "break lspec.cc:nosuchfunction" \
     "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
     "set breakpoint on non-existent function"
 
-gdb_test "break NameSpace::overload" \
-    "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
-    "set breakpoint at all instances of NameSpace::overload"
+gdb_breakpoint "NameSpace::overload" -locs 3
 
 gdb_test "break lspec.cc:NameSpace::overload" \
     "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
@@ -210,6 +202,4 @@  gdb_test "file $binfile" \
     "Reading symbols from .*" \
     "set the new inferior file for linespec tests"
 
-gdb_test "break -q main" \
-    "Breakpoint \[0-9\]+ at $hex: -qualified main. .2 locations." \
-    "set breakpoint at main in both inferiors"
+gdb_breakpoint "-q main" -locs 2
diff --git a/gdb/testsuite/gdb.multi/bp-thread-specific.exp b/gdb/testsuite/gdb.multi/bp-thread-specific.exp
index c1d87521ee9..fbf86443e83 100644
--- a/gdb/testsuite/gdb.multi/bp-thread-specific.exp
+++ b/gdb/testsuite/gdb.multi/bp-thread-specific.exp
@@ -49,16 +49,14 @@  gdb_test "info threads" \
 # Set the first breakpoint.  Currently this is going to insert at two
 # locations ('foo' in both inferiors) even though only one of those
 # locations will ever trigger ('foo' in inferior 2).
-gdb_test "break foo thread 2.1" \
-    "Breakpoint $decimal at $hex: file \[^\r\n\]+$srcfile, line $decimal\\."
+gdb_breakpoint "foo thread 2.1" -locs 1
 
 set bpnum [get_integer_valueof "\$bpnum" "INVALID"]
 
 # Now set another breakpoint that will be at the same location as the
 # earlier breakpoint.  Check that the thread-id used when describing
 # the earlier breakpoints is correct.
-gdb_test "break foo thread 1.1" \
-    "Breakpoint $decimal at $hex: file \[^\r\n\]+$srcfile, line $decimal\\."
+gdb_breakpoint "foo thread 1.1" -locs 1
 
 # Save the breakpoints into a file.
 if {[is_remote host]} {
diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
index 52f84183589..28d0d90d056 100644
--- a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
+++ b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
@@ -105,8 +105,7 @@  proc check_info_breakpoints { testname bp_number expected_loc_count } {
 # Create an inferior-specific breakpoint.  Use gdb_test instead of
 # gdb_breakpoint here as we want to check the breakpoint was placed in
 # multiple locations.
-gdb_test "break foo inferior 1" \
-    "Breakpoint $decimal at $hex: foo\\. \\(2 locations\\)"
+gdb_breakpoint "foo inferior 1" -locs 2
 set bp_number [get_integer_valueof "\$bpnum" "INVALID" \
 		  "get b/p number for inferior specific breakpoint"]
 
diff --git a/gdb/testsuite/gdb.opt/inline-break.exp b/gdb/testsuite/gdb.opt/inline-break.exp
index 9c57d22404b..70549301964 100644
--- a/gdb/testsuite/gdb.opt/inline-break.exp
+++ b/gdb/testsuite/gdb.opt/inline-break.exp
@@ -96,8 +96,7 @@  gdb_test "break func1" \
 # The result should be a breakpoint with two locations: the
 # out-of-line function and the single inlined instance.
 #
-gdb_test "break func2" \
-    "Breakpoint.*at.*func2.*\\(2 locations\\)"
+gdb_breakpoint "func2" -locs 2
 
 #
 # func3b is a static inlined function that is called once from
@@ -114,8 +113,8 @@  gdb_test "break func3b" \
 # the inlined call to func4a in main, and the inlined instance
 # within the out-of-line func4a.
 #
-gdb_test "break func4b" \
-    "Breakpoint.*at.*func4b.*\\(2 locations\\)"
+gdb_breakpoint "func4b" -locs 2
+
 
 #
 # func5b is a non-static inlined function that is called once
@@ -123,8 +122,8 @@  gdb_test "break func4b" \
 # breakpoint with two locations: the out-of-line function and the
 # inlined instance within the inlined call to func5a in main.
 #
-gdb_test "break func5b" \
-    "Breakpoint.*at.*func5b.*\\(2 locations\\)"
+gdb_breakpoint "func5b" -locs 2
+
 #
 # func6b is a non-static inlined function that is called once from
 # within another non-static inlined function.  The result should be
@@ -132,8 +131,7 @@  gdb_test "break func5b" \
 # inlined instance within the out-of-line func6a, and the inlined
 # instance within the inlined call to func6a in main,
 #
-gdb_test "break func6b" \
-    "Breakpoint.*at.*func6b.*\\(3 locations\\)"
+gdb_breakpoint "func6b" -locs 3
 
 #
 # func7b is a static inlined function that is called twice: once from
@@ -141,8 +139,7 @@  gdb_test "break func6b" \
 # two locations: the inlined instance within the inlined instance of
 # func7a, and the inlined instance within main.
 #
-gdb_test "break func7b" \
-    "Breakpoint.*at.*func7b.*\\(2 locations\\)"
+gdb_breakpoint "func7b" -locs 2
 
 #
 # func8b is a non-static inlined function that is called twice: once
@@ -151,8 +148,7 @@  gdb_test "break func7b" \
 # within the inlined instance of func7a, and the inlined instance
 # within main.
 #
-gdb_test "break func8b" \
-    "Breakpoint.*at.*func8b.*\\(3 locations\\)"
+gdb_breakpoint "func8b" -locs 3
 
 #
 # func1 is a static inlined function.  The result should be that no
@@ -314,8 +310,7 @@  with_test_prefix "check alignment" {
 	continue
     }
 
-    gdb_test "break func4b" \
-	"Breakpoint.*at.*func4b.*\\(2 locations\\)"
+    gdb_breakpoint "func4b" -locs 2
 
     set expected_line_length -1
     gdb_test_multiple "info break \$bpnum" "xxxx" {
diff --git a/gdb/testsuite/gdb.python/py-bp-locations.exp b/gdb/testsuite/gdb.python/py-bp-locations.exp
index 4892947ca55..a2bff8a655e 100644
--- a/gdb/testsuite/gdb.python/py-bp-locations.exp
+++ b/gdb/testsuite/gdb.python/py-bp-locations.exp
@@ -56,7 +56,7 @@  proc build_bpl_regexp { args } {
 }
 
 # Set breakpoint with 2 locations.
-gdb_breakpoint "add"
+gdb_breakpoint "add" -locs 2
 
 set expected_line_a [gdb_get_line_number "a + b"]
 set expected_line_b [gdb_get_line_number "c + d"]
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 0475fb95161..ede85ec8504 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -672,6 +672,11 @@  proc gdb_starti_cmd { {inferior_args {}} } {
 #
 # If there is an additional argument it is a list of options; the supported
 # options are allow-pending, temporary, message, no-message and qualified.
+# For multiple breakpoint locations additional options are used. These
+# are -locs and -extra:
+# -locs specifies how many locations to expect the breakpoint set output
+#       and enforces that a single location match is an error.
+# -extra allows specifying extra matches that need to appear in the output.
 #
 # The result is 1 for success, 0 for failure.
 #
@@ -685,6 +690,12 @@  proc gdb_breakpoint { linespec args } {
     global gdb_prompt
     global decimal
 
+    parse_some_args {
+	{locs "\[0-9\]+"}
+	{extra "<nomatch>"}
+	{inferior ""}
+    }
+
     set pending_response n
     if {[lsearch -exact $args allow-pending] != -1} {
 	set pending_response y
@@ -706,29 +717,53 @@  proc gdb_breakpoint { linespec args } {
     set no_message_loc [lsearch -exact $args no-message]
     set message_loc [lsearch -exact $args message]
     # The last one to appear in args wins.
+    # For multiple locations, enable pass printing if caller has used the -locs
+    # option.  This tries to make up for the lost pass output from the
+    # previously used gdb_test "break" pattern.  But only when no-message has
+    # not been set.
     if { $no_message_loc > $message_loc } {
 	set print_fail 0
     } elseif { $message_loc > $no_message_loc } {
 	set print_pass 1
     }
 
+    # Counters for single and multiple locations
+    set multiple_locs 0
+    set single_loc 0
+    set extra_matches 0
+
     set test_name "gdb_breakpoint: set breakpoint at $linespec"
-    # The first two regexps are what we get with -g, the third is without -g.
+
+    # The extra regex is setup to not match unless the caller specifies
+    # an extra match.
     gdb_test_multiple "$break_command $linespec" $test_name {
-	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
-	-re "$break_message \[0-9\]*: file .*, line $decimal.\r\n$gdb_prompt $" {}
-	-re "$break_message \[0-9\]* at .*$gdb_prompt $" {}
-	-re "$break_message \[0-9\]* \\(.*\\) pending.*$gdb_prompt $" {
-		if {$pending_response == "n"} {
-			if { $print_fail } {
-				fail $gdb_test_name
-			}
-			return 0
+	-re "$extra" {
+	    incr extra_matches
+	    exp_continue
+	}
+	-re "$break_message \[0-9\]+ at .*: file .*, line $decimal.\r\n$gdb_prompt $" {
+	    incr single_loc
+	}
+	-re "$break_message \[0-9\]*: file .*, line $decimal.\r\n$gdb_prompt $" {
+	    incr single_loc
+	}
+	-re "$break_message \[0-9\]+ at .*\($locs locations\).*\r\n$gdb_prompt $" {
+	    incr multiple_locs
+	}
+	-re "$break_message \[0-9\]+ at .*\.\r\n$gdb_prompt $" {
+	    incr single_loc
+	}
+	-re "$break_message \[0-9\]+ \\(.*\\) pending.*$gdb_prompt $" {
+	    if {$pending_response == "n"} {
+		if { $print_fail } {
+		    fail $gdb_test_name
 		}
+		return 0
+	    }
 	}
-	-re "Make breakpoint pending.*y or \\\[n\\\]. $" { 
-		send_gdb "$pending_response\n"
-		exp_continue
+	-re "Make breakpoint pending.*y or \\\[n\\\]. $" {
+	    send_gdb "$pending_response\n"
+	    exp_continue
 	}
 	-re "$gdb_prompt $" {
 	    if { $print_fail } {
@@ -737,11 +772,40 @@  proc gdb_breakpoint { linespec args } {
 	    return 0
 	}
     }
+
+    # If multiple locations where requested, assert we didn't
+    # see a single location match.
+    if { [string compare $locs "\[0-9\]+"] != 0
+	 && [string compare $locs 1] != 0
+	 && $single_loc != 0 } {
+	if { $print_fail } {
+	    fail $test_name
+	}
+	return 0
+    }
+
+    # Special case to enforce single location matches only. If -LOCS is set to
+    # 1 fail if we get multi location matches.
+    if { [string compare $locs 1] == 0 && $multiple_locs != 0 } {
+	if { $print_fail } {
+	    fail $test_name
+	}
+	return 0
+    }
+
+    # If extra regex is specified, see that it was actually matched.
+    if { [string compare $extra "<nomatch>"] != 0 && $extra_matches == 0 } {
+	if { $print_fail } {
+	    fail $test_name
+	}
+	return 0
+    }
+
     if { $print_pass } {
 	pass $test_name
     }
     return 1
-}    
+}
 
 # Set breakpoint at function and run gdb until it breaks there.
 # Since this is the only breakpoint that will be set, if it stops